Newer
Older
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2018 by Sonic Team Junior.
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file d_netfil.c
/// \brief Transfer a file using HSendPacket.
#include <stdio.h>
#ifndef _WIN32_WCE
#ifdef __OS2__
#include <sys/types.h>
#endif // __OS2__
#include <sys/stat.h>
#endif
#if !defined (UNDER_CE)
#include <time.h>
#endif
#if ((defined (_WIN32) && !defined (_WIN32_WCE)) || defined (__DJGPP__)) && !defined (_XBOX)
#include <io.h>
#include <direct.h>
#elif !defined (_WIN32_WCE) && !(defined (_XBOX) && !defined (__GNUC__))
#include <sys/types.h>
#include <dirent.h>
#include <utime.h>
#endif
#ifdef __GNUC__
#include <unistd.h>
#include <limits.h>
#elif defined (_WIN32) && !defined (_WIN32_WCE)
#include <sys/utime.h>
#endif
#ifdef __DJGPP__
#include <dir.h>
#include <utime.h>
#endif
#ifdef HAVE_CURL
#include "curl/curl.h"
#endif
#include "doomdef.h"
#include "doomstat.h"
#include "d_main.h"
#include "g_game.h"
#include "i_net.h"
#include "i_system.h"
#include "m_argv.h"
#include "d_net.h"
#include "w_wad.h"
#include "d_netfil.h"
#include "z_zone.h"
#include "byteptr.h"
#include "p_setup.h"
#include "m_misc.h"
#include "m_menu.h"
#include "md5.h"
#include "filesrch.h"
// Prototypes
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid);
#ifdef HAVE_CURL
size_t curlwrite_data(void *ptr, size_t size, size_t nmemb, FILE *stream);
int curlprogress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);
#endif
union {
char *filename; // Name of the file
char *ram; // Pointer to the data in RAM
} id;
UINT32 size; // Size of the file
INT32 node; // Destination
struct filetx_s *next; // Next file in the list
filetx_t *txlist; // Linked list of all files for the node
UINT32 position; // The current position in the file
boolean init; // false if we want to reset position / open a new file
} filetran_t;
static filetran_t transfer[MAXNETNODES];
// The files currently being sent/received
typedef struct fileused_s
{
FILE *file;
UINT8 count;
} fileused_t;
static fileused_t transferFiles[UINT8_MAX + 1];
// Read time of file: stat _stmtime
// Write time of file: utime
// Receiver structure
INT32 fileneedednum; // Number of files needed to join the server
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
char downloaddir[512] = "DOWNLOAD";
#ifdef CLIENT_LOADINGSCREEN
// for cl loading screen

