1 // SONIC ROBO BLAST 2
2 //-----------------------------------------------------------------------------
3 // Copyright (C) 1998-2000 by DooM Legacy Team.
4 // Copyright (C) 1999-2020 by Sonic Team Junior.
5 //
6 // This program is free software distributed under the
7 // terms of the GNU General Public License, version 2.
8 // See the 'LICENSE' file for more details.
9 //-----------------------------------------------------------------------------
10 /// \file  d_netfil.c
11 /// \brief Transfer a file using HSendPacket.
12 
13 #include <stdio.h>
14 #include <sys/stat.h>
15 
16 #include <time.h>
17 
18 #if defined (_WIN32) || defined (__DJGPP__)
19 #include <io.h>
20 #include <direct.h>
21 #else
22 #include <sys/types.h>
23 #include <dirent.h>
24 #include <utime.h>
25 #endif
26 
27 #ifdef __GNUC__
28 #include <unistd.h>
29 #include <limits.h>
30 #elif defined (_WIN32)
31 #include <sys/utime.h>
32 #endif
33 #ifdef __DJGPP__
34 #include <dir.h>
35 #include <utime.h>
36 #endif
37 
38 #include "doomdef.h"
39 #include "doomstat.h"
40 #include "d_main.h"
41 #include "g_game.h"
42 #include "i_net.h"
43 #include "i_system.h"
44 #include "m_argv.h"
45 #include "d_net.h"
46 #include "w_wad.h"
47 #include "d_netfil.h"
48 #include "z_zone.h"
49 #include "byteptr.h"
50 #include "p_setup.h"
51 #include "m_misc.h"
52 #include "m_menu.h"
53 #include "md5.h"
54 #include "filesrch.h"
55 
56 #include <errno.h>
57 
58 // Prototypes
59 static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid);
60 
61 // Sender structure
62 typedef struct filetx_s
63 {
64 	INT32 ram;
65 	union {
66 		char *filename; // Name of the file
67 		char *ram; // Pointer to the data in RAM
68 	} id;
69 	UINT32 size; // Size of the file
70 	UINT8 fileid;
71 	INT32 node; // Destination
72 	struct filetx_s *next; // Next file in the list
73 } filetx_t;
74 
75 // Current transfers (one for each node)
76 typedef struct filetran_s
77 {
78 	filetx_t *txlist; // Linked list of all files for the node
79 	UINT8 iteration;
80 	UINT8 ackediteration;
81 	UINT32 position; // The current position in the file
82 	boolean *ackedfragments;
83 	UINT32 ackedsize;
84 	FILE *currentfile; // The file currently being sent/received
85 	tic_t dontsenduntil;
86 } filetran_t;
87 static filetran_t transfer[MAXNETNODES];
88 
89 // Read time of file: stat _stmtime
90 // Write time of file: utime
91 
92 // Receiver structure
93 INT32 fileneedednum; // Number of files needed to join the server
94 fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
95 static tic_t lasttimeackpacketsent = 0;
96 char downloaddir[512] = "DOWNLOAD";
97 
98 // For resuming failed downloads
99 typedef struct
100 {
101 	char filename[MAX_WADPATH];
102 	UINT8 md5sum[16];
103 	boolean *receivedfragments;
104 	UINT32 fragmentsize;
105 	UINT32 currentsize;
106 } pauseddownload_t;
107 static pauseddownload_t *pauseddownload = NULL;
108 
109 #ifndef NONET
110 // for cl loading screen
111 INT32 lastfilenum = -1;
112 #endif
113 
114 luafiletransfer_t *luafiletransfers = NULL;
115 boolean waitingforluafiletransfer = false;
116 boolean waitingforluafilecommand = false;
117 char luafiledir[256 + 16] = "luafiles";
118 
119 
120 /** Fills a serverinfo packet with information about wad files loaded.
121   *
122   * \todo Give this function a better name since it is in global scope.
123   * Used to have size limiting built in - now handled via W_LoadWadFile in w_wad.c
124   *
125   */
PutFileNeeded(void)126 UINT8 *PutFileNeeded(void)
127 {
128 	size_t i, count = 0;
129 	UINT8 *p = netbuffer->u.serverinfo.fileneeded;
130 	char wadfilename[MAX_WADPATH] = "";
131 	UINT8 filestatus;
132 
133 	for (i = 0; i < numwadfiles; i++)
134 	{
135 		// If it has only music/sound lumps, don't put it in the list
136 		if (!wadfiles[i]->important)
137 			continue;
138 
139 		filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
140 
141 		// Store in the upper four bits
142 		if (!cv_downloading.value)
143 			filestatus += (2 << 4); // Won't send
144 		else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
145 			filestatus += (1 << 4); // Will send if requested
146 		// else
147 			// filestatus += (0 << 4); -- Won't send, too big
148 
149 		WRITEUINT8(p, filestatus);
150 
151 		count++;
152 		WRITEUINT32(p, wadfiles[i]->filesize);
153 		nameonly(strcpy(wadfilename, wadfiles[i]->filename));
154 		WRITESTRINGN(p, wadfilename, MAX_WADPATH);
155 		WRITEMEM(p, wadfiles[i]->md5sum, 16);
156 	}
157 	netbuffer->u.serverinfo.fileneedednum = (UINT8)count;
158 
159 	return p;
160 }
161 
162 /** Parses the serverinfo packet and fills the fileneeded table on client
163   *
164   * \param fileneedednum_parm The number of files needed to join the server
165   * \param fileneededstr The memory block containing the list of needed files
166   *
167   */
D_ParseFileneeded(INT32 fileneedednum_parm,UINT8 * fileneededstr)168 void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr)
169 {
170 	INT32 i;
171 	UINT8 *p;
172 	UINT8 filestatus;
173 
174 	fileneedednum = fileneedednum_parm;
175 	p = (UINT8 *)fileneededstr;
176 	for (i = 0; i < fileneedednum; i++)
177 	{
178 		fileneeded[i].status = FS_NOTFOUND; // We haven't even started looking for the file yet
179 		fileneeded[i].justdownloaded = false;
180 		filestatus = READUINT8(p); // The first byte is the file status
181 		fileneeded[i].willsend = (UINT8)(filestatus >> 4);
182 		fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
183 		fileneeded[i].file = NULL; // The file isn't open yet
184 		READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
185 		READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
186 	}
187 }
188 
CL_PrepareDownloadSaveGame(const char * tmpsave)189 void CL_PrepareDownloadSaveGame(const char *tmpsave)
190 {
191 #ifndef NONET
192 	lastfilenum = -1;
193 #endif
194 
195 	fileneedednum = 1;
196 	fileneeded[0].status = FS_REQUESTED;
197 	fileneeded[0].justdownloaded = false;
198 	fileneeded[0].totalsize = UINT32_MAX;
199 	fileneeded[0].file = NULL;
200 	memset(fileneeded[0].md5sum, 0, 16);
201 	strcpy(fileneeded[0].filename, tmpsave);
202 }
203 
204 /** Checks the server to see if we CAN download all the files,
205   * before starting to create them and requesting.
206   *
207   * \return True if we can download all the files
208   *
209   */
CL_CheckDownloadable(void)210 boolean CL_CheckDownloadable(void)
211 {
212 	UINT8 i,dlstatus = 0;
213 
214 	for (i = 0; i < fileneedednum; i++)
215 		if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
216 		{
217 			if (fileneeded[i].willsend == 1)
218 				continue;
219 
220 			if (fileneeded[i].willsend == 0)
221 				dlstatus = 1;
222 			else //if (fileneeded[i].willsend == 2)
223 				dlstatus = 2;
224 		}
225 
226 	// Downloading locally disabled
227 	if (!dlstatus && M_CheckParm("-nodownload"))
228 		dlstatus = 3;
229 
230 	if (!dlstatus)
231 		return true;
232 
233 	// not downloadable, put reason in console
234 	CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
235 	for (i = 0; i < fileneedednum; i++)
236 		if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
237 		{
238 			CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
239 
240 				if (fileneeded[i].status == FS_NOTFOUND)
241 					CONS_Printf(M_GetText(" not found, md5: "));
242 				else if (fileneeded[i].status == FS_MD5SUMBAD)
243 					CONS_Printf(M_GetText(" wrong version, md5: "));
244 
245 			{
246 				INT32 j;
247 				char md5tmp[33];
248 				for (j = 0; j < 16; j++)
249 					sprintf(&md5tmp[j*2], "%02x", fileneeded[i].md5sum[j]);
250 				CONS_Printf("%s", md5tmp);
251 			}
252 			CONS_Printf("\n");
253 		}
254 
255 	switch (dlstatus)
256 	{
257 		case 1:
258 			CONS_Printf(M_GetText("Some files are larger than the server is willing to send.\n"));
259 			break;
260 		case 2:
261 			CONS_Printf(M_GetText("The server is not allowing download requests.\n"));
262 			break;
263 		case 3:
264 			CONS_Printf(M_GetText("All files downloadable, but you have chosen to disable downloading locally.\n"));
265 			break;
266 	}
267 	return false;
268 }
269 
270 /** Returns true if a needed file transfer can be resumed
271   *
272   * \param file The needed file to resume the transfer for
273   * \return True if the transfer can be resumed
274   *
275   */
CL_CanResumeDownload(fileneeded_t * file)276 static boolean CL_CanResumeDownload(fileneeded_t *file)
277 {
278 	return pauseddownload
279 		&& !strcmp(pauseddownload->filename, file->filename) // Same name
280 		&& !memcmp(pauseddownload->md5sum, file->md5sum, 16) // Same checksum
281 		&& pauseddownload->fragmentsize == file->fragmentsize; // Same fragment size
282 }
283 
CL_AbortDownloadResume(void)284 void CL_AbortDownloadResume(void)
285 {
286 	if (!pauseddownload)
287 		return;
288 
289 	free(pauseddownload->receivedfragments);
290 	remove(pauseddownload->filename);
291 	free(pauseddownload);
292 	pauseddownload = NULL;
293 }
294 
295 /** Sends requests for files in the ::fileneeded table with a status of
296   * ::FS_NOTFOUND.
297   *
298   * \return True if the packet was successfully sent
299   * \note Sends a PT_REQUESTFILE packet
300   *
301   */
CL_SendFileRequest(void)302 boolean CL_SendFileRequest(void)
303 {
304 	char *p;
305 	INT32 i;
306 	INT64 totalfreespaceneeded = 0, availablefreespace;
307 
308 #ifdef PARANOIA
309 	if (M_CheckParm("-nodownload"))
310 		I_Error("Attempted to download files in -nodownload mode");
311 
312 	for (i = 0; i < fileneedednum; i++)
313 		if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
314 			&& (fileneeded[i].willsend == 0 || fileneeded[i].willsend == 2))
315 		{
316 			I_Error("Attempted to download files that were not sendable");
317 		}
318 #endif
319 
320 	netbuffer->packettype = PT_REQUESTFILE;
321 	p = (char *)netbuffer->u.textcmd;
322 	for (i = 0; i < fileneedednum; i++)
323 		if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD))
324 		{
325 			totalfreespaceneeded += fileneeded[i].totalsize;
326 			nameonly(fileneeded[i].filename);
327 			WRITEUINT8(p, i); // fileid
328 			WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
329 			// put it in download dir
330 			strcatbf(fileneeded[i].filename, downloaddir, "/");
331 			fileneeded[i].status = FS_REQUESTED;
332 		}
333 	WRITEUINT8(p, 0xFF);
334 	I_GetDiskFreeSpace(&availablefreespace);
335 	if (totalfreespaceneeded > availablefreespace)
336 		I_Error("To play on this server you must download %s KB,\n"
337 			"but you have only %s KB free space on this drive\n",
338 			sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10)));
339 
340 	// prepare to download
341 	I_mkdir(downloaddir, 0755);
342 	return HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd);
343 }
344 
345 // get request filepak and put it on the send queue
346 // returns false if a requested file was not found or cannot be sent
PT_RequestFile(INT32 node)347 boolean PT_RequestFile(INT32 node)
348 {
349 	char wad[MAX_WADPATH+1];
350 	UINT8 *p = netbuffer->u.textcmd;
351 	UINT8 id;
352 	while (p < netbuffer->u.textcmd + MAXTEXTCMD-1) // Don't allow hacked client to overflow
353 	{
354 		id = READUINT8(p);
355 		if (id == 0xFF)
356 			break;
357 		READSTRINGN(p, wad, MAX_WADPATH);
358 		if (!AddFileToSendQueue(node, wad, id))
359 		{
360 			SV_AbortSendFiles(node);
361 			return false; // don't read the rest of the files
362 		}
363 	}
364 	return true; // no problems with any files
365 }
366 
367 /** Checks if the files needed aren't already loaded or on the disk
368   *
369   * \return 0 if some files are missing
370   *         1 if all files exist
371   *         2 if some already loaded files are not requested or are in a different order
372   *
373   */
CL_CheckFiles(void)374 INT32 CL_CheckFiles(void)
375 {
376 	INT32 i, j;
377 	char wadfilename[MAX_WADPATH];
378 	INT32 ret = 1;
379 	size_t packetsize = 0;
380 	size_t filestoget = 0;
381 
382 //	if (M_CheckParm("-nofiles"))
383 //		return 1;
384 
385 	// the first is the iwad (the main wad file)
386 	// we don't care if it's called srb2.pk3 or not.
387 	// Never download the IWAD, just assume it's there and identical
388 	fileneeded[0].status = FS_OPEN;
389 
390 	// Modified game handling -- check for an identical file list
391 	// must be identical in files loaded AND in order
392 	// Return 2 on failure -- disconnect from server
393 	if (modifiedgame)
394 	{
395 		CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
396 		for (i = 1, j = 1; i < fileneedednum || j < numwadfiles;)
397 		{
398 			if (j < numwadfiles && !wadfiles[j]->important)
399 			{
400 				// Unimportant on our side.
401 				++j;
402 				continue;
403 			}
404 
405 			// If this test is true, we've reached the end of one file list
406 			// and the other still has a file that's important
407 			if (i >= fileneedednum || j >= numwadfiles)
408 				return 2;
409 
410 			// For the sake of speed, only bother with a md5 check
411 			if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
412 				return 2;
413 
414 			// It's accounted for! let's keep going.
415 			CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
416 			fileneeded[i].status = FS_OPEN;
417 			++i;
418 			++j;
419 		}
420 		return 1;
421 	}
422 
423 	// See W_LoadWadFile in w_wad.c
424 	packetsize = packetsizetally;
425 
426 	for (i = 1; i < fileneedednum; i++)
427 	{
428 		CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
429 
430 		// Check in already loaded files
431 		for (j = 1; wadfiles[j]; j++)
432 		{
433 			nameonly(strcpy(wadfilename, wadfiles[j]->filename));
434 			if (!stricmp(wadfilename, fileneeded[i].filename) &&
435 				!memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
436 			{
437 				CONS_Debug(DBG_NETPLAY, "already loaded\n");
438 				fileneeded[i].status = FS_OPEN;
439 				break;
440 			}
441 		}
442 		if (fileneeded[i].status != FS_NOTFOUND)
443 			continue;
444 
445 		packetsize += nameonlylength(fileneeded[i].filename) + 22;
446 
447 		if ((numwadfiles+filestoget >= MAX_WADFILES)
448 		|| (packetsize > MAXFILENEEDED*sizeof(UINT8)))
449 			return 3;
450 
451 		filestoget++;
452 
453 		fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
454 		CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
455 		if (fileneeded[i].status != FS_FOUND)
456 			ret = 0;
457 	}
458 	return ret;
459 }
460 
461 // Load it now
CL_LoadServerFiles(void)462 void CL_LoadServerFiles(void)
463 {
464 	INT32 i;
465 
466 //	if (M_CheckParm("-nofiles"))
467 //		return;
468 
469 	for (i = 1; i < fileneedednum; i++)
470 	{
471 		if (fileneeded[i].status == FS_OPEN)
472 			continue; // Already loaded
473 		else if (fileneeded[i].status == FS_FOUND)
474 		{
475 			P_AddWadFile(fileneeded[i].filename);
476 			G_SetGameModified(true);
477 			fileneeded[i].status = FS_OPEN;
478 		}
479 		else if (fileneeded[i].status == FS_MD5SUMBAD)
480 			I_Error("Wrong version of file %s", fileneeded[i].filename);
481 		else
482 		{
483 			const char *s;
484 			switch(fileneeded[i].status)
485 			{
486 			case FS_NOTFOUND:
487 				s = "FS_NOTFOUND";
488 				break;
489 			case FS_REQUESTED:
490 				s = "FS_REQUESTED";
491 				break;
492 			case FS_DOWNLOADING:
493 				s = "FS_DOWNLOADING";
494 				break;
495 			default:
496 				s = "unknown";
497 				break;
498 			}
499 			I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
500 				fileneeded[i].status, s);
501 		}
502 	}
503 }
504 
AddLuaFileTransfer(const char * filename,const char * mode)505 void AddLuaFileTransfer(const char *filename, const char *mode)
506 {
507 	luafiletransfer_t **prevnext; // A pointer to the "next" field of the last transfer in the list
508 	luafiletransfer_t *filetransfer;
509 	static INT32 id;
510 
511 	// Find the last transfer in the list and set a pointer to its "next" field
512 	prevnext = &luafiletransfers;
513 	while (*prevnext)
514 		prevnext = &((*prevnext)->next);
515 
516 	// Allocate file transfer information and append it to the transfer list
517 	filetransfer = malloc(sizeof(luafiletransfer_t));
518 	if (!filetransfer)
519 		I_Error("AddLuaFileTransfer: Out of memory\n");
520 	*prevnext = filetransfer;
521 	filetransfer->next = NULL;
522 
523 	// Allocate the file name
524 	filetransfer->filename = strdup(filename);
525 	if (!filetransfer->filename)
526 		I_Error("AddLuaFileTransfer: Out of memory\n");
527 
528 	// Create and allocate the real file name
529 	if (server)
530 		filetransfer->realfilename = strdup(va("%s" PATHSEP "%s",
531 												luafiledir, filename));
532 	else
533 		filetransfer->realfilename = strdup(va("%s" PATHSEP "client" PATHSEP "$$$%d%d.tmp",
534 												luafiledir, rand(), rand()));
535 	if (!filetransfer->realfilename)
536 		I_Error("AddLuaFileTransfer: Out of memory\n");
537 
538 	strlcpy(filetransfer->mode, mode, sizeof(filetransfer->mode));
539 
540 	// Only if there is no transfer already going on
541 	if (server && filetransfer == luafiletransfers)
542 		SV_PrepareSendLuaFile();
543 	else
544 		filetransfer->ongoing = false;
545 
546 	// Store the callback so it can be called once everyone has the file
547 	filetransfer->id = id;
548 	StoreLuaFileCallback(id);
549 	id++;
550 
551 	if (waitingforluafiletransfer)
552 	{
553 		waitingforluafiletransfer = false;
554 		CL_PrepareDownloadLuaFile();
555 	}
556 }
557 
SV_PrepareSendLuaFileToNextNode(void)558 static void SV_PrepareSendLuaFileToNextNode(void)
559 {
560 	INT32 i;
561 	UINT8 success = 1;
562 
563     // Find a client to send the file to
564 	for (i = 1; i < MAXNETNODES; i++)
565 		if (luafiletransfers->nodestatus[i] == LFTNS_WAITING) // Node waiting
566 		{
567 			// Tell the client we're about to send them the file
568 			netbuffer->packettype = PT_SENDINGLUAFILE;
569 			if (!HSendPacket(i, true, 0, 0))
570 				I_Error("Failed to send a PT_SENDINGLUAFILE packet\n"); // !!! Todo: Handle failure a bit better lol
571 
572 			luafiletransfers->nodestatus[i] = LFTNS_ASKED;
573 			luafiletransfers->nodetimeouts[i] = I_GetTime() + 30 * TICRATE;
574 
575 			return;
576 		}
577 
578 	// No client found, everyone has the file
579 	// Send a net command with 1 as its first byte to indicate the file could be opened
580 	SendNetXCmd(XD_LUAFILE, &success, 1);
581 }
582 
SV_PrepareSendLuaFile(void)583 void SV_PrepareSendLuaFile(void)
584 {
585 	char *binfilename;
586 	INT32 i;
587 
588 	luafiletransfers->ongoing = true;
589 
590 	// Set status to "waiting" for everyone
591 	for (i = 0; i < MAXNETNODES; i++)
592 		luafiletransfers->nodestatus[i] = (nodeingame[i] ? LFTNS_WAITING : LFTNS_NONE);
593 
594 	if (FIL_ReadFileOK(luafiletransfers->realfilename))
595 	{
596 		// If opening in text mode, convert all newlines to LF
597 		if (!strchr(luafiletransfers->mode, 'b'))
598 		{
599 			binfilename = strdup(va("%s" PATHSEP "$$$%d%d.tmp",
600 				luafiledir, rand(), rand()));
601 			if (!binfilename)
602 				I_Error("SV_PrepareSendLuaFile: Out of memory\n");
603 
604 			if (!FIL_ConvertTextFileToBinary(luafiletransfers->realfilename, binfilename))
605 				I_Error("SV_PrepareSendLuaFile: Failed to convert file newlines\n");
606 
607 			// Use the temporary file instead
608 			free(luafiletransfers->realfilename);
609 			luafiletransfers->realfilename = binfilename;
610 		}
611 
612 		SV_PrepareSendLuaFileToNextNode();
613 	}
614 	else
615 	{
616 		// Send a net command with 0 as its first byte to indicate the file couldn't be opened
617 		UINT8 success = 0;
618 		SendNetXCmd(XD_LUAFILE, &success, 1);
619 	}
620 }
621 
SV_HandleLuaFileSent(UINT8 node)622 void SV_HandleLuaFileSent(UINT8 node)
623 {
624 	luafiletransfers->nodestatus[node] = LFTNS_SENT;
625 	SV_PrepareSendLuaFileToNextNode();
626 }
627 
RemoveLuaFileTransfer(void)628 void RemoveLuaFileTransfer(void)
629 {
630 	luafiletransfer_t *filetransfer = luafiletransfers;
631 
632 	// If it was a temporary file, delete it
633 	if (server && !strchr(filetransfer->mode, 'b'))
634 		remove(filetransfer->realfilename);
635 
636 	RemoveLuaFileCallback(filetransfer->id);
637 
638 	luafiletransfers = filetransfer->next;
639 
640 	free(filetransfer->filename);
641 	free(filetransfer->realfilename);
642 	free(filetransfer);
643 }
644 
RemoveAllLuaFileTransfers(void)645 void RemoveAllLuaFileTransfers(void)
646 {
647 	while (luafiletransfers)
648 		RemoveLuaFileTransfer();
649 }
650 
SV_AbortLuaFileTransfer(INT32 node)651 void SV_AbortLuaFileTransfer(INT32 node)
652 {
653 	if (luafiletransfers)
654 	{
655 		if (luafiletransfers->nodestatus[node] == LFTNS_ASKED
656 			|| luafiletransfers->nodestatus[node] == LFTNS_SENDING)
657 		{
658 			SV_PrepareSendLuaFileToNextNode();
659 		}
660 		luafiletransfers->nodestatus[node] = LFTNS_NONE;
661 	}
662 }
663 
CL_PrepareDownloadLuaFile(void)664 void CL_PrepareDownloadLuaFile(void)
665 {
666 	// If there is no transfer in the list, this normally means the server
667 	// called io.open before us, so we have to wait until we call it too
668 	if (!luafiletransfers)
669 	{
670 		waitingforluafiletransfer = true;
671 		return;
672 	}
673 
674 	if (luafiletransfers->ongoing)
675 	{
676 		waitingforluafilecommand = true;
677 		return;
678 	}
679 
680 	// Tell the server we are ready to receive the file
681 	netbuffer->packettype = PT_ASKLUAFILE;
682 	HSendPacket(servernode, true, 0, 0);
683 
684 	fileneedednum = 1;
685 	fileneeded[0].status = FS_REQUESTED;
686 	fileneeded[0].justdownloaded = false;
687 	fileneeded[0].totalsize = UINT32_MAX;
688 	fileneeded[0].file = NULL;
689 	memset(fileneeded[0].md5sum, 0, 16);
690 	strcpy(fileneeded[0].filename, luafiletransfers->realfilename);
691 
692 	// Make sure all directories in the file path exist
693 	MakePathDirs(fileneeded[0].filename);
694 
695 	luafiletransfers->ongoing = true;
696 }
697 
698 // Number of files to send
699 // Little optimization to quickly test if there is a file in the queue
700 static INT32 filestosend = 0;
701 
702 /** Adds a file to the file list for a node
703   *
704   * \param node The node to send the file to
705   * \param filename The file to send
706   * \param fileid The index of the file in the list of added files
707   * \sa AddRamToSendQueue
708   * \sa AddLuaFileToSendQueue
709   *
710   */
AddFileToSendQueue(INT32 node,const char * filename,UINT8 fileid)711 static boolean AddFileToSendQueue(INT32 node, const char *filename, UINT8 fileid)
712 {
713 	filetx_t **q; // A pointer to the "next" field of the last file in the list
714 	filetx_t *p; // The new file request
715 	INT32 i;
716 	char wadfilename[MAX_WADPATH];
717 
718 	if (cv_noticedownload.value)
719 		CONS_Printf("Sending file \"%s\" to node %d (%s)\n", filename, node, I_GetNodeAddress(node));
720 
721 	// Find the last file in the list and set a pointer to its "next" field
722 	q = &transfer[node].txlist;
723 	while (*q)
724 		q = &((*q)->next);
725 
726 	// Allocate a file request and append it to the file list
727 	p = *q = (filetx_t *)malloc(sizeof (filetx_t));
728 	if (!p)
729 		I_Error("AddFileToSendQueue: No more memory\n");
730 
731 	// Initialise with zeros
732 	memset(p, 0, sizeof (filetx_t));
733 
734 	// Allocate the file name
735 	p->id.filename = (char *)malloc(MAX_WADPATH);
736 	if (!p->id.filename)
737 		I_Error("AddFileToSendQueue: No more memory\n");
738 
739 	// Set the file name and get rid of the path
740 	strlcpy(p->id.filename, filename, MAX_WADPATH);
741 	nameonly(p->id.filename);
742 
743 	// Look for the requested file through all loaded files
744 	for (i = 0; wadfiles[i]; i++)
745 	{
746 		strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
747 		nameonly(wadfilename);
748 		if (!stricmp(wadfilename, p->id.filename))
749 		{
750 			// Copy file name with full path
751 			strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
752 			break;
753 		}
754 	}
755 
756 	// Handle non-loaded file requests
757 	if (!wadfiles[i])
758 	{
759 		DEBFILE(va("%s not found in wadfiles\n", filename));
760 		// This formerly checked if (!findfile(p->id.filename, NULL, true))
761 
762 		// Not found
763 		// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
764 		DEBFILE(va("Client %d request %s: not found\n", node, filename));
765 		free(p->id.filename);
766 		free(p);
767 		*q = NULL;
768 		return false; // cancel the rest of the requests
769 	}
770 
771 	// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
772 	if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
773 	{
774 		// Too big
775 		// Don't inform client (client sucks, man)
776 		DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
777 		free(p->id.filename);
778 		free(p);
779 		*q = NULL;
780 		return false; // cancel the rest of the requests
781 	}
782 
783 	DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
784 	p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
785 	p->fileid = fileid;
786 	p->next = NULL; // End of list
787 	filestosend++;
788 	return true;
789 }
790 
791 /** Adds a memory block to the file list for a node
792   *
793   * \param node The node to send the memory block to
794   * \param data The memory block to send
795   * \param size The size of the block in bytes
796   * \param freemethod How to free the block after it has been sent
797   * \param fileid The index of the file in the list of added files
798   * \sa AddFileToSendQueue
799   * \sa AddLuaFileToSendQueue
800   *
801   */
AddRamToSendQueue(INT32 node,void * data,size_t size,freemethod_t freemethod,UINT8 fileid)802 void AddRamToSendQueue(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
803 {
804 	filetx_t **q; // A pointer to the "next" field of the last file in the list
805 	filetx_t *p; // The new file request
806 
807 	// Find the last file in the list and set a pointer to its "next" field
808 	q = &transfer[node].txlist;
809 	while (*q)
810 		q = &((*q)->next);
811 
812 	// Allocate a file request and append it to the file list
813 	p = *q = (filetx_t *)malloc(sizeof (filetx_t));
814 	if (!p)
815 		I_Error("AddRamToSendQueue: No more memory\n");
816 
817 	// Initialise with zeros
818 	memset(p, 0, sizeof (filetx_t));
819 
820 	p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
821 	p->id.ram = data;
822 	p->size = (UINT32)size;
823 	p->fileid = fileid;
824 	p->next = NULL; // End of list
825 
826 	DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
827 
828 	filestosend++;
829 }
830 
831 /** Adds a file requested by Lua to the file list for a node
832   *
833   * \param node The node to send the file to
834   * \param filename The file to send
835   * \sa AddFileToSendQueue
836   * \sa AddRamToSendQueue
837   *
838   */
AddLuaFileToSendQueue(INT32 node,const char * filename)839 boolean AddLuaFileToSendQueue(INT32 node, const char *filename)
840 {
841 	filetx_t **q; // A pointer to the "next" field of the last file in the list
842 	filetx_t *p; // The new file request
843 	//INT32 i;
844 	//char wadfilename[MAX_WADPATH];
845 
846 	luafiletransfers->nodestatus[node] = LFTNS_SENDING;
847 
848 	// Find the last file in the list and set a pointer to its "next" field
849 	q = &transfer[node].txlist;
850 	while (*q)
851 		q = &((*q)->next);
852 
853 	// Allocate a file request and append it to the file list
854 	p = *q = (filetx_t *)malloc(sizeof (filetx_t));
855 	if (!p)
856 		I_Error("AddLuaFileToSendQueue: No more memory\n");
857 
858 	// Initialise with zeros
859 	memset(p, 0, sizeof (filetx_t));
860 
861 	// Allocate the file name
862 	p->id.filename = (char *)malloc(MAX_WADPATH); // !!!
863 	if (!p->id.filename)
864 		I_Error("AddLuaFileToSendQueue: No more memory\n");
865 
866 	// Set the file name and get rid of the path
867 	strlcpy(p->id.filename, filename, MAX_WADPATH); // !!!
868 	//nameonly(p->id.filename);
869 
870 	DEBFILE(va("Sending Lua file %s to %d\n", filename, node));
871 	p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
872 	p->next = NULL; // End of list
873 	filestosend++;
874 	return true;
875 }
876 
877 /** Stops sending a file for a node, and removes the file request from the list,
878   * either because the file has been fully sent or because the node was disconnected
879   *
880   * \param node The destination
881   *
882   */
SV_EndFileSend(INT32 node)883 static void SV_EndFileSend(INT32 node)
884 {
885 	filetx_t *p = transfer[node].txlist;
886 
887 	// Free the file request according to the freemethod
888 	// parameter used with AddFileToSendQueue/AddRamToSendQueue
889 	switch (p->ram)
890 	{
891 		case SF_FILE: // It's a file, close it and free its filename
892 			if (cv_noticedownload.value)
893 				CONS_Printf("Ending file transfer for node %d\n", node);
894 			if (transfer[node].currentfile)
895 				fclose(transfer[node].currentfile);
896 			free(p->id.filename);
897 			break;
898 		case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
899 			Z_Free(p->id.ram);
900 			break;
901 		case SF_RAM: // It's a memory block allocated with malloc, use free
902 			free(p->id.ram);
903 		case SF_NOFREERAM: // Nothing to free
904 			break;
905 	}
906 
907 	// Remove the file request from the list
908 	transfer[node].txlist = p->next;
909 	free(p);
910 
911 	// Indicate that the transmission is over
912 	transfer[node].currentfile = NULL;
913 	if (transfer[node].ackedfragments)
914 		free(transfer[node].ackedfragments);
915 	transfer[node].ackedfragments = NULL;
916 
917 	filestosend--;
918 }
919 
920 #define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)
921 #define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE))
922 
923 /** Handles file transmission
924   *
925   */
FileSendTicker(void)926 void FileSendTicker(void)
927 {
928 	static INT32 currentnode = 0;
929 	filetx_pak *p;
930 	size_t fragmentsize;
931 	filetx_t *f;
932 	INT32 packetsent, ram, i, j;
933 
934 	// If someone is taking too long to download, kick them with a timeout
935 	// to prevent blocking the rest of the server...
936 	if (luafiletransfers)
937 	{
938 		for (i = 1; i < MAXNETNODES; i++)
939 		{
940 			luafiletransfernodestatus_t status = luafiletransfers->nodestatus[i];
941 
942 			if (status != LFTNS_NONE && status != LFTNS_WAITING && status != LFTNS_SENT
943 				&& I_GetTime() > luafiletransfers->nodetimeouts[i])
944 			{
945 				Net_ConnectionTimeout(i);
946 			}
947 		}
948 	}
949 
950 	if (!filestosend) // No file to send
951 		return;
952 
953 	if (cv_downloadspeed.value) // New behavior
954 		packetsent = cv_downloadspeed.value;
955 	else // Old behavior
956 	{
957 		packetsent = PACKETPERTIC;
958 		if (!packetsent)
959 			packetsent = 1;
960 	}
961 
962 	netbuffer->packettype = PT_FILEFRAGMENT;
963 
964 	// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
965 	while (packetsent-- && filestosend != 0)
966 	{
967 		for (i = currentnode, j = 0; j < MAXNETNODES;
968 			i = (i+1) % MAXNETNODES, j++)
969 		{
970 			if (transfer[i].txlist)
971 				break;
972 		}
973 		// no transfer to do
974 		if (j >= MAXNETNODES)
975 			I_Error("filestosend=%d but no file to send found\n", filestosend);
976 
977 		currentnode = (i+1) % MAXNETNODES;
978 		f = transfer[i].txlist;
979 		ram = f->ram;
980 
981 		// Open the file if it isn't open yet, or
982 		if (!transfer[i].currentfile)
983 		{
984 			if (!ram) // Sending a file
985 			{
986 				long filesize;
987 
988 				transfer[i].currentfile =
989 					fopen(f->id.filename, "rb");
990 
991 				if (!transfer[i].currentfile)
992 					I_Error("File %s does not exist",
993 						f->id.filename);
994 
995 				fseek(transfer[i].currentfile, 0, SEEK_END);
996 				filesize = ftell(transfer[i].currentfile);
997 
998 				// Nobody wants to transfer a file bigger
999 				// than 4GB!
1000 				if (filesize >= LONG_MAX)
1001 					I_Error("filesize of %s is too large", f->id.filename);
1002 				if (filesize == -1)
1003 					I_Error("Error getting filesize of %s", f->id.filename);
1004 
1005 				f->size = (UINT32)filesize;
1006 				fseek(transfer[i].currentfile, 0, SEEK_SET);
1007 			}
1008 			else // Sending RAM
1009 				transfer[i].currentfile = (FILE *)1; // Set currentfile to a non-null value to indicate that it is open
1010 
1011 			transfer[i].iteration = 1;
1012 			transfer[i].ackediteration = 0;
1013 			transfer[i].position = 0;
1014 			transfer[i].ackedsize = 0;
1015 
1016 			transfer[i].ackedfragments = calloc(f->size / FILEFRAGMENTSIZE + 1, sizeof(*transfer[i].ackedfragments));
1017 			if (!transfer[i].ackedfragments)
1018 				I_Error("FileSendTicker: No more memory\n");
1019 
1020 			transfer[i].dontsenduntil = 0;
1021 		}
1022 
1023 		// If the client hasn't acknowledged any fragment from the previous iteration,
1024 		// it is most likely because their acks haven't had enough time to reach the server
1025 		// yet, due to latency. In that case, we wait a little to avoid useless resend.
1026 		if (I_GetTime() < transfer[i].dontsenduntil)
1027 			continue;
1028 
1029 		// Find the first non-acknowledged fragment
1030 		while (transfer[i].ackedfragments[transfer[i].position / FILEFRAGMENTSIZE])
1031 		{
1032 			transfer[i].position += FILEFRAGMENTSIZE;
1033 			if (transfer[i].position >= f->size)
1034 			{
1035 				if (transfer[i].ackediteration < transfer[i].iteration)
1036 					transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2;
1037 
1038 				transfer[i].position = 0;
1039 				transfer[i].iteration++;
1040 			}
1041 		}
1042 
1043 		// Build a packet containing a file fragment
1044 		p = &netbuffer->u.filetxpak;
1045 		fragmentsize = FILEFRAGMENTSIZE;
1046 		if (f->size-transfer[i].position < fragmentsize)
1047 			fragmentsize = f->size-transfer[i].position;
1048 		if (ram)
1049 			M_Memcpy(p->data, &f->id.ram[transfer[i].position], fragmentsize);
1050 		else
1051 		{
1052 			fseek(transfer[i].currentfile, transfer[i].position, SEEK_SET);
1053 
1054 			if (fread(p->data, 1, fragmentsize, transfer[i].currentfile) != fragmentsize)
1055 				I_Error("FileSendTicker: can't read %s byte on %s at %d because %s", sizeu1(fragmentsize), f->id.filename, transfer[i].position, M_FileError(transfer[i].currentfile));
1056 		}
1057 		p->iteration = transfer[i].iteration;
1058 		p->position = LONG(transfer[i].position);
1059 		p->fileid = f->fileid;
1060 		p->filesize = LONG(f->size);
1061 		p->size = SHORT((UINT16)FILEFRAGMENTSIZE);
1062 
1063 		// Send the packet
1064 		if (HSendPacket(i, false, 0, FILETXHEADER + fragmentsize)) // Don't use the default acknowledgement system
1065 		{ // Success
1066 			transfer[i].position = (UINT32)(transfer[i].position + fragmentsize);
1067 			if (transfer[i].position >= f->size)
1068 			{
1069 				if (transfer[i].ackediteration < transfer[i].iteration)
1070 					transfer[i].dontsenduntil = I_GetTime() + TICRATE / 2;
1071 
1072 				transfer[i].position = 0;
1073 				transfer[i].iteration++;
1074 			}
1075 		}
1076 		else
1077 		{ // Not sent for some odd reason, retry at next call
1078 			// Exit the while (can't send this one so why should i send the next?)
1079 			break;
1080 		}
1081 	}
1082 }
1083 
PT_FileAck(void)1084 void PT_FileAck(void)
1085 {
1086 	fileack_pak *packet = &netbuffer->u.fileack;
1087 	INT32 node = doomcom->remotenode;
1088 	filetran_t *trans = &transfer[node];
1089 	INT32 i, j;
1090 
1091 	// Wrong file id? Ignore it, it's probably a late packet
1092 	if (!(trans->txlist && packet->fileid == trans->txlist->fileid))
1093 		return;
1094 
1095 	if (packet->numsegments * sizeof(*packet->segments) != doomcom->datalength - BASEPACKETSIZE - sizeof(*packet))
1096 	{
1097 		Net_CloseConnection(node);
1098 		return;
1099 	}
1100 
1101 	if (packet->iteration > trans->ackediteration)
1102 	{
1103 		trans->ackediteration = packet->iteration;
1104 		if (trans->ackediteration >= trans->iteration - 1)
1105 			trans->dontsenduntil = 0;
1106 	}
1107 
1108 	for (i = 0; i < packet->numsegments; i++)
1109 	{
1110 		fileacksegment_t *segment = &packet->segments[i];
1111 
1112 		for (j = 0; j < 32; j++)
1113 			if (LONG(segment->acks) & (1 << j))
1114 			{
1115 				if (LONG(segment->start) * FILEFRAGMENTSIZE >= trans->txlist->size)
1116 				{
1117 					Net_CloseConnection(node);
1118 					return;
1119 				}
1120 
1121 				if (!trans->ackedfragments[LONG(segment->start) + j])
1122 				{
1123 					trans->ackedfragments[LONG(segment->start) + j] = true;
1124 					trans->ackedsize += FILEFRAGMENTSIZE;
1125 
1126 					// If the last missing fragment was acked, finish!
1127 					if (trans->ackedsize == trans->txlist->size)
1128 					{
1129 						SV_EndFileSend(node);
1130 						return;
1131 					}
1132 				}
1133 			}
1134 	}
1135 }
1136 
PT_FileReceived(void)1137 void PT_FileReceived(void)
1138 {
1139 	filetx_t *trans = transfer[doomcom->remotenode].txlist;
1140 
1141 	if (trans && netbuffer->u.filereceived == trans->fileid)
1142 		SV_EndFileSend(doomcom->remotenode);
1143 }
1144 
SendAckPacket(fileack_pak * packet,UINT8 fileid)1145 static void SendAckPacket(fileack_pak *packet, UINT8 fileid)
1146 {
1147 	size_t packetsize;
1148 	INT32 i;
1149 
1150 	packetsize = sizeof(*packet) + packet->numsegments * sizeof(*packet->segments);
1151 
1152 	// Finalise the packet
1153 	packet->fileid = fileid;
1154 	for (i = 0; i < packet->numsegments; i++)
1155 	{
1156 		packet->segments[i].start = LONG(packet->segments[i].start);
1157 		packet->segments[i].acks = LONG(packet->segments[i].acks);
1158 	}
1159 
1160 	// Send the packet
1161 	netbuffer->packettype = PT_FILEACK;
1162 	M_Memcpy(&netbuffer->u.fileack, packet, packetsize);
1163 	HSendPacket(servernode, false, 0, packetsize);
1164 
1165 	// Clear the packet
1166 	memset(packet, 0, sizeof(*packet) + 512);
1167 }
1168 
AddFragmentToAckPacket(fileack_pak * packet,UINT8 iteration,UINT32 fragmentpos,UINT8 fileid)1169 static void AddFragmentToAckPacket(fileack_pak *packet, UINT8 iteration, UINT32 fragmentpos, UINT8 fileid)
1170 {
1171 	fileacksegment_t *segment = &packet->segments[packet->numsegments - 1];
1172 
1173 	packet->iteration = max(packet->iteration, iteration);
1174 
1175     if (packet->numsegments == 0
1176 		|| fragmentpos < segment->start
1177 		|| fragmentpos - segment->start >= 32)
1178 	{
1179 		// If the packet becomes too big, send it
1180 		if ((packet->numsegments + 1) * sizeof(*segment) > 512)
1181 			SendAckPacket(packet, fileid);
1182 
1183 		packet->numsegments++;
1184 		segment = &packet->segments[packet->numsegments - 1];
1185 		segment->start = fragmentpos;
1186 	}
1187 
1188 	// Set the bit that represents the fragment
1189 	segment->acks |= 1 << (fragmentpos - segment->start);
1190 }
1191 
FileReceiveTicker(void)1192 void FileReceiveTicker(void)
1193 {
1194 	INT32 i;
1195 
1196 	for (i = 0; i < fileneedednum; i++)
1197 	{
1198 		fileneeded_t *file = &fileneeded[i];
1199 
1200 		if (file->status == FS_DOWNLOADING)
1201 		{
1202 			if (lasttimeackpacketsent - I_GetTime() > TICRATE / 2)
1203 				SendAckPacket(file->ackpacket, i);
1204 
1205 			// When resuming a tranfer, start with telling
1206 			// the server what parts we already received
1207 			if (file->ackresendposition != UINT32_MAX && file->status == FS_DOWNLOADING)
1208 			{
1209 				// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
1210 				INT32 j;
1211 				for (j = 0; j < 2048; j++)
1212 				{
1213 					if (file->receivedfragments[file->ackresendposition])
1214 						AddFragmentToAckPacket(file->ackpacket, file->iteration, file->ackresendposition, i);
1215 
1216 					file->ackresendposition++;
1217 					if (file->ackresendposition * file->fragmentsize >= file->totalsize)
1218 					{
1219 						file->ackresendposition = UINT32_MAX;
1220 						break;
1221 					}
1222 				}
1223 			}
1224 		}
1225 	}
1226 }
1227 
PT_FileFragment(void)1228 void PT_FileFragment(void)
1229 {
1230 	INT32 filenum = netbuffer->u.filetxpak.fileid;
1231 	fileneeded_t *file = &fileneeded[filenum];
1232 	UINT32 fragmentpos = LONG(netbuffer->u.filetxpak.position);
1233 	UINT16 fragmentsize = SHORT(netbuffer->u.filetxpak.size);
1234 	UINT16 boundedfragmentsize = doomcom->datalength - BASEPACKETSIZE - sizeof(netbuffer->u.filetxpak);
1235 	char *filename;
1236 
1237 	filename = va("%s", file->filename);
1238 	nameonly(filename);
1239 
1240 	if (!(strcmp(filename, "srb2.pk3")
1241 		&& strcmp(filename, "zones.pk3")
1242 		&& strcmp(filename, "player.dta")
1243 		&& strcmp(filename, "patch.pk3")
1244 		&& strcmp(filename, "music.dta")
1245 		))
1246 		I_Error("Tried to download \"%s\"", filename);
1247 
1248 	filename = file->filename;
1249 
1250 	if (filenum >= fileneedednum)
1251 	{
1252 		DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));
1253 		//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
1254 		return;
1255 	}
1256 
1257 	if (file->status == FS_REQUESTED)
1258 	{
1259 		if (file->file)
1260 			I_Error("PT_FileFragment: already open file\n");
1261 
1262 		file->status = FS_DOWNLOADING;
1263 		file->fragmentsize = fragmentsize;
1264 		file->iteration = 0;
1265 
1266 		file->ackpacket = calloc(1, sizeof(*file->ackpacket) + 512);
1267 		if (!file->ackpacket)
1268 			I_Error("FileSendTicker: No more memory\n");
1269 
1270 		if (CL_CanResumeDownload(file))
1271 		{
1272 			file->file = fopen(filename, "r+b");
1273 			if (!file->file)
1274 				I_Error("Can't reopen file %s: %s", filename, strerror(errno));
1275 			CONS_Printf("\r%s...\n", filename);
1276 
1277 			CONS_Printf("Resuming download...\n");
1278 			file->currentsize = pauseddownload->currentsize;
1279 			file->receivedfragments = pauseddownload->receivedfragments;
1280 			file->ackresendposition = 0;
1281 
1282 			free(pauseddownload);
1283 			pauseddownload = NULL;
1284 		}
1285 		else
1286 		{
1287 			CL_AbortDownloadResume();
1288 
1289 			file->file = fopen(filename, "wb");
1290 			if (!file->file)
1291 				I_Error("Can't create file %s: %s", filename, strerror(errno));
1292 
1293 			CONS_Printf("\r%s...\n",filename);
1294 
1295 			file->currentsize = 0;
1296 			file->totalsize = LONG(netbuffer->u.filetxpak.filesize);
1297 			file->ackresendposition = UINT32_MAX; // Only used for resumed downloads
1298 
1299 			file->receivedfragments = calloc(file->totalsize / fragmentsize + 1, sizeof(*file->receivedfragments));
1300 			if (!file->receivedfragments)
1301 				I_Error("FileSendTicker: No more memory\n");
1302 		}
1303 
1304 		lasttimeackpacketsent = I_GetTime();
1305 	}
1306 
1307 	if (file->status == FS_DOWNLOADING)
1308 	{
1309 		if (fragmentpos >= file->totalsize)
1310 			I_Error("Invalid file fragment\n");
1311 
1312 		file->iteration = max(file->iteration, netbuffer->u.filetxpak.iteration);
1313 
1314 		if (!file->receivedfragments[fragmentpos / fragmentsize]) // Not received yet
1315 		{
1316 			file->receivedfragments[fragmentpos / fragmentsize] = true;
1317 
1318 			// We can receive packets in the wrong order, anyway all OSes support gaped files
1319 			fseek(file->file, fragmentpos, SEEK_SET);
1320 			if (fragmentsize && fwrite(netbuffer->u.filetxpak.data, boundedfragmentsize, 1, file->file) != 1)
1321 				I_Error("Can't write to %s: %s\n",filename, M_FileError(file->file));
1322 			file->currentsize += boundedfragmentsize;
1323 
1324 			AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum);
1325 
1326 			// Finished?
1327 			if (file->currentsize == file->totalsize)
1328 			{
1329 				fclose(file->file);
1330 				file->file = NULL;
1331 				free(file->receivedfragments);
1332 				free(file->ackpacket);
1333 				file->status = FS_FOUND;
1334 				file->justdownloaded = true;
1335 				CONS_Printf(M_GetText("Downloading %s...(done)\n"),
1336 					filename);
1337 
1338 				// Tell the server we have received the file
1339 				netbuffer->packettype = PT_FILERECEIVED;
1340 				netbuffer->u.filereceived = filenum;
1341 				HSendPacket(servernode, true, 0, 1);
1342 
1343 				if (luafiletransfers)
1344 				{
1345 					// Tell the server we have received the file
1346 					netbuffer->packettype = PT_HASLUAFILE;
1347 					HSendPacket(servernode, true, 0, 0);
1348 				}
1349 			}
1350 		}
1351 		else // Already received
1352 		{
1353 			// If they are sending us the fragment again, it's probably because
1354 			// they missed our previous ack, so we must re-acknowledge it
1355 			AddFragmentToAckPacket(file->ackpacket, file->iteration, fragmentpos / fragmentsize, filenum);
1356 		}
1357 	}
1358 	else if (!file->justdownloaded)
1359 	{
1360 		const char *s;
1361 		switch(file->status)
1362 		{
1363 		case FS_NOTFOUND:
1364 			s = "FS_NOTFOUND";
1365 			break;
1366 		case FS_FOUND:
1367 			s = "FS_FOUND";
1368 			break;
1369 		case FS_OPEN:
1370 			s = "FS_OPEN";
1371 			break;
1372 		case FS_MD5SUMBAD:
1373 			s = "FS_MD5SUMBAD";
1374 			break;
1375 		default:
1376 			s = "unknown";
1377 			break;
1378 		}
1379 		I_Error("Received a file not requested (file id: %d, file status: %s)\n", filenum, s);
1380 	}
1381 
1382 #ifndef NONET
1383 	lastfilenum = filenum;
1384 #endif
1385 }
1386 
1387 /** \brief Checks if a node is downloading a file
1388  *
1389  * \param node The node to check for
1390  * \return True if the node is downloading a file
1391  *
1392  */
SendingFile(INT32 node)1393 boolean SendingFile(INT32 node)
1394 {
1395 	return transfer[node].txlist != NULL;
1396 }
1397 
1398 /** Cancels all file requests for a node
1399   *
1400   * \param node The destination
1401   * \sa SV_EndFileSend
1402   *
1403   */
SV_AbortSendFiles(INT32 node)1404 void SV_AbortSendFiles(INT32 node)
1405 {
1406 	while (transfer[node].txlist)
1407 		SV_EndFileSend(node);
1408 }
1409 
CloseNetFile(void)1410 void CloseNetFile(void)
1411 {
1412 	INT32 i;
1413 	// Is sending?
1414 	for (i = 0; i < MAXNETNODES; i++)
1415 		SV_AbortSendFiles(i);
1416 
1417 	// Receiving a file?
1418 	for (i = 0; i < MAX_WADFILES; i++)
1419 		if (fileneeded[i].status == FS_DOWNLOADING && fileneeded[i].file)
1420 		{
1421 			fclose(fileneeded[i].file);
1422 			free(fileneeded[i].ackpacket);
1423 
1424 			if (!pauseddownload && i != 0) // 0 is either srb2.srb or the gamestate...
1425 			{
1426 				// Don't remove the file, save it for later in case we resume the download
1427 				pauseddownload = malloc(sizeof(*pauseddownload));
1428 				if (!pauseddownload)
1429 					I_Error("CloseNetFile: No more memory\n");
1430 
1431 				strcpy(pauseddownload->filename, fileneeded[i].filename);
1432 				memcpy(pauseddownload->md5sum, fileneeded[i].md5sum, 16);
1433 				pauseddownload->currentsize = fileneeded[i].currentsize;
1434 				pauseddownload->receivedfragments = fileneeded[i].receivedfragments;
1435 				pauseddownload->fragmentsize = fileneeded[i].fragmentsize;
1436 			}
1437 			else
1438 			{
1439 				free(fileneeded[i].receivedfragments);
1440 				// File is not complete delete it
1441 				remove(fileneeded[i].filename);
1442 			}
1443 		}
1444 }
1445 
Command_Downloads_f(void)1446 void Command_Downloads_f(void)
1447 {
1448 	INT32 node;
1449 
1450 	for (node = 0; node < MAXNETNODES; node++)
1451 		if (transfer[node].txlist
1452 		&& transfer[node].txlist->ram == SF_FILE) // Node is downloading a file?
1453 		{
1454 			const char *name = transfer[node].txlist->id.filename;
1455 			UINT32 position = transfer[node].ackedsize;
1456 			UINT32 size = transfer[node].txlist->size;
1457 			char ratecolor;
1458 
1459 			// Avoid division by zero errors
1460 			if (!size)
1461 				size = 1;
1462 
1463 			name = &name[strlen(name) - nameonlylength(name)];
1464 			switch (4 * (position - 1) / size)
1465 			{
1466 				case 0: ratecolor = '\x85'; break;
1467 				case 1: ratecolor = '\x87'; break;
1468 				case 2: ratecolor = '\x82'; break;
1469 				case 3: ratecolor = '\x83'; break;
1470 				default: ratecolor = '\x80';
1471 			}
1472 
1473 			CONS_Printf("%2d  %c%s  ", node, ratecolor, name); // Node and file name
1474 			CONS_Printf("\x80%uK\x84/\x80%uK ", position / 1024, size / 1024); // Progress in kB
1475 			CONS_Printf("\x80(%c%u%%\x80)  ", ratecolor, (UINT32)(100.0 * position / size)); // Progress in %
1476 			CONS_Printf("%s\n", I_GetNodeAddress(node)); // Address and newline
1477 		}
1478 }
1479 
1480 // Functions cut and pasted from Doomatic :)
1481 
nameonly(char * s)1482 void nameonly(char *s)
1483 {
1484 	size_t j, len;
1485 	void *ns;
1486 
1487 	for (j = strlen(s); j != (size_t)-1; j--)
1488 		if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
1489 		{
1490 			ns = &(s[j+1]);
1491 			len = strlen(ns);
1492 #if 0
1493 			M_Memcpy(s, ns, len+1);
1494 #else
1495 			memmove(s, ns, len+1);
1496 #endif
1497 			return;
1498 		}
1499 }
1500 
1501 // Returns the length in characters of the last element of a path.
nameonlylength(const char * s)1502 size_t nameonlylength(const char *s)
1503 {
1504 	size_t j, len = strlen(s);
1505 
1506 	for (j = len; j != (size_t)-1; j--)
1507 		if ((s[j] == '\\') || (s[j] == ':') || (s[j] == '/'))
1508 			return len - j - 1;
1509 
1510 	return len;
1511 }
1512 
1513 #ifndef O_BINARY
1514 #define O_BINARY 0
1515 #endif
1516 
checkfilemd5(char * filename,const UINT8 * wantedmd5sum)1517 filestatus_t checkfilemd5(char *filename, const UINT8 *wantedmd5sum)
1518 {
1519 #if defined (NOMD5)
1520 	(void)wantedmd5sum;
1521 	(void)filename;
1522 #else
1523 	FILE *fhandle;
1524 	UINT8 md5sum[16];
1525 
1526 	if (!wantedmd5sum)
1527 		return FS_FOUND;
1528 
1529 	fhandle = fopen(filename, "rb");
1530 	if (fhandle)
1531 	{
1532 		md5_stream(fhandle,md5sum);
1533 		fclose(fhandle);
1534 		if (!memcmp(wantedmd5sum, md5sum, 16))
1535 			return FS_FOUND;
1536 		return FS_MD5SUMBAD;
1537 	}
1538 
1539 	I_Error("Couldn't open %s for md5 check", filename);
1540 #endif
1541 	return FS_FOUND; // will never happen, but makes the compiler shut up
1542 }
1543 
1544 // Rewritten by Monster Iestyn to be less stupid
1545 // Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
1546 // (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
findfile(char * filename,const UINT8 * wantedmd5sum,boolean completepath)1547 filestatus_t findfile(char *filename, const UINT8 *wantedmd5sum, boolean completepath)
1548 {
1549 	filestatus_t homecheck; // store result of last file search
1550 	boolean badmd5 = false; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
1551 
1552 	// first, check SRB2's "home" directory
1553 	homecheck = filesearch(filename, srb2home, wantedmd5sum, completepath, 10);
1554 
1555 	if (homecheck == FS_FOUND) // we found the file, so return that we have :)
1556 		return FS_FOUND;
1557 	else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
1558 		badmd5 = true;
1559 	// if not found at all, just move on without doing anything
1560 
1561 	// next, check SRB2's "path" directory
1562 	homecheck = filesearch(filename, srb2path, wantedmd5sum, completepath, 10);
1563 
1564 	if (homecheck == FS_FOUND) // we found the file, so return that we have :)
1565 		return FS_FOUND;
1566 	else if (homecheck == FS_MD5SUMBAD) // file has a bad md5; move on and look for a file with the right md5
1567 		badmd5 = true;
1568 	// if not found at all, just move on without doing anything
1569 
1570 	// finally check "." directory
1571 	homecheck = filesearch(filename, ".", wantedmd5sum, completepath, 10);
1572 
1573 	if (homecheck != FS_NOTFOUND) // if not found this time, fall back on the below return statement
1574 		return homecheck; // otherwise return the result we got
1575 
1576 	return (badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND); // md5 sum bad or file not found
1577 }
1578