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