FS2_Open
Open source remastering of the Freespace 2 engine
multi_xfer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #include "network/multi_xfer.h"
14 #include "network/multi.h"
15 #include "network/multimsgs.h"
16 #include "network/psnet2.h"
17 #include "io/timer.h"
18 #include "cfile/cfile.h"
19 
20 #ifndef NDEBUG
21 #include "playerman/player.h"
22 #include "network/multiutil.h"
23 #include "network/multi_log.h"
24 #endif
25 
26 
27 
28 
29 // ------------------------------------------------------------------------------------------
30 // MULTI XFER DEFINES/VARS
31 //
32 
33 #define MULTI_XFER_VERBOSE // keep this defined for verbose debug output
34 
35 #define MULTI_XFER_INVALID_HANDLE(handle) ( (handle < 0) || (handle > (MAX_XFER_ENTRIES-1)) || !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_USED) || (strlen(Multi_xfer_entry[handle].filename) <= 0) )
36 
37 // packet codes
38 #define MULTI_XFER_CODE_ACK 0 // simple response to the last request
39 #define MULTI_XFER_CODE_NAK 1 // simple response to the last request
40 #define MULTI_XFER_CODE_HEADER 2 // file xfer header information follows, requires a HEADER_RESPONSE
41 #define MULTI_XFER_CODE_DATA 3 // data block follows, requires an ack
42 #define MULTI_XFER_CODE_FINAL 4 // indication from sender that xfer is complete, requires an ack
43 
44 // entry flags
45 #define MULTI_XFER_FLAG_USED (1<<0) // this entry is in use
46 #define MULTI_XFER_FLAG_SEND (1<<1) // this entry is sending a file
47 #define MULTI_XFER_FLAG_RECV (1<<2) // this entry is receiving a file
48 #define MULTI_XFER_FLAG_PENDING (1<<3) // this entry is ready to send a header and start the process
49 #define MULTI_XFER_FLAG_WAIT_ACK (1<<4) // waiting for an ack/nak
50 #define MULTI_XFER_FLAG_WAIT_DATA (1<<5) // waiting for another block of data
51 #define MULTI_XFER_FLAG_UNKNOWN (1<<6) // xfer final has been sent, and we are waiting for a response
52 #define MULTI_XFER_FLAG_SUCCESS (1<<7) // finished xfer
53 #define MULTI_XFER_FLAG_FAIL (1<<8) // xfer failed
54 #define MULTI_XFER_FLAG_TIMEOUT (1<<9) // xfer has timed-out
55 #define MULTI_XFER_FLAG_QUEUE_CURRENT (1<<10) // for a set of XFER_FLAG_QUEUE'd files, this is the current one sending
56 
57 // packet size for file xfer
58 #define MULTI_XFER_MAX_DATA_SIZE 490 // this will keep us within the MULTI_XFER_MAX_SIZE_LIMIT
59 
60 // timeout for a given xfer operation
61 #define MULTI_XFER_TIMEOUT 10000
62 
63 //XSTR:OFF
64 
65 // temp filename header for xferring files
66 #define MULTI_XFER_FNAME_PREFIX "_fsx_"
67 
68 //XSTR:ON
69 
70 // xfer entries/events
71 #define MAX_XFER_ENTRIES 60 // the max allowed file xfer entries
72 typedef struct xfer_entry {
73  int flags; // status flags for this entry
74  char filename[MAX_FILENAME_LEN+1]; // filename of the currently xferring file
75  char ex_filename[MAX_FILENAME_LEN+10]; // filename with xfer prefix tacked on to the front
76  CFILE *file; // file handle of the current xferring file
77  int file_size; // total size of the file being xferred
78  int file_ptr; // total bytes we're received so far
79  ushort file_chksum; // used for checking successfully xferred files
80  PSNET_SOCKET_RELIABLE file_socket; // socket used to xfer the file
81  int xfer_stamp; // timestamp for the current operation
82  int force_dir; // force the file to go to this directory on receive (will override Multi_xfer_force_dir)
83  ushort sig; // identifying sig - sender specifies this
84 } xfer_entry;
85 xfer_entry Multi_xfer_entry[MAX_XFER_ENTRIES]; // the file xfer entries themselves
86 
87 // callback function pointer for when we start receiving a file
89 
90 // lock for the xfer system
92 
93 // force directory type for receives
95 
96 // unique file signature - this along with a socket # is enough to identify all xfers
98 
99 
100 // ------------------------------------------------------------------------------------------
101 // MULTI XFER FORWARD DECLARATIONS
102 //
103 
104 // evaluate the condition of the entry
106 
107 // set an entry to be "failed"
109 
110 // get a valid xfer entry handle
112 
113 // process an ack for this entry
115 
116 // process a nak for this entry
118 
119 // process a "final" packet
121 
122 // process a data packet
123 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size);
124 
125 // process a header
126 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum);
127 
128 // send the next block of outgoing data or a "final" packet if we're done
130 
131 // send an ack to the sender
133 
134 // send a nak to the sender
136 
137 // send a "final" packet
139 
140 // send the header to begin a file transfer
142 
143 // convert the filename into the prefixed ex_filename
144 void multi_xfer_conv_prefix(char *filename, char *ex_filename);
145 
146 // get a new xfer sig
148 
149 // ------------------------------------------------------------------------------------------
150 // MULTI XFER FUNCTIONS
151 //
152 
153 // initialize all file xfer transaction stuff, call in multi_level_init()
154 void multi_xfer_init(void (*multi_xfer_recv_callback)(int handle))
155 {
156  // blast all the entries
157  memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
158 
159  // assign the receive callback function pointer
160  Multi_xfer_recv_notify = multi_xfer_recv_callback;
161 
162  // unlocked
163  Multi_xfer_locked = 0;
164 
165  // no forced directory
167 }
168 
169 // do frame for all file xfers, call in multi_do_frame()
171 {
172  int idx;
173 
174  // process all valid xfer entries
175  for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
176  // if this one is actually in use and has not finished for one reason or another
177  if((Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED) && !(Multi_xfer_entry[idx].flags & (MULTI_XFER_FLAG_SUCCESS | MULTI_XFER_FLAG_FAIL | MULTI_XFER_FLAG_TIMEOUT))){
178  // evaluate the condition of this entry (fail, timeout, etc)
179  multi_xfer_eval_entry(&Multi_xfer_entry[idx]);
180  }
181  }
182 }
183 
184 // reset the xfer system, including shutting down/killing all active xfers
186 {
187  int idx;
188 
189  // shut down all active xfers
190  for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
191  if(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED){
192  multi_xfer_abort(idx);
193  }
194  }
195 
196  // blast all the memory clean
197  memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
198 }
199 
200 // send a file to the specified player, return a handle
201 int multi_xfer_send_file(PSNET_SOCKET_RELIABLE who, char *filename, int cfile_flags, int flags)
202 {
203  xfer_entry temp_entry;
204  int handle;
205 
206  // if the system is locked, return -1
207  if(Multi_xfer_locked){
208  return -1;
209  }
210 
211  // attempt to get a free handle
212  handle = multi_xfer_get_free_handle();
213  if(handle == -1){
214  return -1;
215  }
216 
217  // clear the temp entry
218  memset(&temp_entry,0,sizeof(xfer_entry));
219 
220  // set the filename
221  strcpy_s(temp_entry.filename,filename);
222 
223  // attempt to open the file
224  temp_entry.file = NULL;
225  temp_entry.file = cfopen(filename,"rb",CFILE_NORMAL,cfile_flags);
226  if(temp_entry.file == NULL){
227 #ifdef MULTI_XFER_VERBOSE
228  nprintf(("Network","MULTI XFER : Could not open file %s on xfer send!\n",filename));
229 #endif
230 
231  return -1;
232  }
233 
234  // set the file size
235  temp_entry.file_size = -1;
236  temp_entry.file_size = cfilelength(temp_entry.file);
237  if(temp_entry.file_size == -1){
238 #ifdef MULTI_XFER_VERBOSE
239  nprintf(("Network","MULTI XFER : Could not get file length for file %s on xfer send\n",filename));
240 #endif
241  return -1;
242  }
243  temp_entry.file_ptr = 0;
244 
245  // get the file checksum
246  if(!cf_chksum_short(temp_entry.file,&temp_entry.file_chksum)){
247 #ifdef MULTI_XFER_VERBOSE
248  nprintf(("Network","MULTI XFER : Could not get file checksum for file %s on xfer send\n",filename));
249 #endif
250  return -1;
251  }
252 #ifdef MULTI_XFER_VERBOSE
253  nprintf(("Network","MULTI XFER : Got file %s checksum of %d\n",temp_entry.filename,(int)temp_entry.file_chksum));
254 #endif
255  // rewind the file pointer to the beginning of the file
256  cfseek(temp_entry.file,0,CF_SEEK_SET);
257 
258  // set the flags
260  temp_entry.flags |= flags;
261 
262  // set the socket
263  temp_entry.file_socket = who;
264 
265  // set the signature
266  temp_entry.sig = multi_xfer_get_sig();
267 
268  // copy to the global array
269  memset(&Multi_xfer_entry[handle],0,sizeof(xfer_entry));
270  memcpy(&Multi_xfer_entry[handle],&temp_entry,sizeof(xfer_entry));
271 
272  return handle;
273 }
274 
275 // get the status of the current file xfer
276 int multi_xfer_get_status(int handle)
277 {
278  // if this is an invalid or an unused handle, notify as such
279  if((handle < 0) || (handle > (MAX_XFER_ENTRIES-1)) || !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_USED) ){
280  return MULTI_XFER_NONE;
281  }
282 
283  // if the xfer has timed-out
284  if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_TIMEOUT){
285  return MULTI_XFER_TIMEDOUT;
286  }
287 
288  // if the xfer has failed for one reason or another (not timeout)
289  if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_FAIL){
290  return MULTI_XFER_FAIL;
291  }
292 
293  // if the xfer has succeeded
294  if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_SUCCESS){
295  return MULTI_XFER_SUCCESS;
296  }
297 
298  // if the xfer is queued
299  if((Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE) && !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
300  return MULTI_XFER_QUEUED;
301  }
302 
303  // otherwise the xfer is still in progress
304  return MULTI_XFER_IN_PROGRESS;
305 }
306 
307 // abort a transferring file
308 void multi_xfer_abort(int handle)
309 {
310  xfer_entry *xe;
311 
312  // don't do anything if this is an invalid handle
313  if(MULTI_XFER_INVALID_HANDLE(handle)){
314  return;
315  }
316 
317  // get e handle to the entry
318  xe = &Multi_xfer_entry[handle];
319 
320  // close any open file and delete it
321  if(xe->file != NULL){
322  cfclose(xe->file);
323  xe->file = NULL;
324 
325  // delete it if there isn't some problem with the filename
326  if((xe->flags & MULTI_XFER_FLAG_RECV) && (xe->filename[0] != '\0')){
327  cf_delete(xe->ex_filename, xe->force_dir);
328  }
329  }
330 
331  // zero the socket
333 
334  // blast the entry
335  memset(xe,0,sizeof(xfer_entry));
336 }
337 
338 // release an xfer handle
340 {
341  xfer_entry *xe;
342 
343  // don't do anything if this is an invalid handle
344  if(MULTI_XFER_INVALID_HANDLE(handle)){
345  return;
346  }
347 
348  // get e handle to the entry
349  xe = &Multi_xfer_entry[handle];
350 
351  // close any open file and delete it
352  if(xe->file != NULL){
353  cfclose(xe->file);
354  xe->file = NULL;
355 
356  // delete it if the file was not successfully received
357  if(!(xe->flags & MULTI_XFER_FLAG_SUCCESS) && (xe->flags & MULTI_XFER_FLAG_RECV) && (xe->filename[0] != '\0')){
359  }
360  }
361 
362  // zero the socket
364 
365  // blast the entry
366  memset(xe,0,sizeof(xfer_entry));
367 }
368 
369 // get the filename of the xfer for the given handle
370 char *multi_xfer_get_filename(int handle)
371 {
372  // if this is an invalid handle, return NULL
373  if(MULTI_XFER_INVALID_HANDLE(handle)){
374  return NULL;
375  }
376 
377  // otherwise return the string
378  return Multi_xfer_entry[handle].filename;
379 }
380 
381 // lock the xfer system (don't accept incoming files, don't allow outgoing files)
383 {
384  Multi_xfer_locked = 1;
385 }
386 
387 // unlock the xfer system
389 {
390  Multi_xfer_locked = 0;
391 }
392 
393 // force all receives to go into the specified directory by cfile type
394 void multi_xfer_force_dir(int cf_type)
395 {
396  Multi_xfer_force_dir = cf_type;
398 }
399 
400 // forces the given xfer entry to the specified directory type (only valid when called from the recv_callback function)
401 void multi_xfer_handle_force_dir(int handle,int cf_type)
402 {
403  // if this is an invalid handle, return NULL
404  if(MULTI_XFER_INVALID_HANDLE(handle)){
405  return;
406  }
407 
408  // force to go to the given directory
409  Multi_xfer_entry[handle].force_dir = cf_type;
410  Assert(Multi_xfer_entry[handle].force_dir > CF_TYPE_ANY);
411 }
412 
413 // or the flag on a given entry
414 void multi_xfer_xor_flags(int handle,int flags)
415 {
416  // if this is an invalid handle, return NULL
417  if(MULTI_XFER_INVALID_HANDLE(handle)){
418  return;
419  }
420 
421  // xor the flags
422  Multi_xfer_entry[handle].flags ^= flags;
423 }
424 
425 // get the flags for a given entry
426 int multi_xfer_get_flags(int handle)
427 {
428  // if this is an invalid handle, return NULL
429  if(MULTI_XFER_INVALID_HANDLE(handle)){
430  return -1;
431  }
432 
433  // return the flags
434  return Multi_xfer_entry[handle].flags;
435 }
436 
437 // if the passed filename is being xferred, return the xfer handle, otherwise return -1
439 {
440  int idx;
441 
442  // if we have an invalid filename, do nothing
443  if((filename == NULL) || (strlen(filename) <= 0)){
444  return 0;
445  }
446 
447  // otherwise, perform a lookup
448  for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
449  // if we found a matching filename
450  if((Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED) && !stricmp(filename,Multi_xfer_entry[idx].filename)){
451  return idx;
452  }
453  }
454 
455  // did not find a match
456  return -1;
457 }
458 
459 // get the % of completion of the passed file handle, return < 0 if invalid
460 float multi_xfer_pct_complete(int handle)
461 {
462  // if this is an invalid handle, return invalid
463  if(MULTI_XFER_INVALID_HANDLE(handle)){
464  return -1.0f;
465  }
466 
467  // if the file size is 0, return invalid
468  if(Multi_xfer_entry[handle].file_size == 0){
469  return -1.0f;
470  }
471 
472  // return the pct completion
473  return (float)Multi_xfer_entry[handle].file_ptr / (float)Multi_xfer_entry[handle].file_size;
474 }
475 
476 // get the socket of the file xfer (useful for identifying players)
478 {
479  // if this is an invalid handle, return NULL
480  if(MULTI_XFER_INVALID_HANDLE(handle)){
481  return INVALID_SOCKET;
482  }
483 
484  return Multi_xfer_entry[handle].file_socket;
485 }
486 
487 // get the CF_TYPE of the directory this file is going to
489 {
490  // if this is an invalid handle, return NULL
491  if(MULTI_XFER_INVALID_HANDLE(handle)){
492  return INVALID_SOCKET;
493  }
494 
495  return Multi_xfer_entry[handle].force_dir;
496 }
497 
498 
499 // ------------------------------------------------------------------------------------------
500 // MULTI XFER FORWARD DECLARATIONS
501 //
502 
503 // evaluate the condition of the entry
505 {
506  int idx;
507  int found;
508  xfer_entry *xe_c;
509 
510  // if the entry is marked as successful, then don't do anything
511  if(xe->flags & MULTI_XFER_FLAG_SUCCESS){
512  return;
513  }
514 
515  // if the entry is queued
516  if(xe->flags & MULTI_XFER_FLAG_QUEUE){
517  // if the entry is not current
519  // see if there are any other queued up xfers to this target. if not, make me current and start sending
520  found = 0;
521  for(idx=0; idx<MAX_XFER_ENTRIES; idx++){
522  xe_c = &Multi_xfer_entry[idx];
523 
524  // if this is a valid entry and is a queued entry and is going to the same target
525  if((xe_c->flags & MULTI_XFER_FLAG_USED) && (xe_c->file_socket == xe->file_socket) && (xe_c->flags & MULTI_XFER_FLAG_SEND) &&
527 
528  found = 1;
529  break;
530  }
531  }
532 
533  // if we found no other entries, make this guy current and pending
534  if(!found){
537 
538 #ifdef MULTI_XFER_VERBOSE
539  nprintf(("Network","MULTI_XFER : Starting xfer send for queued entry %s\n", xe->filename));
540 #endif
541  }
542  // otherwise, do nothing for him - he has to still wait
543  else {
544  return;
545  }
546  }
547  }
548 
549  // if the entry is marked as pending - send out the header to get the ball rolling
550  if(xe->flags & MULTI_XFER_FLAG_PENDING){
551  // send the header to begin the transfer
553 
554  // set the timestamp
556 
557  // unset the pending flag
558  xe->flags &= ~(MULTI_XFER_FLAG_PENDING);
559 
560  // set the ack/wait flag
562  }
563 
564  // see if the entry has timed-out for one reason or another
565  if((xe->xfer_stamp != -1) && timestamp_elapsed(xe->xfer_stamp)){
567 
568  // if we should be auto-destroying this entry, do so
571  }
572  }
573 }
574 
575 // lookup a file xfer entry by player
577 {
578  int idx;
579 
580  // look through all valid xfer entries
581  for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
582  // if we're looking for sending entries
583  if(sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_SEND)){
584  continue;
585  }
586  // if we're looking for recv entries
587  if(!sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_RECV)){
588  continue;
589  }
590 
591  // if we found a match
592  if((Multi_xfer_entry[idx].file_socket == who) && (Multi_xfer_entry[idx].sig == sig)){
593  return &Multi_xfer_entry[idx];
594  }
595  }
596 
597  return NULL;
598 }
599 
600 // set an entry to be "failed"
602 {
603  // set its flags appropriately
606 
607  // close the file pointer
608  if(xe->file != NULL){
609  cfclose(xe->file);
610  xe->file = NULL;
611  }
612 
613  // delete the file
614  if((xe->flags & MULTI_XFER_FLAG_RECV) && (xe->filename[0] != '\0')){
616  }
617 
618  // null the timestamp
619  xe->xfer_stamp = -1;
620 
621  // if we should be auto-destroying this entry, do so
623  multi_xfer_release_handle(xe - Multi_xfer_entry);
624  }
625 
626  // blast the memory clean
627  memset(xe,0,sizeof(xfer_entry));
628 }
629 
630 // get a valid xfer entry handle
632 {
633  int idx;
634 
635  // look for a free entry
636  for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
637  if(!(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED)){
638  return idx;
639  }
640  }
641 
642  return -1;
643 }
644 
645 
646 // ------------------------------------------------------------------------------------------
647 // MULTI XFER PACKET HANDLERS
648 //
649 
650 // process an incoming file xfer data packet, return bytes processed, guaranteed to process the entire
651 // packet regardless of error conditions
653 {
654  ubyte val;
655  xfer_entry *xe;
656  char filename[255];
657  ushort data_size = 0;
658  int file_size = -1;
659  ushort file_checksum = 0;
660  int offset = 0;
661  ubyte xfer_data[600];
662  ushort sig;
663  int sender_side = 1;
664 
665  // read in all packet data
666  GET_DATA(val);
667  GET_USHORT(sig);
668  switch(val){
669  // RECV side
670  case MULTI_XFER_CODE_DATA:
671  GET_USHORT(data_size);
672  memcpy(xfer_data, data + offset, data_size);
673  offset += data_size;
674  sender_side = 0;
675  break;
676 
677  // RECV side
679  GET_STRING(filename);
680  GET_INT(file_size);
681  GET_USHORT(file_checksum);
682  sender_side = 0;
683  break;
684 
685  // SEND side
686  case MULTI_XFER_CODE_ACK:
687  case MULTI_XFER_CODE_NAK:
688  break;
689 
690  // RECV side
692  sender_side = 0;
693  break;
694 
695  default:
696  Int3();
697  }
698 
699  // at this point we've read all the data in the packet
700 
701  // at this point, we should process code-specific data
702  xe = NULL;
703  if(val != MULTI_XFER_CODE_HEADER){
704  // if the code is not a request or a header, we need to look up the existing xfer_entry
705  xe = NULL;
706 
707  xe = multi_xfer_find_entry(who, sig, sender_side);
708  if(xe == NULL){
709 #ifdef MULTI_XFER_VERBOSE
710  nprintf(("Network","MULTI XFER : Could not find xfer entry for incoming data!\n"));
711 
712  // this is a rare case - I'm not overly concerned about it. But it _does_ happen. So blech
713 #ifndef NDEBUG
714  int np_index = find_player_socket(who);
715  ml_string("MULTI XFER : Could not find xfer entry for incoming data :");
716  ml_printf(": sig == %d", sig);
717  ml_printf(": xfer header == %d", val);
718  if(np_index < 0){
719  ml_string(": player == unknown");
720  } else {
721  ml_printf(": player == %s", Net_players[np_index].m_player->callsign);
722  }
723  if(sender_side){
724  ml_string(": sending");
725  } else {
726  ml_string(": receiving");
727  }
728 #endif
729 #endif
730  return offset;
731  }
732  }
733 
734  switch((int)val){
735  // process an ack for this entry
736  case MULTI_XFER_CODE_ACK :
737  Assert(xe != NULL);
739  break;
740 
741  // process a nak for this entry
742  case MULTI_XFER_CODE_NAK :
743  Assert(xe != NULL);
745  break;
746 
747  // process a "final" packet
748  case MULTI_XFER_CODE_FINAL :
749  Assert(xe != NULL);
751  break;
752 
753  // process a data packet
754  case MULTI_XFER_CODE_DATA :
755  Assert(xe != NULL);
756  multi_xfer_process_data(xe, xfer_data, data_size);
757  break;
758 
759  // process a header
761  // send on my reliable socket
762  multi_xfer_process_header(xfer_data, who, sig, filename, file_size, file_checksum);
763  break;
764  }
765  return offset;
766 }
767 
768 // process an ack for this entry
770 {
771  // if we are a sender
772  if(xe->flags & MULTI_XFER_FLAG_SEND){
773  // if we are waiting on a final ack, then the transfer has completed successfully
774  if(xe->flags & MULTI_XFER_FLAG_UNKNOWN){
775  xe->flags &= ~(MULTI_XFER_FLAG_UNKNOWN);
777 
778 #ifdef MULTI_XFER_VERBOSE
779  nprintf(("Network", "MULTI XFER : Successfully sent file %s\n", xe->filename));
780 #endif
781 
782  // if we should be auto-destroying this entry, do so
784  multi_xfer_release_handle(xe - Multi_xfer_entry);
785  }
786  }
787  // otherwise if we're waiting for an ack, we should send the next chunk of data or a "final" packet if we're done
788  else if(xe->flags & MULTI_XFER_FLAG_WAIT_ACK){
790  }
791  }
792 }
793 
794 // process a nak for this entry
796 {
797  // if we get an ack at any time we should simply set the xfer to failed
799 }
800 
801 // process a "final" packet
803 {
804  ushort chksum;
805 
806  // make sure we skip a line
807  nprintf(("Network","\n"));
808 
809  // close the file
810  if(xe->file != NULL){
811  cflush(xe->file);
812  cfclose(xe->file);
813  xe->file = NULL;
814  }
815 
816  // check to make sure the file checksum is the same
817  chksum = 0;
818  if(!cf_chksum_short(xe->ex_filename, &chksum, -1, xe->force_dir) || (chksum != xe->file_chksum)){
819  // mark as failed
821 
822 #ifdef MULTI_XFER_VERBOSE
823  nprintf(("Network","MULTI XFER : file %s failed checksum %d %d!\n",xe->ex_filename, (int)xe->file_chksum, (int)chksum));
824 #endif
825 
826  // abort the xfer
827  multi_xfer_abort(xe - Multi_xfer_entry);
828  return;
829  }
830  // checksums check out, so rename the file and be done with it
831  else {
832 #ifdef MULTI_XFER_VERBOSE
833  nprintf(("Network","MULTI XFER : renaming xferred file from %s to %s (chksum %d %d)\n", xe->ex_filename, xe->filename, (int)xe->file_chksum, (int)chksum));
834 #endif
835  // rename the file properly
837  // mark the xfer as being successful
839 
840  nprintf(("Network","MULTI XFER : SUCCESSFULLY TRANSFERRED FILE %s (%d bytes)\n", xe->filename, xe->file_size));
841 
842  // send an ack to the sender
844  } else {
845  // mark it as failing
847  nprintf(("Network","FAILED TO TRANSFER FILE (could not rename temp file %s)\n", xe->ex_filename));
848 
849  // delete the tempfile
850  cf_delete(xe->ex_filename, xe->force_dir);
851 
852  // send an nak to the sender
854  }
855 
856  // if we should be auto-destroying this entry, do so
858  multi_xfer_release_handle(xe - Multi_xfer_entry);
859  }
860  }
861 }
862 
863 // process a data packet
864 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size)
865 {
866  // print out a crude progress indicator
867  nprintf(("Network","."));
868 
869  // attempt to write the rest of the data string to the file
870  if((xe->file == NULL) || !cfwrite(data, data_size, 1, xe->file)){
871  // inform the sender we had a problem
873 
874  // fail this entry
876 
877  xe->file_ptr += data_size;
878  return;
879  }
880 
881  // increment the file pointer
882  xe->file_ptr += data_size;
883 
884  // send an ack to the sender
886 
887  // set the timestmp
889 }
890 
891 // process a header, return bytes processed
892 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum)
893 {
894  xfer_entry *xe;
895  int handle;
896 
897  // if the xfer system is locked, send a nak
898  if(Multi_xfer_locked){
899  multi_xfer_send_nak(who, sig);
900  return;
901  }
902 
903  // try and get a free xfer handle
904  handle = multi_xfer_get_free_handle();
905  if(handle == -1){
906  multi_xfer_send_nak(who, sig);
907  return;
908  } else {
909  xe = &Multi_xfer_entry[handle];
910  memset(xe,0,sizeof(xfer_entry));
911  }
912 
913  // set the recv and used flags
915 
916  // get the header data
917  xe->file_size = file_size;
918 
919  // get the file chksum
920  xe->file_chksum = file_checksum;
921 
922  // set the socket
923  xe->file_socket = who;
924 
925  // set the timeout timestamp
927 
928  // set the sig
929  xe->sig = sig;
930 
931  // copy the filename and get the prefixed xfer filename
932  strcpy_s(xe->filename, filename);
934 #ifdef MULTI_XFER_VERBOSE
935  nprintf(("Network","MULTI XFER : converted filename %s to %s\n",xe->filename, xe->ex_filename));
936 #endif
937 
938  // determine what directory to place the file in
939  // individual xfer entries take precedence over the global multi xfer force entry
941 
942  // call the callback function
943  Multi_xfer_recv_notify(handle);
944 
945  // if the notify function invalidated this xfer handle, then cancel the whole thing
946  if(xe->flags & MULTI_XFER_FLAG_REJECT){
947  multi_xfer_send_nak(who, sig);
948 
949  // clear the data
950  memset(xe, 0, sizeof(xfer_entry));
951  return;
952  }
953 
954  // delete the old file (if it exists)
957 
958  // attempt to open the file (using the prefixed filename)
959  xe->file = NULL;
960  xe->file = cfopen(xe->ex_filename, "wb", CFILE_NORMAL, xe->force_dir);
961  if(xe->file == NULL){
962  multi_xfer_send_nak(who, sig);
963 
964  // clear the data
965  memset(xe, 0, sizeof(xfer_entry));
966  return;
967  }
968 
969  // set the waiting for data flag
971 
972  // send an ack to the server
973  multi_xfer_send_ack(who, sig);
974 
975 #ifdef MULTI_XFER_VERBOSE
976  nprintf(("Network","MULTI XFER : AFTER HEADER %s\n",xe->filename));
977 #endif
978 }
979 
980 // send the next block of outgoing data or a "final" packet if we're done
982 {
984  ushort data_size;
985  int flen;
986  int packet_size = 0;
987 
988  // print out a crude progress indicator
989  nprintf(("Network", "+"));
990 
991  // if we've sent all the data, then we should send a "final" packet
992  if(xe->file_ptr >= xe->file_size){
993  // mark the entry as unknown
995 
996  // set the timestmp
998 
999  // send the packet
1000  multi_xfer_send_final(xe);
1001 
1002  return;
1003  }
1004 
1005  // build the header
1007 
1008  // length of the added string
1009  flen = strlen(xe->filename) + 4;
1010 
1011  // determine how much data we are going to send with this packet and add it in
1012  if((xe->file_size - xe->file_ptr) >= (MULTI_XFER_MAX_DATA_SIZE - flen)){
1013  data_size = (ushort)(MULTI_XFER_MAX_DATA_SIZE - flen);
1014  } else {
1015  data_size = (unsigned short)(xe->file_size - xe->file_ptr);
1016  }
1017  // increment the file pointer
1018  xe->file_ptr += data_size;
1019 
1020  // add the opcode
1021  code = MULTI_XFER_CODE_DATA;
1022  ADD_DATA(code);
1023 
1024  // add the sig
1025  ADD_USHORT(xe->sig);
1026 
1027  // add in the size of the rest of the packet
1028  ADD_USHORT(data_size);
1029 
1030  // copy in the data
1031  if(cfread(data+packet_size,1,(int)data_size,xe->file) == 0){
1032  // send a nack to the receiver
1034 
1035  // fail this send
1036  multi_xfer_fail_entry(xe);
1037  return;
1038  }
1039 
1040  // increment the packet size
1041  packet_size += (int)data_size;
1042 
1043  // set the timestmp
1045 
1046  // otherwise send the data
1047  psnet_rel_send(xe->file_socket, data, packet_size);
1048 }
1049 
1050 // send an ack to the sender
1052 {
1054  int packet_size = 0;
1055 
1056  // build the header and add
1058 
1059  // add the opcode
1060  code = MULTI_XFER_CODE_ACK;
1061  ADD_DATA(code);
1062 
1063  // add the sig
1064  ADD_USHORT(sig);
1065 
1066  // send the data
1067  psnet_rel_send(socket, data, packet_size);
1068 }
1069 
1070 // send a nak to the sender
1072 {
1074  int packet_size = 0;
1075 
1076  // build the header and add the code
1078 
1079  // add the opcode
1080  code = MULTI_XFER_CODE_NAK;
1081  ADD_DATA(code);
1082 
1083  // add the sig
1084  ADD_USHORT(sig);
1085 
1086  // send the data
1087  psnet_rel_send(socket, data, packet_size);
1088 }
1089 
1090 // send a "final" packet
1092 {
1094  int packet_size = 0;
1095 
1096  // build the header
1098 
1099  // add the code
1100  code = MULTI_XFER_CODE_FINAL;
1101  ADD_DATA(code);
1102 
1103  // add the sig
1104  ADD_USHORT(xe->sig);
1105 
1106  // send the data
1107  psnet_rel_send(xe->file_socket, data, packet_size);
1108 }
1109 
1110 // send the header to begin a file transfer
1112 {
1114  int packet_size = 0;
1115 
1116  // build the header and add the opcode
1118  code = MULTI_XFER_CODE_HEADER;
1119  ADD_DATA(code);
1120 
1121  // add the sig
1122  ADD_USHORT(xe->sig);
1123 
1124  // add the filename
1125  ADD_STRING(xe->filename);
1126 
1127  // add the id #
1128  ADD_INT(xe->file_size);
1129 
1130  // add the file checksum
1131  ADD_USHORT(xe->file_chksum);
1132 
1133  // send the packet
1134  psnet_rel_send(xe->file_socket, data, packet_size);
1135 }
1136 
1137 // convert the filename into the prefixed ex_filename
1138 void multi_xfer_conv_prefix(char *filename,char *ex_filename)
1139 {
1140  char temp[MAX_FILENAME_LEN+50];
1141 
1142  // blast the memory clean
1143  memset(temp, 0, MAX_FILENAME_LEN+50);
1144 
1145  // copy in the prefix
1147 
1148  // stick on the original name
1149  strcat_s(temp, filename);
1150 
1151  // copy the whole thing to the outgoing filename
1152  strcpy(ex_filename, temp);
1153 }
1154 
1155 // get a new xfer sig
1157 {
1158  ushort ret = Multi_xfer_sig;
1159 
1160  // new one
1161  if(Multi_xfer_sig == 0xffff){
1162  Multi_xfer_sig = 0;
1163  } else {
1164  Multi_xfer_sig++;
1165  }
1166 
1167  return ret;
1168 }
#define MULTI_XFER_CODE_NAK
Definition: multi_xfer.cpp:39
#define MAX_FILENAME_LEN
Definition: pstypes.h:324
int force_dir
Definition: multi_xfer.cpp:82
int timestamp(int delta_ms)
Definition: timer.cpp:226
int multi_xfer_process_packet(unsigned char *data, PSNET_SOCKET_RELIABLE who)
Definition: multi_xfer.cpp:652
#define CFILE_NORMAL
Definition: cfile.h:89
#define MULTI_XFER_FLAG_UNKNOWN
Definition: multi_xfer.cpp:51
#define GET_DATA(d)
Definition: multimsgs.h:47
int cf_delete(const char *filename, int path_type)
Delete the specified file.
Definition: cfile.cpp:483
int cfread(void *buf, int elsize, int nelem, CFILE *fp)
#define MULTI_XFER_CODE_DATA
Definition: multi_xfer.cpp:41
char * multi_xfer_get_filename(int handle)
Definition: multi_xfer.cpp:370
void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum)
Definition: multi_xfer.cpp:892
uint PSNET_SOCKET_RELIABLE
Definition: multi_xfer.h:20
#define MULTI_XFER_FLAG_QUEUE
Definition: multi_xfer.h:38
void(* Multi_xfer_recv_notify)(int handle)
Definition: multi_xfer.cpp:88
ushort file_chksum
Definition: multi_xfer.cpp:79
#define ADD_DATA(d)
Definition: multimsgs.h:37
void multi_xfer_process_ack(xfer_entry *xe)
Definition: multi_xfer.cpp:769
Assert(pm!=NULL)
int cflush(CFILE *cfile)
Definition: cfile.cpp:1895
#define ADD_STRING(s)
Definition: multimsgs.h:43
void multi_xfer_process_nak(xfer_entry *xe)
Definition: multi_xfer.cpp:795
void multi_xfer_unlock()
Definition: multi_xfer.cpp:388
void ml_string(const char *string, int add_time)
Definition: multi_log.cpp:131
ushort multi_xfer_get_sig()
int multi_xfer_lookup(char *filename)
Definition: multi_xfer.cpp:438
char ex_filename[MAX_FILENAME_LEN+10]
Definition: multi_xfer.cpp:75
int psnet_rel_send(PSNET_SOCKET_RELIABLE socketid, ubyte *data, int length, int np_index)
Definition: psnet2.cpp:1075
Definition: cfile.h:28
#define MULTI_XFER_NONE
Definition: multi_xfer.h:23
int xfer_stamp
Definition: multi_xfer.cpp:81
#define INVALID_SOCKET
Definition: psnet2.h:53
#define CF_SEEK_SET
Definition: cfile.h:24
float multi_xfer_pct_complete(int handle)
Definition: multi_xfer.cpp:460
#define MULTI_XFER_FNAME_PREFIX
Definition: multi_xfer.cpp:66
#define MULTI_XFER_FLAG_SEND
Definition: multi_xfer.cpp:46
#define MULTI_XFER_FLAG_RECV
Definition: multi_xfer.cpp:47
void multi_xfer_fail_entry(xfer_entry *xe)
Definition: multi_xfer.cpp:601
#define Int3()
Definition: pstypes.h:292
int packet_size
Definition: multi_sexp.cpp:41
void multi_xfer_force_dir(int cf_type)
Definition: multi_xfer.cpp:394
#define CF_TYPE_MULTI_CACHE
Definition: cfile.h:73
#define MULTI_XFER_FLAG_AUTODESTROY
Definition: multi_xfer.h:31
void multi_xfer_send_ack(PSNET_SOCKET_RELIABLE socket, ushort sig)
int multi_xfer_get_status(int handle)
Definition: multi_xfer.cpp:276
void multi_xfer_conv_prefix(char *filename, char *ex_filename)
#define MULTI_XFER_FLAG_USED
Definition: multi_xfer.cpp:45
#define ADD_INT(d)
Definition: multimsgs.h:40
HWND DWORD code
Definition: vddraw.h:425
#define MULTI_XFER_CODE_FINAL
Definition: multi_xfer.cpp:42
#define MAX_PACKET_SIZE
Definition: psnet2.h:34
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
GLintptr offset
Definition: Glext.h:5497
#define XFER_PACKET
Definition: multi.h:246
#define MULTI_XFER_INVALID_HANDLE(handle)
Definition: multi_xfer.cpp:35
unsigned int uint
Definition: pstypes.h:64
Definition: multi_xfer.cpp:72
void ml_printf(const char *format,...)
Definition: multi_log.cpp:112
#define cfopen(...)
Definition: cfile.h:134
int flags
Definition: multi_xfer.cpp:73
#define nprintf(args)
Definition: pstypes.h:239
#define MULTI_XFER_QUEUED
Definition: multi_xfer.h:29
#define BUILD_HEADER(t)
Definition: multimsgs.h:36
char * filename
void multi_xfer_eval_entry(xfer_entry *xe)
Definition: multi_xfer.cpp:504
#define MULTI_XFER_MAX_DATA_SIZE
Definition: multi_xfer.cpp:58
void multi_xfer_handle_force_dir(int handle, int cf_type)
Definition: multi_xfer.cpp:401
#define MULTI_XFER_CODE_ACK
Definition: multi_xfer.cpp:38
#define MULTI_XFER_TIMEDOUT
Definition: multi_xfer.h:27
void multi_xfer_xor_flags(int handle, int flags)
Definition: multi_xfer.cpp:414
#define MULTI_XFER_FLAG_REJECT
Definition: multi_xfer.h:32
int multi_xfer_send_file(PSNET_SOCKET_RELIABLE who, char *filename, int cfile_flags, int flags)
Definition: multi_xfer.cpp:201
void multi_xfer_reset()
Definition: multi_xfer.cpp:185
int cf_rename(const char *old_name, const char *name, int dir_type)
Definition: cfile.cpp:567
int cfwrite(const void *buf, int elsize, int nelem, CFILE *cfile)
Definition: cfile.cpp:1414
void multi_xfer_process_final(xfer_entry *xe)
Definition: multi_xfer.cpp:802
int idx
Definition: multiui.cpp:761
#define MULTI_XFER_IN_PROGRESS
Definition: multi_xfer.h:28
#define MULTI_XFER_CODE_HEADER
Definition: multi_xfer.cpp:40
int file_ptr
Definition: multi_xfer.cpp:78
void multi_xfer_send_next(xfer_entry *xe)
Definition: multi_xfer.cpp:981
#define MULTI_XFER_FLAG_PENDING
Definition: multi_xfer.cpp:48
void multi_xfer_init(void(*multi_xfer_recv_callback)(int handle))
Definition: multi_xfer.cpp:154
void multi_xfer_release_handle(int handle)
Definition: multi_xfer.cpp:339
unsigned char ubyte
Definition: pstypes.h:62
char filename[MAX_FILENAME_LEN+1]
Definition: multi_xfer.cpp:74
int cf_chksum_short(const char *filename, ushort *chksum, int max_size, int cf_type)
Definition: cfile.cpp:1791
GLbitfield flags
Definition: Glext.h:6722
void multi_xfer_do()
Definition: multi_xfer.cpp:170
typedef void(APIENTRY *PFNGLARRAYELEMENTEXTPROC)(GLint i)
#define ADD_USHORT(d)
Definition: multimsgs.h:39
GLuint GLfloat * val
Definition: Glext.h:6741
void multi_xfer_send_nak(PSNET_SOCKET_RELIABLE socket, ushort sig)
typedef float(SCP_EXT_CALLCONV *SCPTRACKIR_PFFLOATVOID)()
void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size)
Definition: multi_xfer.cpp:864
#define MULTI_XFER_TIMEOUT
Definition: multi_xfer.cpp:61
#define strcat_s(...)
Definition: safe_strings.h:68
#define MULTI_XFER_FLAG_TIMEOUT
Definition: multi_xfer.cpp:54
#define MULTI_XFER_FLAG_QUEUE_CURRENT
Definition: multi_xfer.cpp:55
void multi_xfer_lock()
Definition: multi_xfer.cpp:382
ushort Multi_xfer_sig
Definition: multi_xfer.cpp:97
int file_size
Definition: multi_xfer.cpp:77
#define GET_USHORT(d)
Definition: multimsgs.h:49
#define MULTI_XFER_FLAG_SUCCESS
Definition: multi_xfer.cpp:52
struct xfer_entry xfer_entry
unsigned short ushort
Definition: pstypes.h:63
#define CF_TYPE_MISSIONS
Definition: cfile.h:74
int multi_xfer_get_force_dir(int handle)
Definition: multi_xfer.cpp:488
PSNET_SOCKET_RELIABLE file_socket
Definition: multi_xfer.cpp:80
int multi_xfer_get_flags(int handle)
Definition: multi_xfer.cpp:426
GLenum GLsizei GLenum GLenum const GLvoid * data
Definition: Gl.h:1509
#define timestamp_elapsed(stamp)
Definition: timer.h:102
int Multi_xfer_force_dir
Definition: multi_xfer.cpp:94
#define MAX_XFER_ENTRIES
Definition: multi_xfer.cpp:71
uint multi_xfer_get_sock(int handle)
Definition: multi_xfer.cpp:477
CFILE * file
Definition: multi_xfer.cpp:76
#define MULTI_XFER_FLAG_WAIT_ACK
Definition: multi_xfer.cpp:49
int temp
Definition: lua.cpp:4996
ushort sig
Definition: multi_xfer.cpp:83
int find_player_socket(PSNET_SOCKET_RELIABLE sock)
Definition: multiutil.cpp:482
int multi_xfer_get_free_handle()
Definition: multi_xfer.cpp:631
void multi_xfer_send_final(xfer_entry *xe)
#define GET_INT(d)
Definition: multimsgs.h:50
xfer_entry * multi_xfer_find_entry(PSNET_SOCKET_RELIABLE who, ushort sig, int sender_side)
Definition: multi_xfer.cpp:576
int cfclose(CFILE *cfile)
Definition: cfile.cpp:895
int Multi_xfer_locked
Definition: multi_xfer.cpp:91
#define MULTI_XFER_FLAG_WAIT_DATA
Definition: multi_xfer.cpp:50
#define CF_TYPE_ANY
Definition: cfile.h:42
net_player Net_players[MAX_PLAYERS]
Definition: multi.cpp:93
#define GET_STRING(s)
Definition: multimsgs.h:53
#define stricmp(s1, s2)
Definition: config.h:271
xfer_entry Multi_xfer_entry[MAX_XFER_ENTRIES]
Definition: multi_xfer.cpp:85
void multi_xfer_send_header(xfer_entry *xe)
#define MULTI_XFER_FLAG_FAIL
Definition: multi_xfer.cpp:53
#define MULTI_XFER_SUCCESS
Definition: multi_xfer.h:24
int cfilelength(CFILE *cfile)
Definition: cfile.cpp:1393
#define CF_RENAME_SUCCESS
Definition: cfile.h:247
#define MULTI_XFER_FAIL
Definition: multi_xfer.h:25
#define strcpy_s(...)
Definition: safe_strings.h:67
int cfseek(CFILE *fp, int offset, int where)
void multi_xfer_abort(int handle)
Definition: multi_xfer.cpp:308