1 // Emacs style mode select -*- C++ -*-
2 //-----------------------------------------------------------------------------
3 //
4 // $Id: d_netfil.c 1544 2020-08-22 02:40:35Z wesleyjohnson $
5 //
6 // Copyright (C) 1998-2016 by DooM Legacy Team.
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License
10 // as published by the Free Software Foundation; either version 2
11 // of the License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU General Public License for more details.
17 //
18 //
19 // $Log: d_netfil.c,v $
20 // Revision 1.26 2004/04/20 00:34:26 andyp
21 // Linux compilation fixes and string cleanups
22 //
23 // Revision 1.25 2003/05/04 04:28:33 sburke
24 // Use SHORT to convert network data between big- and little-endian format.
25 //
26 // Revision 1.24 2001/07/28 16:18:37 bpereira
27 // Revision 1.23 2001/05/21 16:23:32 crashrl
28 //
29 // Revision 1.22 2001/05/21 14:57:05 crashrl
30 // Readded directory crawling file search function
31 //
32 // Revision 1.21 2001/05/16 17:12:52 crashrl
33 // Added md5-sum support, removed recursiv wad search
34 //
35 // Revision 1.20 2001/05/14 19:02:58 metzgermeister
36 // * Fixed floor not moving up with player on E3M1
37 // * Fixed crash due to oversized string in screen message ... bad bug!
38 // * Corrected some typos
39 // * fixed sound bug in SDL
40 //
41 // Revision 1.19 2001/04/17 22:26:07 calumr
42 // Initial Mac add
43 //
44 // Revision 1.18 2001/03/30 17:12:49 bpereira
45 // Revision 1.17 2001/02/24 13:35:19 bpereira
46 // Revision 1.16 2001/02/13 20:37:27 metzgermeister
47 // Revision 1.15 2001/02/10 12:27:13 bpereira
48 //
49 // Revision 1.14 2001/01/25 22:15:41 bpereira
50 // added heretic support
51 //
52 // Revision 1.13 2000/10/08 13:30:00 bpereira
53 // Revision 1.12 2000/10/02 18:25:44 bpereira
54 // Revision 1.11 2000/09/28 20:57:14 bpereira
55 // Revision 1.10 2000/09/10 10:39:06 metzgermeister
56 // Revision 1.9 2000/08/31 14:30:55 bpereira
57 // Revision 1.8 2000/08/11 19:10:13 metzgermeister
58 //
59 // Revision 1.7 2000/08/10 14:52:38 ydario
60 // OS/2 port
61 //
62 // Revision 1.6 2000/04/16 18:38:07 bpereira
63 //
64 // Revision 1.5 2000/03/07 03:32:24 hurdler
65 // fix linux compilation
66 //
67 // Revision 1.4 2000/03/05 17:10:56 bpereira
68 // Revision 1.3 2000/02/27 00:42:10 hurdler
69 // Revision 1.2 2000/02/26 00:28:42 hurdler
70 // Mostly bug fix (see borislog.txt 23-2-2000, 24-2-2000)
71 //
72 //
73 // DESCRIPTION:
74 // Transfer a file using HSendPacket
75 //
76 //-----------------------------------------------------------------------------
77
78
79 #include <stdio.h>
80 #include <fcntl.h>
81
82 #ifdef __OS2__
83 #include <sys/types.h>
84 #endif // __OS2__
85
86 #include <sys/stat.h>
87
88 #include <time.h>
89
90 #if defined( WIN32) || defined( __DJGPP__ )
91 #include <io.h>
92 #include <direct.h>
93 #else
94 #include <sys/types.h>
95 //#include <dirent.h>
96 #include <utime.h>
97 #endif
98
99 #ifdef __WIN32__
100 #include <sys/utime.h>
101 #else
102 #include <unistd.h>
103 #endif
104
105 #ifdef __DJGPP__
106 #include <dir.h>
107 #include <utime.h>
108 #endif
109
110 #ifdef ZIPWAD
111 #include <zip.h>
112 #endif
113
114 #include "doomincl.h"
115 #include "doomstat.h"
116 #include "d_net.h"
117 #include "d_netfil.h"
118 #include "d_clisrv.h"
119 #include "g_game.h"
120 #include "i_net.h"
121 #include "i_system.h"
122 #include "m_argv.h"
123 #include "w_wad.h"
124 #include "z_zone.h"
125 #include "byteptr.h"
126 #include "p_setup.h"
127 #include "m_misc.h"
128 #include "m_menu.h"
129 #include "v_video.h"
130 // V_DrawString
131 #include "d_main.h"
132 // DOOMWADDIR
133 #include "md5.h"
134
135 // sender structure
136 typedef struct filetx_s {
137 TAH_e release_tah; // release, access method
138 char * filename; // name of the file
139 byte * data; // data of data transfer
140 uint32_t data_size; // size of data transfer
141 char fileid; // fileid from PT_REQUESTFILE
142 // byte dest_node; // client node destination (UNUSED)
143 struct filetx_s *next; // a queue
144 } filetx_t;
145
146 // Current transfers (one for each node).
147 // One active file/data transfer per node.
148 typedef struct {
149 filetx_t *txlist; // only set by server
150 uint32_t position; // file and data transfer position
151 FILE* currentfile;
152 } transfer_t;
153
154 // Only transfer files to player nodes.
155 static transfer_t transfer[MAXNETNODES];
156
157 // read time of file : stat _stmtime
158 // write time of file : utime
159
160 typedef struct {
161 char filename[MAX_WADPATH];
162 unsigned char md5sum[16];
163 // used only for download
164 FILE *phandle; // open file (owned)
165 uint32_t bytes_recv; // to determine when done and for status
166 uint32_t totalsize;
167 filestatus_e status; // the value returned by recsearch
168 } fileneed_t;
169
170 // Client receiver structure
171 byte netfile_download = 0; // tested by users
172 byte cl_num_fileneed = 0;
173 static fileneed_t cl_fileneed[MAX_WADFILES];
174
175 const char * downloaddir = "DOWNLOAD";
176
177 static void SV_SendFile(byte to_node, char *filename, char fileid);
178
179 static
update_download_done(void)180 void update_download_done( void )
181 {
182 int i;
183 for( i=0; i<cl_num_fileneed; i++ )
184 {
185 byte st = cl_fileneed[i].status;
186 if( st > FS_FOUND ) return;
187 }
188 netfile_download = 0;
189 }
190
191
192 // By server.
193 // Fill the serverinfo packet with wad files loaded by the game on the server.
Put_Server_FileNeed(void)194 byte * Put_Server_FileNeed(void)
195 {
196 int i;
197 byte *p; // macros want byte*
198 char wadfilename[MAX_WADPATH];
199
200 // Format: Series of file descriptor, number of file in packet field.
201 // Dest buff length: fileneed[FILENEED_BUFF_LEN]
202 p=(byte *)&netbuffer->u.serverinfo.fileneed;
203 for(i=0;i<numwadfiles;i++)
204 {
205 // Format: filesize uint32, filename str0, md5sum 16byte
206 WRITEU32(p, wadfiles[i]->filesize);
207 strcpy(wadfilename,wadfiles[i]->filename);
208 nameonly(wadfilename);
209 p = write_string(p, wadfilename);
210
211 // char array, is endian safe
212 WRITEMEM(p,wadfiles[i]->md5sum,16);
213 }
214 netbuffer->u.serverinfo.num_fileneed = i; // numwadfiles
215 return p;
216 }
217
218 // By Client
219 // Handle the received serverinfo packet and fill client fileneed table.
CL_Got_Fileneed(int num_fileneed_parm,byte * fileneed_str)220 void CL_Got_Fileneed(int num_fileneed_parm, byte *fileneed_str)
221 {
222 int i, fn_len;
223 byte *p = fileneed_str;
224 byte * bufend16 = &fileneed_str[FILENEED_BUFF_LEN - 1 - 16];
225 byte * next0;
226 // NULL when not found
227
228 // Format: Series of file descriptor, number of file as parameter.
229 // Src buff length: fileneed[FILENEED_BUFF_LEN]
230 // Must have 0 term.
231 // Last 16 bytes of content will be md5sum, so cannot just tack on 0.
232
233 cl_num_fileneed = num_fileneed_parm;
234 for(i=0; i<cl_num_fileneed; i++) // MAX_WADFILES
235 {
236 // Format: filesize uint32, filename str0, md5sum 16byte
237 fileneed_t * fnp = & cl_fileneed[i]; // client fileneed
238
239 // Protect against malicious packet without 0 term.
240 if( p >= bufend16 ) goto bad_packet; // buffer overrun
241
242 fnp->status = FS_NOTFOUND;
243 fnp->totalsize = READU32(p);
244 fnp->phandle = NULL;
245
246 // [WDJ] String overflow safe
247 next0 = memchr( p, '\0', bufend16 - p );
248 if((next0 == NULL) || (next0 > bufend16))
249 {
250 fnp->filename[0] = '\0';
251 goto bad_packet; // overran last 0 term.
252 }
253 // Test on next0 guarantees that there is a 0 term.
254 fn_len = next0 - p + 1; // strnlen equiv.
255 int read_len = min( fn_len, MAX_WADPATH-1 ); // length safe
256 memcpy(fnp->filename, p, read_len);
257 fnp->filename[MAX_WADPATH-1] = '\0';
258 p += fn_len; // whole, next0 + 1
259
260 // char array, is endian safe
261 READMEM(p,fnp->md5sum,16);
262 }
263 return;
264
265 bad_packet:
266 GenPrintf(EMSG_warn, "Fileneed bad packet\n" );
267 return;
268 }
269
270 #define BUFFSIZE 128
271 // By Client
272 // Return true while waiting on fileneed files.
CL_waiting_on_fileneed(void)273 boolean CL_waiting_on_fileneed( void )
274 {
275 static byte stat_cnt2 = 0;
276 boolean waiting = false;
277 char b[BUFFSIZE];
278 int i;
279 int pos = 0;
280
281 // [WDJ] Status reporting moved here, consistent file report in a box.
282 // Update stats on screen.
283
284 M_DrawTextBox( 2, NETFILE_BOX_Y, 38, 6);
285 if(stat_cnt2++ > 4)
286 {
287 stat_cnt2 = 0;
288 // First call in CL_ConnectToServer
289 Net_GetNetStat();
290 }
291 snprintf( b, BUFFSIZE-1, "Download File %4.2f KBPS", (float)netstat_recv_bps/1024 );
292 b[BUFFSIZE-1] = 0;
293 V_DrawString (30, NETFILE_BOX_Y+8, 0, b);
294
295 for(i=0; i<cl_num_fileneed; i++)
296 {
297 fileneed_t * fnp = & cl_fileneed[i];
298 if(fnp->status==FS_DOWNLOADING || fnp->status==FS_REQUESTED)
299 {
300 waiting = true;
301 // Display the actively loading files, in the box, first 4.
302 if( pos < (8*4) )
303 {
304 char * f = strchr( fnp->filename, '/' );
305 f = (f)? f+1 : fnp->filename;
306 snprintf( b, BUFFSIZE-1, "%-40s %4i %4i",
307 f, fnp->totalsize>>10, fnp->bytes_recv>>10 );
308 b[BUFFSIZE-1] = 0;
309 V_DrawString (12, NETFILE_BOX_Y+16+pos, 0, b );
310 pos += 8;
311 }
312 }
313 }
314
315 if( verbose>1 && ! waiting )
316 {
317 // Print final Stat
318 GenPrintf(EMSG_info, "Download speed %4.2f KBPS",
319 ((float)netstat_recv_bps)/1024);
320 }
321 netfile_download = waiting;
322 return waiting;
323 }
324
325 // Do not load savegame while any other file download for this client is in progress.
326
327 // By Client.
328 // Prepare to receive a savegame.
CL_Prepare_download_savegame(const char * tmpsave)329 void CL_Prepare_download_savegame(const char *tmpsave)
330 {
331 // Savegames always have SAVEGAME_FILEID.
332 strcpy(cl_fileneed[SAVEGAME_FILEID].filename, tmpsave);
333 cl_fileneed[SAVEGAME_FILEID].status = FS_REQUESTED;
334 cl_fileneed[SAVEGAME_FILEID].totalsize = -1;
335 cl_fileneed[SAVEGAME_FILEID].phandle = NULL;
336 memset(cl_fileneed[SAVEGAME_FILEID].md5sum, 0, 16); // none
337
338 cl_num_fileneed = 1;
339 netfile_download = 1;
340 }
341
342 // By Client.
CL_Cancel_download_savegame(void)343 void CL_Cancel_download_savegame( void )
344 {
345 cl_num_fileneed = 0;
346 netfile_download = 0;
347 }
348
349
350 // By Client.
351 // Send to the server the names of requested files.
352 // Files who status is FS_NOTFOUND in the fileneed table are sent.
353 // Return RFR_success when request succeeds.
Send_RequestFile(void)354 reqfile_e Send_RequestFile(void)
355 {
356 char filetmp[ MAX_WADPATH ];
357 int i, fcnt;
358 uint64_t availablefreespace;
359 uint32_t totalfreespaceneeded=0;
360 fileneed_t * fnp;
361
362 if( M_CheckParm("-nodownload")
363 || (cv_download_files.EV == 0) ) // download not allowed
364 {
365 int j;
366 int len;
367 char s[1024];
368
369 // Not allowed to download files.
370 // Check for missing files.
371 s[0]=0;
372 for(i=0; i<cl_num_fileneed; i++)
373 {
374 fnp = & cl_fileneed[i];
375 if( fnp->status!=FS_FOUND )
376 {
377 len = strlen(s);
378 if( len > (sizeof(s)-80) ) break; // prevent buffer overrun
379
380 strcat(s," \"");
381 strcat(s,fnp->filename);
382 strcat(s,"\"");
383 switch(fnp->status)
384 {
385 case FS_NOTFOUND:
386 strcat(s," not found");
387 break;
388 case FS_MD5SUMBAD:
389 strcat(s," has wrong md5sum, needs: ");
390
391 for(j=0; j<16; j++)
392 {
393 sprintf(&s[len],"%02x", fnp->md5sum[j]);
394 len += 2;
395 }
396 s[len]='\0';
397 break;
398 case FS_OPEN:
399 strcat(s," found, ok");
400 break;
401 default:
402 strcat(s, " unknown reason");
403 break;
404 }
405 strcat(s,"\n");
406 }
407 }
408 if( s[0] == 0 )
409 return RFR_success; // All files are satisfied
410
411 // This error message needs to be with s[].
412 I_SoftError("To play with this server you should have these files:\n"
413 "%s\n"
414 "Remove -nodownload if you want to get them from the server!\n",
415 s );
416 return RFR_nodownload;
417 }
418
419
420 // prepare to download
421 I_mkdir(downloaddir,0755);
422
423 // Make up one or more request packet to get files from the server.
424 fcnt = 0; // used as fileid, and index to cl_fileneed
425 do{
426 // Format: one or more file requests.
427 // byte fileid; // 0xFF = terminate
428 // string filename; // 0 term
429 byte *p = netbuffer->u.bytepak.b;
430 int bcnt = 0;
431 for(; fcnt<cl_num_fileneed; fcnt++)
432 {
433 fnp = & cl_fileneed[fcnt];
434 if( fnp->status == FS_NOTFOUND || fnp->status == FS_MD5SUMBAD)
435 {
436 if( fnp->status == FS_NOTFOUND )
437 totalfreespaceneeded += fnp->totalsize;
438 strcpy( filetmp, fnp->filename );
439 nameonly(filetmp);
440
441 // [WDJ] Check for net buffer overflow.
442 int nxt_bcnt = bcnt + strlen( filetmp ) + 1;
443 if( nxt_bcnt > MAX_NETBYTE_LEN-1 ) break;
444 bcnt = nxt_bcnt;
445
446 WRITECHAR(p,fcnt); // fileid, 0..n
447 p = write_string(p, filetmp);
448
449 // put it in download dir
450 cat_filename( fnp->filename, downloaddir, filetmp );
451 fnp->status = FS_REQUESTED;
452 }
453 }
454 WRITECHAR(p,-1);
455 netbuffer->packettype = PT_REQUESTFILE;
456
457 if( bcnt == 0 ) goto broken_format; // broken, filename too long
458
459 availablefreespace = I_GetDiskFreeSpace();
460 // debug_Printf("free byte %d\n",availablefreespace);
461 if(totalfreespaceneeded > availablefreespace) goto insufficient_space;
462
463 byte errcode = HSendPacket(cl_servernode, SP_reliable, 0, p - netbuffer->u.bytepak.b);
464 if( errcode >= NE_fail )
465 return RFR_send_fail;
466
467 netfile_download = 1;
468 }while( fcnt<cl_num_fileneed );
469 return RFR_success;
470
471 broken_format:
472 I_SoftError("Cannot form File Request for file %s\n", filetmp );
473 return RFR_nodownload;
474
475 // Rare errors
476 insufficient_space:
477 I_SoftError("To play on this server you should download %dKb\n"
478 "but you have only %dKb freespace on this drive\n",
479 totalfreespaceneeded, availablefreespace);
480 return RFR_insufficient_space;
481 }
482
483 // By Server.
484 // PT_REQUESTFILE
485 // Received request filepak. Put the files to the send queue.
Got_RequestFilePak(byte nnode)486 void Got_RequestFilePak(byte nnode)
487 {
488 char *p = (char *)netbuffer->u.bytepak.b;
489
490 // format: REPEAT( byte fileid, string0 filename ), 0xFF
491 // The requester determines a fileid for each filename.
492 while((byte)*p!=0xFF) // fileid
493 {
494 SV_SendFile(nnode, p+1, *p);
495 p++; // skip fileid
496 SKIPSTRING(p);
497 }
498 }
499
500
501 // By Client.
502 // Check if the fileneed from the server are already loaded or on the disk.
CL_CheckFiles(void)503 checkfiles_e CL_CheckFiles(void)
504 {
505 int ret;
506 int i,j;
507 fileneed_t * fnp;
508 char wadfilename[MAX_WADPATH];
509
510 if( M_CheckParm("-nofiles") )
511 return CFR_no_files;
512
513 // The first fileneed is the iwad (the main wad file).
514 // Do not check file date.
515 strcpy(wadfilename, wadfiles[0]->filename);
516 nameonly(wadfilename);
517 if( strcasecmp(wadfilename, cl_fileneed[0].filename) != 0 )
518 {
519 M_SimpleMessage(va("You cannot connect to this server\n"
520 "since it uses %s\n"
521 "You are using %s\n",
522 cl_fileneed[0].filename, wadfilename));
523 return CFR_iwad_error;
524 }
525 cl_fileneed[0].status=FS_OPEN;
526
527 ret = CFR_all_found;
528 for (i=1; i<cl_num_fileneed; i++)
529 {
530 fnp = &cl_fileneed[i];
531 if(devparm)
532 GenPrintf(EMSG_dev, "searching for '%s' ", fnp->filename);
533
534 // check in already loaded files
535 for(j=1;wadfiles[j];j++)
536 {
537 strcpy(wadfilename,wadfiles[j]->filename);
538 nameonly(wadfilename);
539 if( strcasecmp(wadfilename, fnp->filename)==0
540 && !memcmp(wadfiles[j]->md5sum, fnp->md5sum, 16))
541 {
542 if(devparm)
543 GenPrintf(EMSG_dev, "already loaded\n");
544 fnp->status = FS_OPEN;
545 break;
546 }
547 }
548 if( fnp->status!=FS_NOTFOUND )
549 continue;
550
551 // Net security permissions.
552 fnp->status = findfile(fnp->filename, fnp->md5sum, true,
553 /*OUT*/ fnp->filename);
554 if(devparm)
555 GenPrintf(EMSG_dev, "found %d\n", fnp->status);
556 if( fnp->status != FS_FOUND )
557 ret = CFR_download_needed;
558 }
559 return ret;
560 }
561
562 // By Client.
563 // Load unsatisfied fileneed now.
564 // Return false when have a failure.
CL_Load_ServerFiles(void)565 boolean CL_Load_ServerFiles(void)
566 {
567 int i;
568 fileneed_t * fnp;
569
570 // File 0 is the game IWAD.
571 for (i=1; i<cl_num_fileneed; i++)
572 {
573 fnp = & cl_fileneed[i];
574 if( fnp->status == FS_OPEN )
575 {
576 // already loaded
577 continue;
578 }
579 else
580 if( fnp->status == FS_FOUND )
581 {
582 P_AddWadFile(fnp->filename,NULL);
583 fnp->status = FS_OPEN;
584 }
585 else
586 if( fnp->status == FS_MD5SUMBAD)
587 {
588 P_AddWadFile(fnp->filename,NULL);
589 fnp->status = FS_OPEN;
590 CONS_Printf("\2File %s found but with different md5sum\n", fnp->filename);
591 }
592 else
593 {
594 I_SoftError("Try to load file %s with status of %d\n",
595 fnp->filename, fnp->status);
596 return false;
597 }
598 }
599 return true;
600 }
601
602
603
604 // By Server.
605 // A little optimization to test if there is a file in the queue.
606 // Tested by caller of Filetx_Ticker, as enable.
607 // Only the server can enable it.
608 int Filetx_file_cnt = 0;
609
610 // append filetx to txlist
611 static
append_to_txlist(byte to_node,filetx_t * ftp)612 void append_to_txlist( byte to_node, filetx_t * ftp )
613 {
614 // Use indirect ptr to treat head and link the same.
615 filetx_t ** txlpp = & transfer[to_node].txlist;
616 while( *txlpp ) txlpp= &((*txlpp)->next); // find end of txlist
617 *txlpp = ftp; // head or next link
618
619 Filetx_file_cnt++;
620 }
621
622
623 // By Server.
624 // Send a file to client, using client fileid.
625 // to_node : the client node.
626 // filename : wad file to send
627 // fileid : fileid from PT_REQUESTFILE
SV_SendFile(byte to_node,char * filename,char fileid)628 static void SV_SendFile(byte to_node, char *filename, char fileid)
629 {
630 filetx_t *p;
631 int i;
632 char * tx_filename;
633 char wadfilename[MAX_WADPATH];
634
635 p = (filetx_t *)malloc(sizeof(filetx_t));
636 if(!p) goto memory_err;
637
638 tx_filename=(char *)malloc(MAX_WADPATH);
639 if(! tx_filename) goto memory_err;
640
641 p->filename = tx_filename; // filename buffer owner
642
643 strncpy(tx_filename, filename, MAX_WADPATH-1);
644 tx_filename[MAX_WADPATH-1] = '\0';
645
646 // a minimum of security, can only get file in legacy wad directories
647 nameonly(tx_filename);
648
649 // Find the requested file in loaded files.
650 for(i=0; wadfiles[i]; i++)
651 {
652 strcpy(wadfilename,wadfiles[i]->filename);
653 nameonly(wadfilename);
654 if(strcasecmp(wadfilename, tx_filename)==0)
655 {
656 // copy filename with full path
657 strncpy(tx_filename, wadfiles[i]->filename, MAX_WADPATH-1);
658 tx_filename[MAX_WADPATH-1] = '\0';
659 goto send_found;
660 }
661 }
662
663 // Not found error handling.
664 GenPrintf( EMSG_ver, "Requested file, %s, not found in wadfiles.\n", filename );
665 DEBFILE(va("%s not found in wadfiles\n", filename));
666
667 // Net security permissions.
668 if( findfile( tx_filename, NULL, true, /*OUT*/ tx_filename ) == FS_NOTFOUND )
669 {
670 // not found
671 // don't inform client (probably hacker)
672 DEBFILE(va("Client %d request %s : not found\n", to_node, filename));
673 free(tx_filename);
674 free(p);
675 }
676 return;
677
678 // Found the file.
679 send_found:
680 GenPrintf( EMSG_ver, "Sending file %s to %d.\n", filename, to_node );
681 DEBFILE(va("Sending file %s to %d (id=%d)\n", filename, to_node, fileid));
682
683 p->release_tah=TAH_FILE;
684 // size initialized at file open
685 //p->size=size;
686 p->fileid=fileid; // client supplied id for this file
687 p->data = NULL;
688 p->next=NULL; // end of list
689 append_to_txlist( to_node, p );
690
691 return;
692
693 memory_err:
694 I_Error("SendFile: cannot allocate file buffer.\n");
695 }
696
697 // By Server.
698 // to_node : dest node
699 // data : data buffer
700 // size : size of data buffer
701 // tah : how data buffer was allocated
702 // fileid : always 0
SV_SendData(byte to_node,const char * name,byte * data,uint32_t size,TAH_e tah,char fileid)703 void SV_SendData(byte to_node, const char * name, byte *data, uint32_t size, TAH_e tah, char fileid)
704 {
705 filetx_t *p;
706
707 p=(filetx_t *)malloc(sizeof(filetx_t));
708 if(!p) goto memory_err;
709
710 p->release_tah=tah;
711 p->filename= (char*) name; // lose const, but tah makes it not freed.
712 p->data = data;
713 p->data_size=size;
714 p->fileid=fileid;
715 p->next=NULL; // end of list
716 append_to_txlist( to_node, p );
717
718 DEBFILE(va("SendData %s (size:%d) to %d (id=%d)\n",
719 p->filename, size, to_node, fileid));
720
721 return;
722
723 memory_err:
724 I_Error("SendData: cannot allocate data buffer.\n");
725 }
726
727 // By Server.
728 // Close and release the current transfer of the net node.
729 // nnode : net node, 0..(MAXNETNODES-1)
SV_End_SendFile(byte nnode)730 static void SV_End_SendFile(byte nnode)
731 {
732 transfer_t * tnnp = & transfer[nnode];
733 filetx_t * ftxp = tnnp->txlist; // the transfer list
734
735 if( ! ftxp ) // cannot ensure who can call and what state they are in
736 return;
737
738 // By Server.
739 // Deallocation
740 switch (ftxp->release_tah)
741 {
742 case TAH_FILE:
743 if( tnnp->currentfile )
744 {
745 fclose( tnnp->currentfile );
746 }
747 free(ftxp->filename);
748 break;
749 case TAH_Z_FREE:
750 Z_Free(ftxp->data);
751 break;
752 case TAH_MALLOC_FREE:
753 free(ftxp->data);
754 break;
755 case TAH_NOTHING:
756 break;
757 }
758 tnnp->currentfile = NULL; // transfer file, and fake file
759 tnnp->txlist = ftxp->next; // remove filetx from the list
760 free(ftxp);
761 // Master transfer status
762 Filetx_file_cnt--;
763 }
764
765 // By Server.
766 // Called by NetUpdate, CL_ConnectToServer, repair_handler.
Filetx_Ticker(void)767 void Filetx_Ticker(void)
768 {
769 static byte txnode=0; // net node num, 0..(MAXNETNODES-1)
770 byte nn; // net node num
771
772 TAH_e access_tah;
773 uint32_t send_size;
774 int tcnt;
775 int packet_cnt;
776 FILE * fp; // (ref) tnnp current file
777 filetx_pak_t * pak;
778 filetx_t * ftxp;
779 transfer_t * tnnp; // transfer for net node
780
781 if( Filetx_file_cnt == 0 ) goto reject; // nothing to do
782
783 // By Server, only server has Filetx_file_cnt > 0.
784
785 // Packets per tic
786 packet_cnt = net_bandwidth/(TICRATE*software_MAXPACKETLENGTH);
787 if(packet_cnt==0)
788 packet_cnt++;
789 // (((stat_sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(uint32_t)net_bandwidth)
790
791 while( packet_cnt-- && (Filetx_file_cnt > 0) )
792 {
793 // Round robin, fair share.
794 nn = (txnode+1)%MAXNETNODES;
795 for( tcnt=0; tcnt<MAXNETNODES; tcnt++ ) // counter
796 {
797 if(transfer[nn].txlist)
798 goto found;
799 nn = (nn+1)%MAXNETNODES;
800 }
801 // no transfer to do
802 goto transfer_not_found; // no transfer to do
803
804 found:
805 txnode = nn;
806 tnnp = & transfer[nn]; // transfers for the net node
807 ftxp = tnnp->txlist; // list of file/data
808 access_tah = ftxp->release_tah;
809
810 fp = tnnp->currentfile;
811 if(!fp) // file not already open
812 {
813 if(access_tah == TAH_FILE)
814 {
815 // open the file to transfer
816 long filesize;
817
818 fp = fopen(ftxp->filename,"rb");
819 tnnp->currentfile = fp; // owner of open file
820
821 if(! fp)
822 {
823 perror("FileTx");
824 I_SoftError("FileTx: Cannot open file %s\n",
825 ftxp->filename);
826 SV_End_SendFile(nn);
827 continue;
828 }
829
830 fseek(fp, 0, SEEK_END);
831 filesize = ftell( fp );
832
833 // nobody wants to transfer a file bigger than 4GB!
834 // and computers will never need more than 640kb of RAM ;-)
835 if(-1 == filesize) goto file_size_err;
836
837 ftxp->data_size = filesize;
838 fseek(fp, 0, SEEK_SET);
839 }
840 else
841 {
842 tnnp->currentfile = (FILE *)1; // faked open flag
843 }
844 tnnp->position = 0;
845 }
846
847 pak=&netbuffer->u.filetxpak;
848 send_size = software_MAXPACKETLENGTH - (FILETX_HEADER_SIZE+PACKET_BASE_SIZE);
849 if( send_size > ftxp->data_size - tnnp->position )
850 send_size = ftxp->data_size - tnnp->position;
851
852 if(access_tah == TAH_FILE)
853 {
854 if( fread(pak->data, send_size, 1, tnnp->currentfile) != 1 )
855 goto file_read_err;
856 }
857 else
858 {
859 memcpy(pak->data, &ftxp->data[ tnnp->position ], send_size);
860 }
861 pak->position = tnnp->position;
862 // put flag so receiver know the totalsize
863 if( tnnp->position + send_size >= ftxp->data_size )
864 {
865 // End of send file flag.
866 pak->position |= 0x80000000;
867 }
868 pak->position = LE_SWAP32_FAST(pak->position);
869 pak->size = LE_SWAP16_FAST(send_size);
870 pak->fileid = ftxp->fileid;
871 netbuffer->packettype=PT_FILEFRAGMENT;
872
873 // Reliable SEND
874 byte errcode = HSendPacket(nn, SP_reliable, 0, FILETX_HEADER_SIZE + send_size );
875 if( errcode >= NE_fail )
876 { // not sent for some odd reason
877 // retry at next call
878 if(access_tah == TAH_FILE)
879 {
880 // Data transfer reposition
881 fseek( fp, tnnp->position, SEEK_SET);
882 }
883 // exit the while (can't send this one why should i send the next ?
884 break;
885 }
886
887 // Record each fragment of file transfer.
888 tnnp->position += send_size;
889 if(tnnp->position >= ftxp->data_size)
890 {
891 // All sent
892 SV_End_SendFile(nn);
893 }
894 } // while
895 return;
896
897 // Rare fatal errors.
898 file_size_err:
899 perror("FileTx");
900 I_SoftError("FileTx: Error getting filesize of %s\n", ftxp->filename);
901 SV_End_SendFile(nn);
902 goto reject;
903
904 file_read_err:
905 perror("FileTx");
906 I_SoftError("Filetx: Read err on %s at %d of %d bytes\n",
907 ftxp->filename, tnnp->position, send_size);
908 goto reject;
909
910 transfer_not_found:
911 I_SoftError("Filetx: Filetx_file_cnt=%d but Filetx file not found\n", Filetx_file_cnt);
912 Filetx_file_cnt = 0;
913 goto reject;
914
915 reject:
916 return;
917 }
918
919
920 // By Client.
921 // Incoming file fragments from server.
922 // Called by Net_Packet_Handler, unknown_host_handler.
Got_Filetxpak(void)923 void Got_Filetxpak(void)
924 {
925 static int stat_cnt = 0; // steps spent receiving file
926
927 int filenum = netbuffer->u.filetxpak.fileid;
928 fileneed_t * fnp;
929 char * fname; // filename
930 FILE * fp;
931
932 if(filenum>=cl_num_fileneed)
933 {
934 DEBFILE(va("filefragment fileid %d >= requested %d\n",filenum,cl_num_fileneed));
935 goto reject;
936 }
937
938 fnp = & cl_fileneed[filenum];
939 if( fnp->status == FS_REQUESTED )
940 {
941 if(fnp->phandle) goto file_already_open;
942
943 // Open the file.
944 fname = fnp->filename;
945 fp = fopen( fname,"wb" );
946 fnp->phandle = fp; // owner of open file
947 if(!fp) goto file_create_err;
948
949 GenPrintf(EMSG_hud, "\r%s ...", fname);
950 fnp->bytes_recv = 0;
951 fnp->status = FS_DOWNLOADING;
952 }
953
954 if( fnp->status == FS_DOWNLOADING )
955 {
956 // Swap file position and size on big_endian machines.
957 netbuffer->u.filetxpak.position = LE_SWAP32(netbuffer->u.filetxpak.position);
958 netbuffer->u.filetxpak.size = LE_SWAP16(netbuffer->u.filetxpak.size);
959
960 // File is finished only when have received all parts of it, in any order.
961 // WARNING: filepak can arrive out of order so don't stop now !
962 if( netbuffer->u.filetxpak.position & 0x80000000 )
963 {
964 // End of send file flag.
965 netbuffer->u.filetxpak.position &= ~0x80000000;
966 fnp->totalsize = netbuffer->u.filetxpak.position + netbuffer->u.filetxpak.size;
967 }
968 // we can receive packet in the wrong order, anyway all os support gaped file
969 fp = fnp->phandle; // file being loaded
970 fname = fnp->filename; // for status and err msgs
971 fseek(fp, netbuffer->u.filetxpak.position, SEEK_SET);
972 if( fwrite(netbuffer->u.filetxpak.data, netbuffer->u.filetxpak.size, 1, fp) != 1 )
973 goto file_write_err;
974 fnp->bytes_recv += netbuffer->u.filetxpak.size;
975
976 #if 0
977 if(stat_cnt==0)
978 {
979 // Update stats on screen.
980 Net_GetNetStat();
981 GenPrintf(EMSG_hud, "\r%s %dK/%dK %.1fK/s",
982 fname,
983 fnp->bytes_recv>>10,
984 fnp->totalsize>>10,
985 ((float)netstat_recv_bps)/1024);
986 }
987 #endif
988
989 // Detect when all of file received.
990 if(fnp->bytes_recv == fnp->totalsize)
991 {
992 fclose( fp );
993 fnp->phandle = NULL;
994 fnp->status = FS_FOUND;
995 GenPrintf(EMSG_hud, "\rDownloading %s ... (done)\n", fname);
996 update_download_done();
997 }
998 }
999 else
1000 {
1001 I_SoftError("Received a file not requested\n");
1002 goto reject;
1003 }
1004 // send ack back quickly
1005
1006 if(++stat_cnt==4)
1007 {
1008 // Client send to server.
1009 Net_Send_AcksPacket( cl_servernode ); // a packet of acks
1010 stat_cnt=0;
1011 }
1012 return;
1013
1014 // Rare errors.
1015 file_create_err:
1016 I_SoftError("Got_Filetxpak: File create error: %s\n", fname);
1017 goto reject;
1018
1019 file_write_err:
1020 I_SoftError("Got_Filetxpak: File write error: %s\n", fname);
1021 goto reject;
1022
1023 file_already_open:
1024 I_SoftError("Got_Filetxpak: Received a file that is already open\n");
1025 goto reject;
1026
1027 reject:
1028 return;
1029 }
1030
1031 // By Server, to cleanup sending files.
1032 // By Client, does nothing useful.
1033 // nnode: 0..(MAXNETNODES-1)
1034 // Called by Net_CloseConnection, CloseNetFile
Abort_SendFiles(byte nnode)1035 void Abort_SendFiles(byte nnode)
1036 {
1037 while(transfer[nnode].txlist)
1038 {
1039 // By Server, only server have txlist set.
1040 SV_End_SendFile(nnode);
1041 }
1042 }
1043
1044 // By Server, Client
1045 // Called by D_Quit_NetGame
Close_NetFile(void)1046 void Close_NetFile(void)
1047 {
1048 int i;
1049
1050 // Abort sending.
1051 for( i=0;i<MAXNETNODES;i++)
1052 Abort_SendFiles(i);
1053
1054 // Abort receiving a file.
1055 for( i=0; i<MAX_WADFILES; i++ )
1056 {
1057 fileneed_t * fnp = & cl_fileneed[i];
1058 if( fnp->status==FS_DOWNLOADING && fnp->phandle)
1059 {
1060 fclose(fnp->phandle);
1061 // file is not complete, delete it
1062 remove(fnp->filename);
1063 }
1064 }
1065
1066 // Remove FILEFRAGMENT from ackpaks.
1067 Net_AbortPacketType(PT_FILEFRAGMENT);
1068
1069 netfile_download = 0;
1070 }
1071
1072 // functions cut and pasted from doomatic :)
1073
1074 // Remove all except filename at tail
nameonly(char * s)1075 void nameonly(char *s)
1076 {
1077 int j;
1078
1079 for(j=strlen(s);j>=0;j--)
1080 {
1081 if( (s[j]=='\\') || (s[j]==':') || (s[j]=='/') )
1082 {
1083 // [WDJ] DO NOT USE memcpy, these may overlap, use memmove
1084 memmove(s, &(s[j+1]), strlen(&(s[j+1]))+1 );
1085 return;
1086 }
1087 }
1088 }
1089
1090
1091 #if 0
1092 // UNUSED for now
1093 boolean fileexist(char *filename, time_t chk_time)
1094 {
1095 int handle;
1096 handle=open(filename,O_RDONLY|O_BINARY);
1097 if( handle!=-1 )
1098 {
1099 close(handel);
1100 if(chk_time!=0)
1101 {
1102 struct stat bufstat;
1103 stat(filename,&bufstat);
1104 if( chk_time!=bufstat.st_mtime )
1105 return false;
1106 }
1107 return true;
1108 }
1109 return false;
1110 }
1111 #endif
1112
1113
1114 // filename : check the md5 sum of this file
1115 // wantedmd5sum : compare to this md5 sum, NULL if no check
1116 // Return :
1117 // FS_NOTFOUND : file not found
1118 // FS_FOUND : when md5 sum matches, or if no check when file opens for reading
1119 // FS_MD5SUMBAD : when md5 sum does not match
checkfile_md5(const char * filename,const byte * wantedmd5sum)1120 filestatus_e checkfile_md5( const char * filename, const byte * wantedmd5sum)
1121 {
1122 unsigned char md5sum[16];
1123 filestatus_e return_val = FS_NOTFOUND;
1124
1125 #ifdef ZIPWAD
1126 // if ! ziplib_present, then cannot have archive_open
1127 if( archive_open )
1128 {
1129 if( wantedmd5sum )
1130 {
1131 // Find file in archive, then check md5 sum.
1132 return_val = WZ_md5_stream( filename, md5sum );
1133 if( return_val == FS_FOUND )
1134 goto compare_md5_sums;
1135 }
1136 else
1137 {
1138 // Just check that file exists.
1139 if( WZ_find_file_in_archive( filename, NULL ) == FS_FOUND )
1140 return FS_FOUND;
1141 }
1142 // Not found in archive, so check file system too.
1143 }
1144 #endif
1145
1146 {
1147 FILE * fhandle = fopen(filename,"rb");
1148 if( fhandle == NULL )
1149 goto done;
1150
1151 return_val = FS_FOUND;
1152
1153 if( wantedmd5sum )
1154 {
1155 md5_stream( fhandle, md5sum );
1156 }
1157
1158 fclose(fhandle);
1159 }
1160
1161 if( ! wantedmd5sum ) // Just check that file exists.
1162 goto done; // FOUND, NOTFOUND, or worse
1163
1164 #ifdef ZIPWAD
1165 compare_md5_sums:
1166 #endif
1167 if( memcmp(wantedmd5sum, md5sum, 16) )
1168 return_val = FS_MD5SUMBAD;
1169
1170 done:
1171 return return_val;
1172 }
1173
1174
1175 // Search the search directories for the file, with all controls.
1176 // filename: simple filename to find in a doomwaddir
1177 // search_depth: if > 0 then search subdirectories to that depth
1178 // wantedmd5sum : NULL for no md5 check
1179 // completepath: the file name buffer, must be length MAX_WADPATH
1180 // Return FS_FOUND, with the file path in the completepath parameter.
1181 // FS_NOTFOUND
1182 // FS_MD5SUMBAD
1183 static
FullSearch_doomwaddir(const char * filename,int search_depth,const byte * wantedmd5sum,char * completepath)1184 filestatus_e FullSearch_doomwaddir( const char * filename, int search_depth,
1185 const byte * wantedmd5sum,
1186 /* OUT */ char * completepath )
1187 {
1188 filestatus_e fs = FS_NOTFOUND;
1189 int wdi;
1190
1191 for( wdi=0; wdi<MAX_NUM_DOOMWADDIR; wdi++ )
1192 {
1193 if( doomwaddir[wdi] == NULL ) continue;
1194 if( access( doomwaddir[wdi], X_OK ) ) continue;
1195
1196 fs = sys_filesearch( filename, doomwaddir[wdi], wantedmd5sum,
1197 search_depth, completepath );
1198 if( fs == FS_FOUND ) break;
1199 }
1200 return fs;
1201 }
1202
1203 // Search the doom directories, simplified, with owner privilege.
1204 // filename: the search file
1205 // search_depth: if > 0 then search subdirectories to that depth
1206 // completepath: the file name buffer, must be length MAX_WADPATH
1207 // Return FS_FOUND when found, with the file path in the completepath parameter.
1208 // Return FS_ZIP when alternative zip file is found.
1209 // Called by: Check_wad_filenames, Identify_Version (legacy.wad and iwad).
Search_doomwaddir(const char * filename,int search_depth,char * completepath)1210 filestatus_e Search_doomwaddir( const char * filename, int search_depth,
1211 /* OUT */ char * completepath )
1212 {
1213 // Search normal.
1214 if( FullSearch_doomwaddir( filename, search_depth, NULL,
1215 /*OUT*/ completepath ) == FS_FOUND )
1216 return FS_FOUND;
1217
1218 // Not found.
1219
1220 #ifdef ZIPWAD
1221 #ifdef ZIPWAD_OPTIONAL
1222 if( ! ziplib_present )
1223 return FS_NOTFOUND;
1224 #endif
1225
1226 // If not searching directories, then don't search archives either.
1227 if( search_depth > 0 )
1228 {
1229 // Look for an archive file of the same name.
1230 char * arch_filename = WZ_make_archive_name( filename );
1231 if( arch_filename )
1232 {
1233 if( FullSearch_doomwaddir( arch_filename, search_depth, NULL,
1234 /*OUT*/ completepath ) == FS_FOUND )
1235 return FS_ZIP;
1236 }
1237 }
1238 #endif
1239
1240 return FS_NOTFOUND;
1241 }
1242
1243
1244 // Determine if the filename is simple, or has an inherent file path.
1245 // Return the correct inherent filepath.
1246 // Return NULL for a simple filename.
file_searchpath(const char * filename)1247 const char * file_searchpath( const char * filename )
1248 {
1249 // Leading char test, must be before any relative path test.
1250 if( filename[0] == '/' || filename[0] == '\\' || filename[1] == ':' )
1251 return ""; // Absolute path
1252 if( filename[0] == '.' && filename[1] == '.' )
1253 return ""; // Relative blank path.
1254
1255 // Complex filename are file path.
1256 if( strpbrk( filename, ":/\\~" ) )
1257 {
1258 return "."; // Relative to default path
1259 }
1260
1261 if( strstr( filename, ".." ) )
1262 {
1263 return "."; // Relative to default path
1264 }
1265
1266 return NULL; // Simple
1267 }
1268
1269 // Search the doom directories, with md5, restricted privilege.
1270 // filename : the filename to be found
1271 // wantedmd5sum : NULL for no md5 check
1272 // net_secure : true for net downloads, restricted access
1273 // completepath : when not NULL, return the full path and name
1274 // must be a buffer of MAX_WADPATH
1275 // return FS_NOTFOUND
1276 // FS_MD5SUMBAD
1277 // FS_FOUND
1278 // FS_SECURITY
findfile(const char * filename,const byte * wantedmd5sum,boolean net_secure,char * completepath)1279 filestatus_e findfile( const char * filename, const byte * wantedmd5sum,
1280 boolean net_secure,
1281 /*OUT*/ char * completepath )
1282 {
1283 filestatus_e ret_val;
1284
1285 const char * ipath = file_searchpath( filename );
1286 // Complex filename are file path.
1287 if( ipath )
1288 {
1289 if( net_secure )
1290 {
1291 // Net access
1292 // No absolute paths, no subdirectories.
1293 // Cannot back out of directories.
1294 return FS_SECURITY;
1295 }
1296
1297 // Test for reading.
1298 // Do not need ipath for actual absolute or relative access.
1299 if( access( filename, R_OK ) != 0 )
1300 return FS_NOTFOUND;
1301
1302 if( completepath )
1303 cat_filename( completepath, "", filename );
1304 return FS_FOUND;
1305 }
1306
1307 // Simple filename for search doomwaddir.
1308 if( net_secure )
1309 {
1310 // Restrict Net access to only relevant files, for security.
1311 const char * extension = &filename[strlen(filename)-3];
1312 if( strcasecmp( extension,"wad")!=0
1313 && strcasecmp( extension,"deh")!=0
1314 && strcasecmp( extension,"bex")!=0
1315 #ifdef ZIPWAD
1316 && strcasecmp( extension,"zip")!=0
1317 #endif
1318 )
1319 return FS_SECURITY;
1320
1321 // Net is only allowed access to public wad directories.
1322 doomwaddir[1] = NULL;
1323 doomwaddir[2] = NULL;
1324 doomwaddir[MAX_NUM_DOOMWADDIR-2] = NULL;
1325 doomwaddir[MAX_NUM_DOOMWADDIR-1] = NULL;
1326 }
1327 else
1328 {
1329 // defdir is usually "."
1330 owner_wad_search_order();
1331 }
1332
1333 // Search doomwaddir for simple filename.
1334 ret_val = FullSearch_doomwaddir( filename, GAME_SEARCH_DEPTH, wantedmd5sum,
1335 /* OUT */ completepath );
1336
1337 #if 1
1338 return ret_val;
1339 #else
1340 if( ret_val == FS_FOUND )
1341 return FS_FOUND;
1342
1343 // [WDJ] 10 levels had it thrash for a long time when given a bad name.
1344 // Not needed with above directory searches.
1345 // This is a security risk that allows anyone to download private files
1346 // off your computer (using an altered DoomLegacy).
1347 return sys_filesearch(filename, ".", wantedmd5sum, 3, completepath);
1348 #endif
1349 }
1350