LJ Sonic
committed
INT32 lastfilenum = -1;
#ifdef HAVE_CURL
static CURL *http_handle;
static CURLM *multi_handle;
boolean curl_running = false;
boolean curl_failedwebdownload = false;
static double curl_dlnow;
static double curl_dltotal;
static time_t curl_starttime;
INT32 curl_transfers = 0;
static int curl_runninghandles = 0;
static UINT32 curl_origfilesize;
static UINT32 curl_origtotalfilesize;
/** Fills a serverinfo packet with information about wad files loaded.
*
* \todo Give this function a better name since it is in global scope.
* Used to have size limiting built in - now handed via W_LoadWadFile in w_wad.c
UINT8 *PutFileNeeded(UINT16 firstfile)
UINT8 *p_start = netbuffer->packettype == PT_MOREFILESNEEDED ? netbuffer->u.filesneededcfg.files : netbuffer->u.serverinfo.fileneeded;
char wadfilename[MAX_WADPATH] = "";
UINT8 filestatus;
for (i = mainwads+1; i < numwadfiles; i++) //mainwads+1, otherwise we start on the first mainwad
// If it has only music/sound lumps, don't put it in the list
if (!wadfiles[i]->important)
continue;
if (firstfile)
{ // Skip files until we reach the first file.
firstfile--;
continue;
}
nameonly(strcpy(wadfilename, wadfiles[i]->filename));
// Look below at the WRITE macros to understand what these numbers mean.
if (p + 1 + 4 + min(strlen(wadfilename) + 1, MAX_WADPATH) + 16 > p_start + MAXFILENEEDED)
// Too many files to send all at once
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.more = 1;
else
netbuffer->u.serverinfo.kartvars |= SV_LOTSOFADDONS;
filestatus = 1; // Importance - not really used any more, holds 1 by default for backwards compat with MS
// Store in the upper four bits
if (!cv_downloading.value)
else if ((wadfiles[i]->filesize <= (UINT32)cv_maxsend.value * 1024))
filestatus += (1 << 4); // Will send if requested
WRITEUINT8(p, filestatus);
count++;
WRITEUINT32(p, wadfiles[i]->filesize);
WRITESTRINGN(p, wadfilename, MAX_WADPATH);
WRITEMEM(p, wadfiles[i]->md5sum, 16);
}
if (netbuffer->packettype == PT_MOREFILESNEEDED)
netbuffer->u.filesneededcfg.num = count;
else
netbuffer->u.serverinfo.fileneedednum = count;
/** Parses the serverinfo packet and fills the fileneeded table on client
*
* \param fileneedednum_parm The number of files (sent in this page) needed to join the server
* \param fileneededstr The memory block containing the list of needed files
* \param firstfile The first file index to read from
void D_ParseFileneeded(INT32 fileneedednum_parm, UINT8 *fileneededstr, UINT16 firstfile)
fileneedednum = firstfile + fileneedednum_parm;
for (i = firstfile; i < fileneedednum; i++)
fileneeded[i].status = FS_NOTCHECKED; // We haven't even started looking for the file yet
filestatus = READUINT8(p); // The first byte is the file status
fileneeded[i].totalsize = READUINT32(p); // The four next bytes are the file size
fileneeded[i].file = NULL; // The file isn't open yet
READSTRINGN(p, fileneeded[i].filename, MAX_WADPATH); // The next bytes are the file name
READMEM(p, fileneeded[i].md5sum, 16); // The last 16 bytes are the file checksum
}
}
void CL_PrepareDownloadSaveGame(const char *tmpsave)
{
fileneedednum = 1;
fileneeded[0].status = FS_REQUESTED;
fileneeded[0].totalsize = UINT32_MAX;
memset(fileneeded[0].md5sum, 0, 16);
strcpy(fileneeded[0].filename, tmpsave);
}
/** Checks the server to see if we CAN download all the files,
* before starting to create them and requesting.
*
* \return True if we can download all the files
*
*/
boolean CL_CheckDownloadable(void)
{
UINT8 i,dlstatus = 0;
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{
if (fileneeded[i].willsend == 1)
continue;
if (fileneeded[i].willsend == 0)
dlstatus = 1;
else //if (fileneeded[i].willsend == 2)
dlstatus = 2;
}
// Downloading locally disabled
if (!dlstatus && M_CheckParm("-nodownload"))
dlstatus = 3;
if (!dlstatus)
return true;
// not downloadable, put reason in console
CONS_Alert(CONS_NOTICE, M_GetText("You need additional files to connect to this server:\n"));
for (i = 0; i < fileneedednum; i++)
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN)
{
CONS_Printf(" * \"%s\" (%dK)", fileneeded[i].filename, fileneeded[i].totalsize >> 10);
else
CONS_Printf(M_GetText(" not found, md5: "));
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
{
INT32 j;
char md5tmp[33];
for (j = 0; j < 16; j++)
sprintf(&md5tmp[j*2], "%02x", fileneeded[i].md5sum[j]);
CONS_Printf("%s", md5tmp);
}
CONS_Printf("\n");
}
switch (dlstatus)
{
case 1:
CONS_Printf(M_GetText("Some files are larger than the server is willing to send.\n"));
break;
case 2:
CONS_Printf(M_GetText("The server is not allowing download requests.\n"));
break;
case 3:
CONS_Printf(M_GetText("All files downloadable, but you have chosen to disable downloading locally.\n"));
break;
}
return false;
}
// The following was written and, against all odds, works.
#define MORELEGACYDOWNLOADER
/** Sends requests for files in the ::fileneeded table with a status of
*
* \return True if the packet was successfully sent
* \note Sends a PT_REQUESTFILE packet
*
*/
boolean CL_SendRequestFile(void)
{
char *p;
INT32 i;
INT64 totalfreespaceneeded = 0, availablefreespace;
INT32 skippedafile = -1;
#ifdef MORELEGACYDOWNLOADER
boolean firstloop = true;
#endif
#ifdef PARANOIA
if (M_CheckParm("-nodownload"))
{
CONS_Printf("Direct download - Attempted to download files in -nodownload mode");
return false;
}
if (fileneeded[i].status != FS_FOUND && fileneeded[i].status != FS_OPEN
CONS_Printf("Direct download - attempted to download files that were not sendable\n");
return false;
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK))
{
// Error check for the first time around.
totalfreespaceneeded += fileneeded[i].totalsize;
}
}
I_GetDiskFreeSpace(&availablefreespace);
if (totalfreespaceneeded > availablefreespace)
{
CONS_Printf("Direct download -\n"
" To play on this server you must download %s KB,\n"
" but you have only %s KB free space on this drive\n",
sizeu1((size_t)(totalfreespaceneeded>>10)), sizeu2((size_t)(availablefreespace>>10)));
#ifdef MORELEGACYDOWNLOADER
tryagain:
skippedafile = -1;
#endif
#ifdef VERBOSEREQUESTFILE
CONS_Printf("Preparing packet\n");
#endif
netbuffer->packettype = PT_REQUESTFILE;
p = (char *)netbuffer->u.textcmd;
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK))
// Pre-prepare.
size_t checklen;
// Figure out if we'd overrun our buffer.
checklen = strlen(fileneeded[i].filename)+2; // plus the fileid (and terminator, in case this is last)
if ((UINT8 *)(p + checklen) >= netbuffer->u.textcmd + MAXTEXTCMD)
{
skippedafile = i;
// we might have a shorter file that can fit in the remaining space, and file ID permits out-of-order data
continue;
}
// Now write.
WRITEUINT8(p, i); // fileid
WRITESTRINGN(p, fileneeded[i].filename, MAX_WADPATH);
#ifdef VERBOSEREQUESTFILE
CONS_Printf(" file \"%s\" (id %d)\n", i, fileneeded[i].filename);
#endif
// put it in download dir
strcatbf(fileneeded[i].filename, downloaddir, "/");
fileneeded[i].status = FS_REQUESTED;
}
}
#ifdef MORELEGACYDOWNLOADER
if (firstloop)
#else
// If we're not trying extralong legacy download requests, gotta bail.
if (skippedafile != -1)
{
CONS_Printf("Direct download - missing files are as follows:\n");
for (i = 0; i < fileneedednum; i++)
{
if ((fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK || fileneeded[i].status == FS_REQUESTED)) // FS_REQUESTED added
CONS_Printf(" %s\n", fileneeded[i].filename);
}
#endif
I_mkdir(downloaddir, 0755);
// Couldn't fit a single one in?
if (p == (char *)netbuffer->u.textcmd)
{
CONS_Printf("Direct download - fileneeded name for %s (fileneeded[%d]) too long??\n", (skippedafile != -1 ? fileneeded[skippedafile].filename : NULL), skippedafile);
return false;
}
WRITEUINT8(p, 0xFF); // terminator
if (!HSendPacket(servernode, true, 0, p - (char *)netbuffer->u.textcmd))
{
CONS_Printf("Direct download - unable to send packet.\n");
#ifdef MORELEGACYDOWNLOADER
if (skippedafile != -1)
{
firstloop = false;
goto tryagain;
}
#endif
#ifdef VERBOSEREQUESTFILE
CONS_Printf("Returning true\n");
#endif
}
// get request filepak and put it on the send queue
// returns false if a requested file was not found or cannot be sent
boolean Got_RequestFilePak(INT32 node)
{
char wad[MAX_WADPATH+1];
UINT8 *p = netbuffer->u.textcmd;
UINT8 id;
while (p < netbuffer->u.textcmd + MAXTEXTCMD) // Don't allow hacked client to overflow
{
id = READUINT8(p);
if (id == 0xFF)
break;
READSTRINGN(p, wad, MAX_WADPATH);
if (p >= netbuffer->u.textcmd + MAXTEXTCMD || !SV_SendFile(node, wad, id))
if (cv_noticedownload.value)
CONS_Printf("Bad PT_REQUESTFILE from node %d!\n", node);
Monster Iestyn
committed
SV_AbortSendFiles(node);
return false; // don't read any more
/** Checks if the files needed aren't already loaded or on the disk
*
* \return 0 if some files are missing
* 1 if all files exist
* 2 if some already loaded files are not requested or are in a different order
* 3 too many files, over WADLIMIT
* 4 still checking, continuing next tic
INT32 CL_CheckFiles(void)
{
INT32 i, j;
char wadfilename[MAX_WADPATH];

toaster
committed
size_t packetsize = 0;
size_t filestoload = 0;
boolean downloadrequired = false;
// if (M_CheckParm("-nofiles"))
// return 1;
// the first is the iwad (the main wad file)
// we don't care if it's called srb2.srb or srb2.wad.
// Never download the IWAD, just assume it's there and identical
// ...No! Why were we sending the base wads to begin with??
//fileneeded[0].status = FS_OPEN;
// Modified game handling -- check for an identical file list
// must be identical in files loaded AND in order
// Return 2 on failure -- disconnect from server
if (modifiedgame)
{
CONS_Debug(DBG_NETPLAY, "game is modified; only doing basic checks\n");
for (i = 0, j = mainwads+1; i < fileneedednum || j < numwadfiles;)
// Unimportant on our side. still don't care.
++j;
continue;
}
// If this test is true, we've reached the end of one file list
// and the other still has a file that's important
if (i >= fileneedednum || j >= numwadfiles)
return 2;
// For the sake of speed, only bother with a md5 check
if (memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
return 2;
CONS_Debug(DBG_NETPLAY, "'%s' accounted for\n", fileneeded[i].filename);
fileneeded[i].status = FS_OPEN;
++i;
++j;
}
return 1;
}
if (fileneeded[i].status == FS_NOTFOUND || fileneeded[i].status == FS_MD5SUMBAD || fileneeded[i].status == FS_FALLBACK)
if (fileneeded[i].status != FS_OPEN)
if (fileneeded[i].status != FS_NOTCHECKED) //since we're running this over multiple tics now, its possible for us to come across files checked in previous tics
continue;
CONS_Debug(DBG_NETPLAY, "searching for '%s' ", fileneeded[i].filename);
{
nameonly(strcpy(wadfilename, wadfiles[j]->filename));
if (!stricmp(wadfilename, fileneeded[i].filename) &&
!memcmp(wadfiles[j]->md5sum, fileneeded[i].md5sum, 16))
{
CONS_Debug(DBG_NETPLAY, "already loaded\n");
fileneeded[i].status = FS_OPEN;

toaster
committed
packetsize += nameonlylength(fileneeded[i].filename) + 22;
fileneeded[i].status = findfile(fileneeded[i].filename, fileneeded[i].md5sum, true);
CONS_Debug(DBG_NETPLAY, "found %d\n", fileneeded[i].status);
//now making it here means we've checked the entire list and no FS_NOTCHECKED files remain
if (numwadfiles+filestoload > MAX_WADFILES)
return 3;
else if (downloadrequired)
return 0; //some stuff is FS_NOTFOUND, needs download
else
return 1; //everything is FS_OPEN or FS_FOUND, proceed to loading
{
INT32 i;
// if (M_CheckParm("-nofiles"))
// return;
for (i = 0; i < fileneedednum; i++)
P_PartialAddWadFile(fileneeded[i].filename);
G_SetGameModified(true, false);
I_Error("Wrong version of file %s", fileneeded[i].filename);
else
switch(fileneeded[i].status)
{
case FS_NOTFOUND:
s = "FS_NOTFOUND";
break;
case FS_REQUESTED:
s = "FS_REQUESTED";
break;
case FS_DOWNLOADING:
s = "FS_DOWNLOADING";
break;
default:
s = "unknown";
break;
}
I_Error("Try to load file \"%s\" with status of %d (%s)\n", fileneeded[i].filename,
fileneeded[i].status, s);
}
// Number of files to send
// Little optimization to quickly test if there is a file in the queue
static INT32 filestosend = 0;
/** Adds a file to the file list for a node
*
* \param node The node to send the file to
* \param filename The file to send
* \param fileid ???
* \sa SV_SendRam
*
*/
static boolean SV_SendFile(INT32 node, const char *filename, UINT8 fileid)
filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request

LJ Sonic
committed
if (cv_noticedownload.value)
CONS_Printf("Sending file \"%s\" (id %d) to node %d (%s)\n", filename, fileid, node, I_GetNodeAddress(node));

LJ Sonic
committed
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
// Allocate a file request and append it to the file list
if (!p)
I_Error("SV_SendFile: No more memory\n");
// Initialise with zeros
memset(p, 0, sizeof (filetx_t));
// Allocate the file name
p->id.filename = (char *)malloc(MAX_WADPATH);
if (!p->id.filename)
I_Error("SV_SendFile: No more memory\n");
// Set the file name and get rid of the path
strlcpy(p->id.filename, filename, MAX_WADPATH);
nameonly(p->id.filename);
// Look for the requested file through all loaded files
for (i = 0; wadfiles[i]; i++)
{
strlcpy(wadfilename, wadfiles[i]->filename, MAX_WADPATH);
nameonly(wadfilename);
// Copy file name with full path
strlcpy(p->id.filename, wadfiles[i]->filename, MAX_WADPATH);
if (!wadfiles[i])
{
DEBFILE(va("%s not found in wadfiles\n", filename));
// This formerly checked if (!findfile(p->id.filename, NULL, true))
// Not found
// Don't inform client (probably someone who thought they could leak 2.2 ACZ)
DEBFILE(va("Client %d request %s: not found\n", node, filename));
return false; // cancel the rest of the requests
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
if (wadfiles[i]->filesize > (UINT32)cv_maxsend.value * 1024)
{
// Too big
// Don't inform client (client sucks, man)
DEBFILE(va("Client %d request %s: file too big, not sending\n", node, filename));
return false; // cancel the rest of the requests
}
DEBFILE(va("Sending file %s (id=%d) to %d\n", filename, fileid, node));
p->ram = SF_FILE; // It's a file, we need to close it and free its name once we're done sending it
p->next = NULL; // End of list
filestosend++;
/** Adds a memory block to the file list for a node
*
* \param node The node to send the memory block to
* \param data The memory block to send
* \param size The size of the block in bytes
* \param freemethod How to free the block after it has been sent
* \param fileid ???
* \sa SV_SendFile
*
*/
void SV_SendRam(INT32 node, void *data, size_t size, freemethod_t freemethod, UINT8 fileid)
filetx_t **q; // A pointer to the "next" field of the last file in the list
filetx_t *p; // The new file request
// Find the last file in the list and set a pointer to its "next" field
q = &transfer[node].txlist;
while (*q)
q = &((*q)->next);
// Allocate a file request and append it to the file list
if (!p)
I_Error("SV_SendRam: No more memory\n");
// Initialise with zeros
memset(p, 0, sizeof (filetx_t));
p->ram = freemethod; // Remember how to free the memory block for when we're done sending it
p->id.ram = data;
DEBFILE(va("Sending ram %p(size:%u) to %d (id=%u)\n",p->id.ram,p->size,node,fileid));
/** Stops sending a file for a node, and removes the file request from the list,
* either because the file has been fully sent or because the node was disconnected
*
* \param node The destination
*
*/
static void SV_EndFileSend(INT32 node)
// Free the file request according to the freemethod parameter used with SV_SendFile/Ram
case SF_FILE: // It's a file, close it and free its filename

LJ Sonic
committed
if (cv_noticedownload.value)
CONS_Printf("Ending file transfer (id %d) for node %d\n", p->fileid, node);
if (transferFiles[p->fileid].file)
{
if (transferFiles[p->fileid].count > 0)
{
transferFiles[p->fileid].count--;
}
if (transferFiles[p->fileid].count == 0)
{
fclose(transferFiles[p->fileid].file);
transferFiles[p->fileid].file = NULL;
}
}
case SF_Z_RAM: // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
Z_Free(p->id.ram);
case SF_RAM: // It's a memory block allocated with malloc, use free
free(p->id.ram);
case SF_NOFREERAM: // Nothing to free
// Remove the file request from the list
// Indicate that the transmission is over
}
#define PACKETPERTIC net_bandwidth/(TICRATE*software_MAXPACKETLENGTH)

LJ Sonic
committed
* \todo Use an acknowledging method more adapted to file transmission
* The current download speed suffers from lack of ack packets,
* especially when the one downloading has high latency
{
static INT32 currentnode = 0;
filetx_pak *p;
size_t size;
filetx_t *f;

LJ Sonic
committed
INT32 packetsent, ram, i, j;
INT32 maxpacketsent;

LJ Sonic
committed
if (!filestosend) // No file to send

LJ Sonic
committed
if (cv_downloadspeed.value) // New (and experimental) behavior
{
packetsent = cv_downloadspeed.value;
// Don't send more packets than we have free acks

LJ Sonic
committed
maxpacketsent = Net_GetFreeAcks(false) - 5; // Let 5 extra acks just in case

LJ Sonic
committed
if (packetsent > maxpacketsent && maxpacketsent > 0) // Send at least one packet
packetsent = maxpacketsent;
}
else // Old behavior
{
packetsent = PACKETPERTIC;
if (!packetsent)
packetsent = 1;
}
netbuffer->packettype = PT_FILEFRAGMENT;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)

LJ Sonic
committed
for (i = currentnode, j = 0; j < MAXNETNODES;
i = (i+1) % MAXNETNODES, j++)
{
if (transfer[i].txlist)
goto found;
}
// no transfer to do
I_Error("filestosend=%d but no file to send found\n", filestosend);
found:
currentnode = (i+1) % MAXNETNODES;
f = transfer[i].txlist;
ram = f->ram;
// It needs opened.
transferFiles[f->fileid].file =
fopen(f->id.filename, "rb");
if (!transferFiles[f->fileid].file)
{
I_Error("Can't open file %s: %s",
f->id.filename, strerror(errno));
}
// Increment number of nodes using this file.
I_Assert(transferFiles[f->fileid].count < UINT8_MAX);
transferFiles[f->fileid].count++;
fseek(transferFiles[f->fileid].file, 0, SEEK_END);
filesize = ftell(transferFiles[f->fileid].file);
// Nobody wants to transfer a file bigger
// than 4GB!
if (filesize >= LONG_MAX)
I_Error("filesize of %s is too large", f->id.filename);
if (filesize == -1)
I_Error("Error getting filesize of %s", f->id.filename);
f->size = transferFiles[f->fileid].position = (UINT32)filesize;
transfer[i].init = true; // Indicate that it is open
}
if (!ram)
{
// Seek to the right position if we aren't already there.
if (transferFiles[f->fileid].position != transfer[i].position)
{
fseek(transferFiles[f->fileid].file, transfer[i].position, SEEK_SET);
}
// Build a packet containing a file fragment
p = &netbuffer->u.filetxpak;
size = software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE);
if (f->size - transfer[i].position < size)
{
size = f->size - transfer[i].position;
}
M_Memcpy(p->data, &f->id.ram[transfer[i].position], size);
}
else if (fread(p->data, 1, size, transferFiles[f->fileid].file) != size)
{
I_Error("SV_FileSendTicker: can't read %s byte on %s at %d because %s",
sizeu1(size), f->id.filename, transfer[i].position, M_FileError(transferFiles[f->fileid].file));
transferFiles[f->fileid].position = (UINT32)(transferFiles[f->fileid].position + size);
// Put flag so receiver knows the total size
if (transfer[i].position + size == f->size)
p->position |= LONG(0x80000000);
p->fileid = f->fileid;
p->size = SHORT((UINT16)size);
// Send the packet
if (HSendPacket(i, true, 0, FILETXHEADER + size)) // Reliable SEND
transfer[i].position = (UINT32)(transfer[i].position + size);
if (transfer[i].position == f->size) // Finish?
{
// Not sent for some odd reason, retry at next call
// Exit the while (can't send this one so why should i send the next?)
break;
}
}
}
void Got_Filetxpak(void)
{
INT32 filenum = netbuffer->u.filetxpak.fileid;

LJ Sonic
committed
fileneeded_t *file = &fileneeded[filenum];
char *filename = file->filename;

LJ Sonic
committed
if (!(strcmp(filename, "srb2.srb")
&& strcmp(filename, "srb2.wad")
&& strcmp(filename, "patch.dta")
//&& strcmp(filename, "music.dta")
&& strcmp(filename, "gfx.kart")
&& strcmp(filename, "textures.kart")
&& strcmp(filename, "chars.kart")
&& strcmp(filename, "maps.kart")
&& strcmp(filename, "sounds.kart")
&& strcmp(filename, "music.kart")
&& strcmp(filename, "patch.kart")

LJ Sonic
committed
))
I_Error("Tried to download \"%s\"", filename);
DEBFILE(va("fileframent not needed %d>%d\n", filenum, fileneedednum));

LJ Sonic
committed
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);

LJ Sonic
committed
if (file->status == FS_REQUESTED)

LJ Sonic
committed
if (file->file)
I_Error("Got_Filetxpak: already open file\n");

LJ Sonic
committed
file->file = fopen(filename, "wb");
if (!file->file)
I_Error("Can't create file %s: %s", filename, strerror(errno));
CONS_Printf("\r%s...\n",filename);
file->currentsize = 0;
file->status = FS_DOWNLOADING;