]> icculus.org git repositories - taylor/freespace2.git/blob - src/network/multi_xfer.cpp
added copyright header
[taylor/freespace2.git] / src / network / multi_xfer.cpp
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
6  * the source.
7  */
8
9 /*
10  * $Logfile: /Freespace2/code/Network/multi_xfer.cpp $
11  * $Revision$
12  * $Date$
13  * $Author$
14  *
15  * $Log$
16  * Revision 1.5  2002/06/09 04:41:24  relnev
17  * added copyright header
18  *
19  * Revision 1.4  2002/06/01 07:12:33  relnev
20  * a few NDEBUG updates.
21  *
22  * removed a few warnings.
23  *
24  * Revision 1.3  2002/05/26 20:22:48  theoddone33
25  * Most of network/ works
26  *
27  * Revision 1.2  2002/05/07 03:16:47  theoddone33
28  * The Great Newline Fix
29  *
30  * Revision 1.1.1.1  2002/05/03 03:28:10  root
31  * Initial import.
32  *
33  * 
34  * 11    3/10/99 6:50p Dave
35  * Changed the way we buffer packets for all clients. Optimized turret
36  * fired packets. Did some weapon firing optimizations.
37  * 
38  * 10    3/09/99 6:24p Dave
39  * More work on object update revamping. Identified several sources of
40  * unnecessary bandwidth.
41  * 
42  * 9     1/24/99 11:37p Dave
43  * First full rev of beam weapons. Very customizable. Removed some bogus
44  * Int3()'s in low level net code.
45  * 
46  * 8     12/16/98 11:17a Dave
47  * Fixed potential situation where a send and receive to the same player
48  * with the same sig might get confused with each other.
49  * 
50  * 7     12/14/98 4:01p Dave
51  * Got multi_data stuff working well with new xfer stuff. 
52  * 
53  * 6     12/14/98 12:13p Dave
54  * Spiffed up xfer system a bit. Put in support for squad logo file xfer.
55  * Need to test now.
56  * 
57  * 5     11/19/98 8:03a Dave
58  * Full support for D3-style reliable sockets. Revamped packet lag/loss
59  * system, made it receiver side and at the lowest possible level.
60  * 
61  * 4     11/17/98 11:12a Dave
62  * Removed player identification by address. Now assign explicit id #'s.
63  * 
64  * 3     11/05/98 5:55p Dave
65  * Big pass at reducing #includes
66  * 
67  * 2     10/07/98 10:53a Dave
68  * Initial checkin.
69  * 
70  * 1     10/07/98 10:50a Dave
71  * 
72  * 56    9/11/98 9:31a Dave
73  * Fixed file xfer bug regarding checksums.
74  * 
75  * 55    8/12/98 4:53p Dave
76  * Put in 32 bit checksumming for PXO missions. No validation on the
77  * actual tracker yet, though.
78  * 
79  * 54    6/13/98 9:32p Mike
80  * Kill last character in file which caused "Find in Files" to report the
81  * file as "not a text file."
82  * 
83  * 53    6/13/98 6:01p Hoffoss
84  * Externalized all new (or forgot to be added) strings to all the code.
85  * 
86  * 52    6/13/98 3:19p Hoffoss
87  * NOX()ed out a bunch of strings that shouldn't be translated.
88  * 
89  * 51    5/21/98 1:52a Dave
90  * Remove obsolete command line functions. Reduce shield explosion packets
91  * drastically. Tweak PXO screen even more. Fix file xfer system so that
92  * we can guarantee file uniqueness.
93  * 
94  * 50    4/30/98 4:53p John
95  * Restructured and cleaned up cfile code.  Added capability to read off
96  * of CD-ROM drive and out of multiple pack files.
97  * 
98  * 49    4/23/98 6:18p Dave
99  * Store ETS values between respawns. Put kick feature in the text
100  * messaging system. Fixed text messaging system so that it doesn't
101  * process or trigger ship controls. Other UI fixes.
102  * 
103  * 48    4/22/98 5:53p Dave
104  * Large reworking of endgame sequencing. Updated multi host options
105  * screen for new artwork. Put in checks for host or team captains leaving
106  * midgame.
107  * 
108  * 47    4/21/98 4:44p Dave
109  * Implement Vasudan ships in multiplayer. Added a debug function to bash
110  * player rank. Fixed a few rtvoice buffer overrun problems. Fixed ui
111  * problem in options screen. 
112  * 
113  * 46    4/20/98 6:04p Dave
114  * Implement multidata cache flushing and xferring mission files to
115  * multidata. Make sure observers can't change hud config. Fix pilot image
116  * viewing in popup. Put in game status field. Tweaked multi options. 
117  * 
118  * 45    4/08/98 2:51p Dave
119  * Fixed pilot image xfer once again. Solidify team selection process in
120  * pre-briefing multiplayer.
121  * 
122  * 44    4/04/98 4:22p Dave
123  * First rev of UDP reliable sockets is done. Seems to work well if not
124  * overly burdened.
125  * 
126  * 43    4/03/98 1:03a Dave
127  * First pass at unreliable guaranteed delivery packets.
128  * 
129  * 42    4/01/98 11:19p Dave
130  * Put in auto-loading of xferred pilot pic files. Grey out background
131  * behind pinfo popup. Put a chatbox message in when players are kicked.
132  * Moved mission title down in briefing. Other ui fixes.
133  * 
134  * 41    3/31/98 4:51p Dave
135  * Removed medals screen and multiplayer buttons from demo version. Put in
136  * new pilot popup screen. Make ships in mp team vs. team have proper team
137  * ids. Make mp respawns a permanent option saved in the player file.
138  * 
139  * 40    3/30/98 8:46a Allender
140  * fix an optimized build compiler warning
141  * 
142  * 39    3/26/98 6:01p Dave
143  * Put in file checksumming routine in cfile. Made pilot pic xferring more
144  * robust. Cut header size of voice data packets in half. Put in
145  * restricted game host query system.
146  * 
147  * 38    3/25/98 2:16p Dave
148  * Select random default image for newly created pilots. Fixed several
149  * multi-pause messaging bugs. Begin work on online help for multiplayer
150  * keys.
151  * 
152  * 37    3/24/98 5:00p Dave
153  * Fixed several ui bugs. Put in pre and post voice stream playback sound
154  * fx. Put in error specific popups for clients getting dropped from games
155  * through actions other than their own.
156  * 
157  * 36    3/23/98 5:42p Dave
158  * Put in automatic xfer of pilot pic files. Changed multi_xfer system so
159  * that it can support multiplayer sends/received between client and
160  * server simultaneously.
161  * 
162  * 35    3/21/98 7:14p Dave
163  * Fixed up standalone player slot switching. Made training missions not
164  * count towards player stats.
165  * 
166  * 34    3/16/98 11:52p Allender
167  * Put in timestamp updates when processing data on both sender and
168  * receiver sides.
169  * 
170  * 33    2/22/98 2:53p Dave
171  * Put in groundwork for advanced multiplayer campaign  options.
172  * 
173  * 32    2/20/98 4:43p Dave
174  * Finished support for multiplayer player data files. Split off
175  * multiplayer campaign functionality.
176  * 
177  * 31    2/19/98 6:26p Dave
178  * Fixed a few file xfer bugs. Tweaked mp team select screen. Put in
179  * initial support for player data uploading.
180  * 
181  * 30    2/18/98 10:21p Dave
182  * Ripped out old file xfer system. Put in brand new xfer system.
183  * 
184  * $NoKeywords: $
185  */
186
187 #ifndef PLAT_UNIX
188 #include <winsock.h>
189 #include <io.h>
190 #endif
191 #include "multi_xfer.h"
192 #include "cfile.h"
193 #include "multimsgs.h"
194 #include "psnet.h"
195 #include "popup.h"
196 #include "multi_endgame.h"
197 #include "timer.h"
198 #include "multi.h"
199 #include "multiutil.h"
200 #include "multi_log.h"
201
202 // ------------------------------------------------------------------------------------------
203 // MULTI XFER DEFINES/VARS
204 //
205
206 #define MULTI_XFER_VERBOSE                                                                              // keep this defined for verbose debug output
207
208 #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) )
209
210 // packet codes
211 #define MULTI_XFER_CODE_ACK                                     0                               // simple response to the last request
212 #define MULTI_XFER_CODE_NAK                                     1                               // simple response to the last request
213 #define MULTI_XFER_CODE_HEADER                          2                               // file xfer header information follows, requires a HEADER_RESPONSE
214 #define MULTI_XFER_CODE_DATA                                    3                               // data block follows, requires an ack
215 #define MULTI_XFER_CODE_FINAL                                   4                               // indication from sender that xfer is complete, requires an ack
216
217 // entry flags
218 #define MULTI_XFER_FLAG_USED                                    (1<<0)          // this entry is in use 
219 #define MULTI_XFER_FLAG_SEND                                    (1<<1)          // this entry is sending a file
220 #define MULTI_XFER_FLAG_RECV                                    (1<<2)          // this entry is receiving a file
221 #define MULTI_XFER_FLAG_PENDING                         (1<<3)          // this entry is ready to send a header and start the process
222 #define MULTI_XFER_FLAG_WAIT_ACK                                (1<<4)          // waiting for an ack/nak
223 #define MULTI_XFER_FLAG_WAIT_DATA                       (1<<5)          // waiting for another block of data 
224 #define MULTI_XFER_FLAG_UNKNOWN                         (1<<6)          // xfer final has been sent, and we are waiting for a response
225 #define MULTI_XFER_FLAG_SUCCESS                         (1<<7)          // finished xfer
226 #define MULTI_XFER_FLAG_FAIL                                    (1<<8)          // xfer failed
227 #define MULTI_XFER_FLAG_TIMEOUT                         (1<<9)          // xfer has timed-out
228 #define MULTI_XFER_FLAG_QUEUE_CURRENT           (1<<10)         // for a set of XFER_FLAG_QUEUE'd files, this is the current one sending
229
230 // packet size for file xfer
231 #define MULTI_XFER_MAX_DATA_SIZE                                490                     // this will keep us within the MULTI_XFER_MAX_SIZE_LIMIT
232
233 // timeout for a given xfer operation
234 #define MULTI_XFER_TIMEOUT                                              10000           
235
236 //XSTR:OFF
237
238 // temp filename header for xferring files
239 #define MULTI_XFER_FNAME_PREFIX                         "_fsx_"
240
241 //XSTR:ON
242
243 // xfer entries/events
244 #define MAX_XFER_ENTRIES                                                60                              // the max allowed file xfer entries
245 typedef struct xfer_entry {
246         int flags;                                                                                                              // status flags for this entry
247         char filename[MAX_FILENAME_LEN+1];                                              // filename of the currently xferring file
248         char ex_filename[MAX_FILENAME_LEN+10];                                  // filename with xfer prefix tacked on to the front
249         CFILE *file;                                                                                                    // file handle of the current xferring file
250         int file_size;                                                                                                  // total size of the file being xferred
251         int file_ptr;                                                                                                   // total bytes we're received so far
252         ushort file_chksum;                                                                                     // used for checking successfully xferred files
253         PSNET_SOCKET_RELIABLE file_socket;                                              // socket used to xfer the file 
254         int xfer_stamp;                                                                                         // timestamp for the current operation          
255         int force_dir;                                                                                                  // force the file to go to this directory on receive (will override Multi_xfer_force_dir)       
256         ushort sig;                                                                                                             // identifying sig - sender specifies this
257 } xfer_entry;
258 xfer_entry Multi_xfer_entry[MAX_XFER_ENTRIES];                  // the file xfer entries themselves
259
260 // callback function pointer for when we start receiving a file
261 void (*Multi_xfer_recv_notify)(int handle);
262
263 // lock for the xfer system
264 int Multi_xfer_locked;
265
266 // force directory type for receives
267 int Multi_xfer_force_dir; 
268
269 // unique file signature - this along with a socket # is enough to identify all xfers
270 ushort Multi_xfer_sig = 0;
271
272
273 // ------------------------------------------------------------------------------------------
274 // MULTI XFER FORWARD DECLARATIONS
275 //
276
277 // evaluate the condition of the entry
278 void multi_xfer_eval_entry(xfer_entry *xe);
279
280 // set an entry to be "failed"
281 void multi_xfer_fail_entry(xfer_entry *xe);
282
283 // get a valid xfer entry handle
284 int multi_xfer_get_free_handle();
285
286 // process an ack for this entry
287 void multi_xfer_process_ack(xfer_entry *xe);
288
289 // process a nak for this entry
290 void multi_xfer_process_nak(xfer_entry *xe);
291                 
292 // process a "final" packet     
293 void multi_xfer_process_final(xfer_entry *xe);          
294
295 // process a data packet
296 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size);
297         
298 // process a header
299 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum);                
300
301 // send the next block of outgoing data or a "final" packet if we're done
302 void multi_xfer_send_next(xfer_entry *xe);
303
304 // send an ack to the sender
305 void multi_xfer_send_ack(PSNET_SOCKET_RELIABLE socket, ushort sig);
306
307 // send a nak to the sender
308 void multi_xfer_send_nak(PSNET_SOCKET_RELIABLE socket, ushort sig);
309
310 // send a "final" packet
311 void multi_xfer_send_final(xfer_entry *xe);
312
313 // send the header to begin a file transfer
314 void multi_xfer_send_header(xfer_entry *xe);
315
316 // convert the filename into the prefixed ex_filename
317 void multi_xfer_conv_prefix(char *filename, char *ex_filename);
318
319 // get a new xfer sig
320 ushort multi_xfer_get_sig();
321
322 // ------------------------------------------------------------------------------------------
323 // MULTI XFER FUNCTIONS
324 //
325
326 // initialize all file xfer transaction stuff, call in multi_level_init()
327 void multi_xfer_init(void (*multi_xfer_recv_callback)(int handle))
328 {
329         // blast all the entries
330         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
331
332         // assign the receive callback function pointer
333         Multi_xfer_recv_notify = multi_xfer_recv_callback;
334
335         // unlocked
336         Multi_xfer_locked = 0;
337
338         // no forced directory
339         Multi_xfer_force_dir = CF_TYPE_MULTI_CACHE;     
340 }
341
342 // do frame for all file xfers, call in multi_do_frame()
343 void multi_xfer_do()
344 {
345         int idx;
346
347         // process all valid xfer entries
348         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
349                 // if this one is actually in use and has not finished for one reason or another
350                 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))){
351                         // evaluate the condition of this entry (fail, timeout, etc)
352                         multi_xfer_eval_entry(&Multi_xfer_entry[idx]);                  
353                 }
354         }
355 }
356
357 // close down the file xfer system
358 void multi_xfer_close()
359 {
360         int idx;
361
362         // go through all active entries and abort them
363         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
364                 if(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED){
365                         multi_xfer_abort(idx);
366                 }
367         }
368
369         // now blast all the memory free
370         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
371 }
372
373 // reset the xfer system, including shutting down/killing all active xfers
374 void multi_xfer_reset()
375 {
376         int idx;
377
378         // shut down all active xfers
379         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
380                 if(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED){
381                         multi_xfer_abort(idx);
382                 }
383         }
384
385         // blast all the memory clean
386         memset(Multi_xfer_entry,0,sizeof(xfer_entry) * MAX_XFER_ENTRIES);
387 }
388
389 // send a file to the specified player, return a handle
390 int multi_xfer_send_file(PSNET_SOCKET_RELIABLE who, char *filename, int cfile_flags, int flags)
391 {
392         xfer_entry temp_entry;  
393         int handle;
394
395         // if the system is locked, return -1
396         if(Multi_xfer_locked){
397                 return -1;
398         }
399
400         // attempt to get a free handle
401         handle = multi_xfer_get_free_handle();
402         if(handle == -1){
403                 return -1;
404         }
405
406         // clear the temp entry
407         memset(&temp_entry,0,sizeof(xfer_entry));
408
409         // set the filename
410         strcpy(temp_entry.filename,filename);   
411
412         // attempt to open the file
413         temp_entry.file = NULL;
414         temp_entry.file = cfopen(filename,"rb",CFILE_NORMAL,cfile_flags);
415         if(temp_entry.file == NULL){
416 #ifdef MULTI_XFER_VERBOSE
417                 nprintf(("Network","MULTI XFER : Could not open file %s on xfer send!\n",filename));
418 #endif
419
420                 return -1;
421         }
422
423         // set the file size
424         temp_entry.file_size = -1;
425         temp_entry.file_size = cfilelength(temp_entry.file);
426         if(temp_entry.file_size == -1){
427 #ifdef MULTI_XFER_VERBOSE
428                 nprintf(("Network","MULTI XFER : Could not get file length for file %s on xfer send\n",filename));
429 #endif
430                 return -1;
431         }
432         temp_entry.file_ptr = 0;
433
434         // get the file checksum
435         if(!cf_chksum_short(temp_entry.file,&temp_entry.file_chksum)){
436 #ifdef MULTI_XFER_VERBOSE
437                 nprintf(("Network","MULTI XFER : Could not get file checksum for file %s on xfer send\n",filename));
438 #endif
439                 return -1;
440         } 
441 #ifdef MULTI_XFER_VERBOSE
442         nprintf(("Network","MULTI XFER : Got file %s checksum of %d\n",temp_entry.filename,(int)temp_entry.file_chksum));
443 #endif
444         // rewind the file pointer to the beginning of the file
445         cfseek(temp_entry.file,0,CF_SEEK_SET);
446
447         // set the flags
448         temp_entry.flags |= (MULTI_XFER_FLAG_USED | MULTI_XFER_FLAG_SEND | MULTI_XFER_FLAG_PENDING);
449         temp_entry.flags |= flags;
450
451         // set the socket       
452         temp_entry.file_socket = who;           
453
454         // set the signature
455         temp_entry.sig = multi_xfer_get_sig();
456
457         // copy to the global array
458         memset(&Multi_xfer_entry[handle],0,sizeof(xfer_entry));
459         memcpy(&Multi_xfer_entry[handle],&temp_entry,sizeof(xfer_entry));
460         
461         return handle;
462 }
463
464 // get the status of the current file xfer
465 int multi_xfer_get_status(int handle)
466 {
467         // if this is an invalid or an unused handle, notify as such
468         if((handle < 0) || (handle > (MAX_XFER_ENTRIES-1)) || !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_USED) ){
469                 return MULTI_XFER_NONE;
470         }       
471         
472         // if the xfer has timed-out
473         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_TIMEOUT){
474                 return MULTI_XFER_TIMEDOUT;
475         }
476
477         // if the xfer has failed for one reason or another (not timeout)
478         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_FAIL){
479                 return MULTI_XFER_FAIL;
480         }
481
482         // if the xfer has succeeded
483         if(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_SUCCESS){
484                 return MULTI_XFER_SUCCESS;
485         }
486
487         // if the xfer is queued
488         if((Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE) && !(Multi_xfer_entry[handle].flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
489                 return MULTI_XFER_QUEUED;
490         }
491
492         // otherwise the xfer is still in progress
493         return MULTI_XFER_IN_PROGRESS;
494 }
495
496 // abort a transferring file
497 void multi_xfer_abort(int handle)
498 {
499         xfer_entry *xe;
500
501         // don't do anything if this is an invalid handle
502         if(MULTI_XFER_INVALID_HANDLE(handle)){
503                 return;
504         }
505
506         // get e handle to the entry
507         xe = &Multi_xfer_entry[handle];
508
509         // close any open file and delete it 
510         if(xe->file != NULL){
511                 cfclose(xe->file);
512                 xe->file = NULL;
513
514                 // delete it if there isn't some problem with the filename
515                 if((xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
516                         cf_delete(xe->ex_filename, xe->force_dir);
517                 }
518         }
519
520         // zero the socket
521         xe->file_socket = INVALID_SOCKET;
522
523         // blast the entry
524         memset(xe,0,sizeof(xfer_entry));
525 }
526
527 // release an xfer handle
528 void multi_xfer_release_handle(int handle)
529 {
530         xfer_entry *xe;
531
532         // don't do anything if this is an invalid handle
533         if(MULTI_XFER_INVALID_HANDLE(handle)){
534                 return;
535         }
536
537         // get e handle to the entry
538         xe = &Multi_xfer_entry[handle];
539
540         // close any open file and delete it 
541         if(xe->file != NULL){
542                 cfclose(xe->file);
543                 xe->file = NULL;
544
545                 // delete it if the file was not successfully received
546                 if(!(xe->flags & MULTI_XFER_FLAG_SUCCESS) && (xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
547                         cf_delete(xe->ex_filename,xe->force_dir);
548                 }
549         }
550
551         // zero the socket
552         xe->file_socket = INVALID_SOCKET;       
553
554         // blast the entry
555         memset(xe,0,sizeof(xfer_entry));
556 }
557
558 // get the filename of the xfer for the given handle
559 char *multi_xfer_get_filename(int handle)
560 {
561         // if this is an invalid handle, return NULL
562         if(MULTI_XFER_INVALID_HANDLE(handle)){
563                 return NULL;
564         }
565
566         // otherwise return the string
567         return Multi_xfer_entry[handle].filename;
568 }
569
570 // lock the xfer system (don't accept incoming files, don't allow outgoing files)
571 void multi_xfer_lock()
572 {
573         Multi_xfer_locked = 1;
574 }
575
576 // unlock the xfer system
577 void multi_xfer_unlock()
578 {
579         Multi_xfer_locked = 0;
580 }
581
582 // force all receives to go into the specified directory by cfile type
583 void multi_xfer_force_dir(int cf_type)
584 {
585         Multi_xfer_force_dir = cf_type;
586         Assert(Multi_xfer_force_dir > CF_TYPE_ANY);
587 }
588
589 // forces the given xfer entry to the specified directory type (only valid when called from the recv_callback function)
590 void multi_xfer_handle_force_dir(int handle,int cf_type)
591 {
592         // if this is an invalid handle, return NULL
593         if(MULTI_XFER_INVALID_HANDLE(handle)){
594                 return;
595         }
596
597         // force to go to the given directory
598         Multi_xfer_entry[handle].force_dir = cf_type;
599         Assert(Multi_xfer_entry[handle].force_dir > CF_TYPE_ANY);
600 }
601
602 // or the flag on a given entry
603 void multi_xfer_xor_flags(int handle,int flags)
604 {
605         // if this is an invalid handle, return NULL
606         if(MULTI_XFER_INVALID_HANDLE(handle)){
607                 return;
608         }
609
610         // xor the flags
611         Multi_xfer_entry[handle].flags ^= flags;
612 }
613
614 // get the flags for a given entry
615 int multi_xfer_get_flags(int handle)
616 {
617         // if this is an invalid handle, return NULL
618         if(MULTI_XFER_INVALID_HANDLE(handle)){
619                 return -1;
620         }
621
622         // return the flags
623         return Multi_xfer_entry[handle].flags;
624 }
625
626 // if the passed filename is being xferred, return the xfer handle, otherwise return -1
627 int multi_xfer_lookup(char *filename)
628 {
629         int idx;
630
631         // if we have an invalid filename, do nothing
632         if((filename == NULL) || (strlen(filename) <= 0)){
633                 return 0;
634         }
635
636         // otherwise, perform a lookup
637         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
638                 // if we found a matching filename
639                 if((Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED) && !stricmp(filename,Multi_xfer_entry[idx].filename)){
640                         return idx;
641                 }
642         }
643
644         // did not find a match
645         return -1;
646 }
647
648 // get the % of completion of the passed file handle, return < 0 if invalid
649 float multi_xfer_pct_complete(int handle)
650 {
651         // if this is an invalid handle, return invalid
652         if(MULTI_XFER_INVALID_HANDLE(handle)){
653                 return -1.0f;
654         }
655
656         // if the file size is 0, return invalid
657         if(Multi_xfer_entry[handle].file_size == 0){
658                 return -1.0f;
659         }
660
661         // return the pct completion
662         return (float)Multi_xfer_entry[handle].file_ptr / (float)Multi_xfer_entry[handle].file_size;
663 }
664
665 // get the socket of the file xfer (useful for identifying players)
666 uint multi_xfer_get_sock(int handle)
667 {
668         // if this is an invalid handle, return NULL
669         if(MULTI_XFER_INVALID_HANDLE(handle)){
670                 return INVALID_SOCKET;
671         }
672
673         return Multi_xfer_entry[handle].file_socket;
674 }
675
676 // get the CF_TYPE of the directory this file is going to
677 int multi_xfer_get_force_dir(int handle)
678 {
679         // if this is an invalid handle, return NULL
680         if(MULTI_XFER_INVALID_HANDLE(handle)){
681                 return INVALID_SOCKET;
682         }
683
684         return Multi_xfer_entry[handle].force_dir;
685 }
686
687
688 // ------------------------------------------------------------------------------------------
689 // MULTI XFER FORWARD DECLARATIONS
690 //
691
692 // evaluate the condition of the entry
693 void multi_xfer_eval_entry(xfer_entry *xe)
694 {       
695         int idx;
696         int found;
697         xfer_entry *xe_c;
698
699         // if the entry is marked as successful, then don't do anything
700         if(xe->flags & MULTI_XFER_FLAG_SUCCESS){
701                 return;
702         }
703
704         // if the entry is queued
705         if(xe->flags & MULTI_XFER_FLAG_QUEUE){
706                 // if the entry is not current
707                 if(!(xe->flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
708                         // see if there are any other queued up xfers to this target. if not, make me current and start sending
709                         found = 0;
710                         for(idx=0; idx<MAX_XFER_ENTRIES; idx++){
711                                 xe_c = &Multi_xfer_entry[idx];
712
713                                 // if this is a valid entry and is a queued entry and is going to the same target
714                                 if((xe_c->flags & MULTI_XFER_FLAG_USED) && (xe_c->file_socket == xe->file_socket) && (xe_c->flags & MULTI_XFER_FLAG_SEND) && 
715                                         (xe_c->flags & MULTI_XFER_FLAG_QUEUE) && (xe_c->flags & MULTI_XFER_FLAG_QUEUE_CURRENT)){
716                                         
717                                         found = 1;
718                                         break;
719                                 }                               
720                         }
721
722                         // if we found no other entries, make this guy current and pending
723                         if(!found){
724                                 xe->flags |= MULTI_XFER_FLAG_QUEUE_CURRENT;
725                                 xe->flags |= MULTI_XFER_FLAG_PENDING;
726
727 #ifdef MULTI_XFER_VERBOSE
728                                 nprintf(("Network","MULTI_XFER : Starting xfer send for queued entry %s\n", xe->filename));
729 #endif
730                         } 
731                         // otherwise, do nothing for him - he has to still wait
732                         else {
733                                 return;
734                         }
735                 }
736         }
737
738         // if the entry is marked as pending - send out the header to get the ball rolling
739         if(xe->flags & MULTI_XFER_FLAG_PENDING){                
740                 // send the header to begin the transfer
741                 multi_xfer_send_header(xe);
742
743                 // set the timestamp
744                 xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT); 
745
746                 // unset the pending flag
747                 xe->flags &= ~(MULTI_XFER_FLAG_PENDING);
748
749                 // set the ack/wait flag
750                 xe->flags |= MULTI_XFER_FLAG_WAIT_ACK;
751         }
752         
753         // see if the entry has timed-out for one reason or another
754         if((xe->xfer_stamp != -1) && timestamp_elapsed(xe->xfer_stamp)){
755                 xe->flags |= MULTI_XFER_FLAG_TIMEOUT;                   
756
757                 // if we should be auto-destroying this entry, do so
758                 if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
759                         multi_xfer_fail_entry(xe);                      
760                 }
761         }               
762 }
763
764 // lookup a file xfer entry by player
765 xfer_entry *multi_xfer_find_entry(PSNET_SOCKET_RELIABLE who, ushort sig, int sender_side)
766 {
767         int idx;
768
769         // look through all valid xfer entries
770         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
771                 // if we're looking for sending entries
772                 if(sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_SEND)){
773                         continue;
774                 }
775                 // if we're looking for recv entries
776                 if(!sender_side && !(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_RECV)){
777                         continue;
778                 }
779
780                 // if we found a match
781                 if((Multi_xfer_entry[idx].file_socket == who) && (Multi_xfer_entry[idx].sig == sig)){
782                         return &Multi_xfer_entry[idx];
783                 }
784         }
785
786         return NULL;
787 }
788
789 // set an entry to be "failed"
790 void multi_xfer_fail_entry(xfer_entry *xe)
791 {
792         // set its flags appropriately
793         xe->flags &= ~(MULTI_XFER_FLAG_WAIT_ACK | MULTI_XFER_FLAG_WAIT_DATA | MULTI_XFER_FLAG_UNKNOWN);
794         xe->flags |= MULTI_XFER_FLAG_FAIL;
795
796         // close the file pointer
797         if(xe->file != NULL){
798                 cfclose(xe->file);
799                 xe->file = NULL;
800         }
801
802         // delete the file
803         if((xe->flags & MULTI_XFER_FLAG_RECV) && (strlen(xe->filename) > 0)){
804                 cf_delete(xe->ex_filename,xe->force_dir);
805         }
806                 
807         // null the timestamp
808         xe->xfer_stamp = -1;
809
810         // if we should be auto-destroying this entry, do so
811         if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
812                 multi_xfer_release_handle(xe - Multi_xfer_entry);
813         }
814
815         // blast the memory clean
816         memset(xe,0,sizeof(xfer_entry));
817 }
818
819 // get a valid xfer entry handle
820 int multi_xfer_get_free_handle()
821 {
822         int idx;
823
824         // look for a free entry
825         for(idx=0;idx<MAX_XFER_ENTRIES;idx++){
826                 if(!(Multi_xfer_entry[idx].flags & MULTI_XFER_FLAG_USED)){
827                         return idx;
828                 }
829         }
830
831         return -1;
832 }
833
834
835 // ------------------------------------------------------------------------------------------
836 // MULTI XFER PACKET HANDLERS
837 //
838
839 // process an incoming file xfer data packet, return bytes processed, guaranteed to process the entire
840 // packet regardless of error conditions
841 int multi_xfer_process_packet(unsigned char *data, PSNET_SOCKET_RELIABLE who)
842 {       
843         ubyte val;      
844         xfer_entry *xe;
845         char filename[255];
846         ushort data_size = 0;
847         int file_size = -1;
848         ushort file_checksum = 0;
849         int offset = 0;
850         ubyte xfer_data[600];
851         ushort sig;
852         int sender_side = 1;
853
854         // read in all packet data
855         GET_DATA(val);  
856         GET_DATA(sig);
857         switch(val){
858         // RECV side
859         case MULTI_XFER_CODE_DATA:                              
860                 GET_DATA(data_size);            
861                 memcpy(xfer_data, data + offset, data_size);
862                 offset += data_size;
863                 sender_side = 0;
864                 break;
865
866         // RECV side
867         case MULTI_XFER_CODE_HEADER:            
868                 GET_STRING(filename);
869                 GET_DATA(file_size);                                    
870                 GET_DATA(file_checksum);
871                 sender_side = 0;
872                 break;
873
874         // SEND side
875         case MULTI_XFER_CODE_ACK:
876         case MULTI_XFER_CODE_NAK:
877                 break;
878
879         // RECV side
880         case MULTI_XFER_CODE_FINAL:
881                 sender_side = 0;
882                 break;
883
884         default:
885                 Int3();
886         }                       
887
888         // at this point we've read all the data in the packet
889
890         // at this point, we should process code-specific data  
891         xe = NULL;
892         if(val != MULTI_XFER_CODE_HEADER){              
893                 // if the code is not a request or a header, we need to look up the existing xfer_entry
894                 xe = NULL;
895                         
896                 xe = multi_xfer_find_entry(who, sig, sender_side);
897                 if(xe == NULL){                                         
898 #ifdef MULTI_XFER_VERBOSE
899                         nprintf(("Network","MULTI XFER : Could not find xfer entry for incoming data!\n"));
900
901                         // this is a rare case - I'm not overly concerned about it. But it _does_ happen. So blech
902 #ifndef NDEBUG
903                         int np_index = find_player_socket(who);
904                         ml_string("MULTI XFER : Could not find xfer entry for incoming data :");
905                         ml_printf(": sig == %d", sig);
906                         ml_printf(": xfer header == %d", val);
907                         if(np_index < 0){
908                                 ml_string(": player == unknown");
909                         } else {
910                                 ml_printf(": player == %s", Net_players[np_index].player->callsign);
911                         }
912                         if(sender_side){
913                                 ml_string(": sending");
914                         } else {
915                                 ml_string(": receiving");
916                         }
917 #endif
918 #endif
919                 //      Int3();
920                         return offset;
921                 }
922         }
923
924         switch((int)val){
925         // process an ack for this entry
926         case MULTI_XFER_CODE_ACK :
927                 Assert(xe != NULL);
928                 multi_xfer_process_ack(xe);
929                 break;
930         
931         // process a nak for this entry
932         case MULTI_XFER_CODE_NAK :
933                 Assert(xe != NULL);
934                 multi_xfer_process_nak(xe);
935                 break;
936
937         // process a "final" packet
938         case MULTI_XFER_CODE_FINAL :
939                 Assert(xe != NULL);
940                 multi_xfer_process_final(xe);
941                 break;
942
943         // process a data packet
944         case MULTI_XFER_CODE_DATA :
945                 Assert(xe != NULL);
946                 multi_xfer_process_data(xe, xfer_data, data_size);
947                 break;
948         
949         // process a header
950         case MULTI_XFER_CODE_HEADER :
951                 // send on my reliable socket
952                 multi_xfer_process_header(xfer_data, who, sig, filename, file_size, file_checksum);
953                 break;
954         }               
955         return offset;
956 }
957
958 // process an ack for this entry
959 void multi_xfer_process_ack(xfer_entry *xe)
960 {                       
961         // if we are a sender
962         if(xe->flags & MULTI_XFER_FLAG_SEND){
963                 // if we are waiting on a final ack, then the transfer has completed successfully
964                 if(xe->flags & MULTI_XFER_FLAG_UNKNOWN){
965                         xe->flags &= ~(MULTI_XFER_FLAG_UNKNOWN);
966                         xe->flags |= MULTI_XFER_FLAG_SUCCESS;
967
968 #ifdef MULTI_XFER_VERBOSE
969                         nprintf(("Network", "MULTI XFER : Successfully sent file %s\n", xe->filename));
970 #endif
971
972                         // if we should be auto-destroying this entry, do so
973                         if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
974                                 multi_xfer_release_handle(xe - Multi_xfer_entry);
975                         }
976                 } 
977                 // otherwise if we're waiting for an ack, we should send the next chunk of data or a "final" packet if we're done
978                 else if(xe->flags & MULTI_XFER_FLAG_WAIT_ACK){
979                         multi_xfer_send_next(xe);
980                 }
981         }
982 }
983
984 // process a nak for this entry
985 void multi_xfer_process_nak(xfer_entry *xe)
986 {               
987         // if we get an ack at any time we should simply set the xfer to failed
988         multi_xfer_fail_entry(xe);
989 }
990                 
991 // process a "final" packet     
992 void multi_xfer_process_final(xfer_entry *xe)
993 {       
994         ushort chksum;
995
996         // make sure we skip a line
997         nprintf(("Network","\n"));
998         
999         // close the file
1000         if(xe->file != NULL){
1001                 cflush(xe->file);
1002                 cfclose(xe->file);
1003                 xe->file = NULL;
1004         }       
1005
1006         // check to make sure the file checksum is the same
1007         chksum = 0;
1008         if(!cf_chksum_short(xe->ex_filename, &chksum, -1, xe->force_dir) || (chksum != xe->file_chksum)){
1009                 // mark as failed
1010                 xe->flags |= MULTI_XFER_FLAG_FAIL;
1011
1012 #ifdef MULTI_XFER_VERBOSE
1013                 nprintf(("Network","MULTI XFER : file %s failed checksum %d %d!\n",xe->ex_filename, (int)xe->file_chksum, (int)chksum));
1014 #endif
1015
1016                 // abort the xfer
1017                 multi_xfer_abort(xe - Multi_xfer_entry);
1018                 return;
1019         }
1020         // checksums check out, so rename the file and be done with it
1021         else {
1022 #ifdef MULTI_XFER_VERBOSE
1023                 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));
1024 #endif
1025                 // rename the file properly
1026                 if(cf_rename(xe->ex_filename,xe->filename, xe->force_dir) == CF_RENAME_SUCCESS){
1027                         // mark the xfer as being successful
1028                         xe->flags |= MULTI_XFER_FLAG_SUCCESS;   
1029
1030                         nprintf(("Network","MULTI XFER : SUCCESSFULLY TRANSFERRED FILE %s (%d bytes)\n", xe->filename, xe->file_size));         
1031
1032                         // send an ack to the sender
1033                         multi_xfer_send_ack(xe->file_socket, xe->sig);
1034                 } else {
1035                         // mark it as failing
1036                         xe->flags |= MULTI_XFER_FLAG_FAIL;
1037                         nprintf(("Network","FAILED TO TRANSFER FILE (could not rename temp file %s)\n", xe->ex_filename));
1038
1039                         // delete the tempfile
1040                         cf_delete(xe->ex_filename, xe->force_dir);
1041
1042                         // send an nak to the sender
1043                         multi_xfer_send_nak(xe->file_socket, xe->sig);
1044                 }
1045
1046                 // if we should be auto-destroying this entry, do so
1047                 if(xe->flags & MULTI_XFER_FLAG_AUTODESTROY){
1048                         multi_xfer_release_handle(xe - Multi_xfer_entry);
1049                 }
1050         }
1051 }
1052
1053 // process a data packet
1054 void multi_xfer_process_data(xfer_entry *xe, ubyte *data, int data_size)        
1055 {                       
1056         // print out a crude progress indicator
1057         nprintf(("Network","."));               
1058
1059         // attempt to write the rest of the data string to the file
1060         if((xe->file == NULL) || !cfwrite(data, data_size, 1, xe->file)){
1061                 // inform the sender we had a problem
1062                 multi_xfer_send_nak(xe->file_socket, xe->sig);
1063
1064                 // fail this entry
1065                 multi_xfer_fail_entry(xe);
1066
1067                 xe->file_ptr += data_size;              
1068                 return;
1069         }
1070
1071         // increment the file pointer
1072         xe->file_ptr += data_size;
1073
1074         // send an ack to the sender
1075         multi_xfer_send_ack(xe->file_socket, xe->sig);
1076
1077         // set the timestmp
1078         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT); 
1079 }
1080         
1081 // process a header, return bytes processed
1082 void multi_xfer_process_header(ubyte *data, PSNET_SOCKET_RELIABLE who, ushort sig, char *filename, int file_size, ushort file_checksum)
1083 {               
1084         xfer_entry *xe;         
1085         int handle;     
1086
1087         // if the xfer system is locked, send a nak
1088         if(Multi_xfer_locked){          
1089                 multi_xfer_send_nak(who, sig);
1090                 return;
1091         }
1092
1093         // try and get a free xfer handle
1094         handle = multi_xfer_get_free_handle();
1095         if(handle == -1){               
1096                 multi_xfer_send_nak(who, sig);
1097                 return;
1098         } else {
1099                 xe = &Multi_xfer_entry[handle];
1100                 memset(xe,0,sizeof(xfer_entry));
1101         }               
1102
1103         // set the recv and used flags
1104         xe->flags |= (MULTI_XFER_FLAG_USED | MULTI_XFER_FLAG_RECV);
1105
1106         // get the header data  
1107         xe->file_size = file_size;
1108
1109         // get the file chksum
1110         xe->file_chksum = file_checksum;        
1111
1112         // set the socket
1113         xe->file_socket = who;  
1114
1115         // set the timeout timestamp
1116         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1117
1118         // set the sig
1119         xe->sig = sig;
1120
1121         // copy the filename and get the prefixed xfer filename
1122         strcpy(xe->filename, filename);
1123         multi_xfer_conv_prefix(xe->filename, xe->ex_filename);
1124 #ifdef MULTI_XFER_VERBOSE
1125         nprintf(("Network","MULTI XFER : converted filename %s to %s\n",xe->filename, xe->ex_filename));
1126 #endif
1127
1128         // determine what directory to place the file in
1129         // individual xfer entries take precedence over the global multi xfer force entry       
1130         xe->force_dir = Multi_xfer_force_dir;   
1131
1132         // call the callback function
1133         Multi_xfer_recv_notify(handle); 
1134
1135         // if the notify function invalidated this xfer handle, then cancel the whole thing
1136         if(xe->flags & MULTI_XFER_FLAG_REJECT){         
1137                 multi_xfer_send_nak(who, sig);
1138                 
1139                 // clear the data
1140                 memset(xe, 0, sizeof(xfer_entry));
1141                 return;
1142         }                       
1143
1144         // delete the old file (if it exists)
1145         cf_delete( xe->filename, CF_TYPE_MULTI_CACHE );
1146         cf_delete( xe->filename, CF_TYPE_MISSIONS );
1147
1148         // attempt to open the file (using the prefixed filename)
1149         xe->file = NULL;
1150         xe->file = cfopen(xe->ex_filename, "wb", CFILE_NORMAL, xe->force_dir);
1151         if(xe->file == NULL){           
1152                 multi_xfer_send_nak(who, sig);          
1153
1154                 // clear the data
1155                 memset(xe, 0, sizeof(xfer_entry));
1156                 return;
1157         }
1158         
1159         // set the waiting for data flag
1160         xe->flags |= MULTI_XFER_FLAG_WAIT_DATA;         
1161
1162         // send an ack to the server            
1163         multi_xfer_send_ack(who, sig);  
1164
1165 #ifdef MULTI_XFER_VERBOSE
1166         nprintf(("Network","MULTI XFER : AFTER HEADER %s\n",xe->filename));
1167 #endif  
1168 }
1169
1170 // send the next block of outgoing data or a "final" packet if we're done
1171 void multi_xfer_send_next(xfer_entry *xe)
1172 {
1173         ubyte data[MAX_PACKET_SIZE],code;
1174         ushort data_size;
1175         int flen;
1176         int packet_size = 0;    
1177
1178         // print out a crude progress indicator
1179         nprintf(("Network", "+"));              
1180
1181         // if we've sent all the data, then we should send a "final" packet
1182         if(xe->file_ptr >= xe->file_size){
1183                 // mark the entry as unknown 
1184                 xe->flags |= MULTI_XFER_FLAG_UNKNOWN;
1185
1186                 // set the timestmp
1187                 xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1188
1189                 // send the packet
1190                 multi_xfer_send_final(xe);              
1191
1192                 return;
1193         }
1194
1195         // build the header 
1196         BUILD_HEADER(XFER_PACKET);      
1197
1198         // length of the added string
1199         flen = strlen(xe->filename) + 4;
1200
1201         // determine how much data we are going to send with this packet and add it in
1202         if((xe->file_size - xe->file_ptr) >= (MULTI_XFER_MAX_DATA_SIZE - flen)){
1203                 data_size = (ushort)(MULTI_XFER_MAX_DATA_SIZE - flen);
1204         } else {
1205                 data_size = (unsigned short)(xe->file_size - xe->file_ptr);
1206         }
1207         // increment the file pointer
1208         xe->file_ptr += data_size;      
1209
1210         // add the opcode
1211         code = MULTI_XFER_CODE_DATA;
1212         ADD_DATA(code);
1213
1214         // add the sig
1215         ADD_DATA(xe->sig);
1216
1217         // add in the size of the rest of the packet    
1218         ADD_DATA(data_size);
1219         
1220         // copy in the data
1221         if(cfread(data+packet_size,1,(int)data_size,xe->file) == 0){
1222                 // send a nack to the receiver
1223                 multi_xfer_send_nak(xe->file_socket, xe->sig);
1224
1225                 // fail this send
1226                 multi_xfer_fail_entry(xe);              
1227                 return;
1228         }
1229
1230         // increment the packet size
1231         packet_size += (int)data_size;
1232
1233         // set the timestmp
1234         xe->xfer_stamp = timestamp(MULTI_XFER_TIMEOUT);
1235
1236         // otherwise send the data      
1237         psnet_rel_send(xe->file_socket, data, packet_size);
1238 }
1239
1240 // send an ack to the sender
1241 void multi_xfer_send_ack(PSNET_SOCKET_RELIABLE socket, ushort sig)
1242 {
1243         ubyte data[MAX_PACKET_SIZE],code;       
1244         int packet_size = 0;
1245
1246         // build the header and add 
1247         BUILD_HEADER(XFER_PACKET);      
1248
1249         // add the opcode
1250         code = MULTI_XFER_CODE_ACK;
1251         ADD_DATA(code);
1252
1253         // add the sig
1254         ADD_DATA(sig);
1255         
1256         // send the data        
1257         psnet_rel_send(socket, data, packet_size);
1258 }
1259
1260 // send a nak to the sender
1261 void multi_xfer_send_nak(PSNET_SOCKET_RELIABLE socket, ushort sig)
1262 {
1263         ubyte data[MAX_PACKET_SIZE],code;       
1264         int packet_size = 0;
1265
1266         // build the header and add the code
1267         BUILD_HEADER(XFER_PACKET);      
1268
1269         // add the opcode
1270         code = MULTI_XFER_CODE_NAK;
1271         ADD_DATA(code);
1272
1273         // add the sig
1274         ADD_DATA(sig);
1275
1276         // send the data        
1277         psnet_rel_send(socket, data, packet_size);
1278 }
1279
1280 // send a "final" packet
1281 void multi_xfer_send_final(xfer_entry *xe)
1282 {
1283         ubyte data[MAX_PACKET_SIZE],code;       
1284         int packet_size = 0;
1285
1286         // build the header
1287         BUILD_HEADER(XFER_PACKET);      
1288
1289         // add the code
1290         code = MULTI_XFER_CODE_FINAL;
1291         ADD_DATA(code);
1292
1293         // add the sig
1294         ADD_DATA(xe->sig);
1295
1296         // send the data        
1297         psnet_rel_send(xe->file_socket, data, packet_size);
1298 }
1299
1300 // send the header to begin a file transfer
1301 void multi_xfer_send_header(xfer_entry *xe)
1302 {
1303         ubyte data[MAX_PACKET_SIZE],code;       
1304         int packet_size = 0;
1305
1306         // build the header and add the opcode
1307         BUILD_HEADER(XFER_PACKET);      
1308         code = MULTI_XFER_CODE_HEADER;
1309         ADD_DATA(code);
1310
1311         // add the sig
1312         ADD_DATA(xe->sig);
1313
1314         // add the filename
1315         ADD_STRING(xe->filename);
1316                 
1317         // add the id #
1318         ADD_DATA(xe->file_size);
1319
1320         // add the file checksum
1321         ADD_DATA(xe->file_chksum);
1322
1323         // send the packet      
1324         psnet_rel_send(xe->file_socket, data, packet_size);
1325 }
1326
1327 // convert the filename into the prefixed ex_filename
1328 void multi_xfer_conv_prefix(char *filename,char *ex_filename)
1329 {
1330         char temp[MAX_FILENAME_LEN+50];
1331         
1332         // blast the memory clean
1333         memset(temp, 0, MAX_FILENAME_LEN+50);
1334
1335         // copy in the prefix
1336         strcpy(temp, MULTI_XFER_FNAME_PREFIX);
1337
1338         // stick on the original name
1339         strcat(temp, filename);
1340
1341         // copy the whole thing to the outgoing filename
1342         strcpy(ex_filename, temp);
1343 }
1344
1345 // get a new xfer sig
1346 ushort multi_xfer_get_sig()
1347 {
1348         ushort ret = Multi_xfer_sig;
1349
1350         // new one
1351         if(Multi_xfer_sig == 0xffff){
1352                 Multi_xfer_sig = 0;
1353         } else {
1354                 Multi_xfer_sig++;
1355         }
1356
1357         return ret;
1358 }