2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
2021-05-07 15:45:56 +00:00
// Copyright (C) 1999-2021 by Sonic Team Junior.
2014-03-15 16:59:03 +00:00
//
// 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>
# include <sys/stat.h>
# include <time.h>
2021-03-22 14:43:26 +00:00
# ifdef _WIN32
2014-03-15 16:59:03 +00:00
# include <io.h>
# include <direct.h>
2017-09-29 22:25:34 +00:00
# else
2014-03-15 16:59:03 +00:00
# include <sys/types.h>
# include <dirent.h>
# include <utime.h>
# endif
# ifdef __GNUC__
# include <unistd.h>
# include <limits.h>
2017-09-29 22:25:34 +00:00
# elif defined (_WIN32)
2014-03-15 16:59:03 +00:00
# include <sys/utime.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"
2014-04-14 05:14:58 +00:00
# include <errno.h>
2017-05-26 12:39:54 +00:00
// Prototypes
2020-05-12 17:06:40 +00:00
static boolean AddFileToSendQueue ( INT32 node , const char * filename , UINT8 fileid ) ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Sender structure
2014-03-15 16:59:03 +00:00
typedef struct filetx_s
{
INT32 ram ;
2016-12-31 18:26:33 +00:00
union {
char * filename ; // Name of the file
char * ram ; // Pointer to the data in RAM
} id ;
UINT32 size ; // Size of the file
2014-03-15 16:59:03 +00:00
UINT8 fileid ;
2016-12-31 18:26:33 +00:00
INT32 node ; // Destination
struct filetx_s * next ; // Next file in the list
2014-03-15 16:59:03 +00:00
} filetx_t ;
2016-12-31 18:26:33 +00:00
// Current transfers (one for each node)
2014-03-15 16:59:03 +00:00
typedef struct filetran_s
{
2016-12-31 18:26:33 +00:00
filetx_t * txlist ; // Linked list of all files for the node
2020-05-20 14:21:18 +00:00
UINT8 iteration ;
UINT8 ackediteration ;
2016-12-31 18:26:33 +00:00
UINT32 position ; // The current position in the file
2020-05-16 20:09:00 +00:00
boolean * ackedfragments ;
UINT32 ackedsize ;
2016-12-31 18:26:33 +00:00
FILE * currentfile ; // The file currently being sent/received
2020-05-20 14:21:18 +00:00
tic_t dontsenduntil ;
2014-03-15 16:59:03 +00:00
} filetran_t ;
static filetran_t transfer [ MAXNETNODES ] ;
2016-12-31 18:26:33 +00:00
// Read time of file: stat _stmtime
// Write time of file: utime
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Receiver structure
INT32 fileneedednum ; // Number of files needed to join the server
fileneeded_t fileneeded [ MAX_WADFILES ] ; // List of needed files
2020-05-16 20:09:00 +00:00
static tic_t lasttimeackpacketsent = 0 ;
2018-11-14 21:50:52 +00:00
char downloaddir [ 512 ] = " DOWNLOAD " ;
2014-03-15 16:59:03 +00:00
2020-05-19 09:28:24 +00:00
// For resuming failed downloads
typedef struct
{
char filename [ MAX_WADPATH ] ;
UINT8 md5sum [ 16 ] ;
boolean * receivedfragments ;
UINT32 fragmentsize ;
UINT32 currentsize ;
} pauseddownload_t ;
static pauseddownload_t * pauseddownload = NULL ;
2020-06-27 00:01:16 +00:00
# ifndef NONET
2014-03-15 16:59:03 +00:00
// for cl loading screen
2017-01-13 19:53:52 +00:00
INT32 lastfilenum = - 1 ;
2014-03-15 16:59:03 +00:00
# endif
2020-01-22 22:08:57 +00:00
luafiletransfer_t * luafiletransfers = NULL ;
boolean waitingforluafiletransfer = false ;
2020-05-19 21:50:37 +00:00
boolean waitingforluafilecommand = false ;
2020-02-21 16:31:32 +00:00
char luafiledir [ 256 + 16 ] = " luafiles " ;
2020-01-22 22:08:57 +00:00
2014-03-15 16:59:03 +00:00
/** Fills a serverinfo packet with information about wad files loaded.
*
* \ todo Give this function a better name since it is in global scope .
2021-03-23 02:56:55 +00:00
* Used to have size limiting built in - now handled via W_InitFile in w_wad . c
2016-12-31 18:26:33 +00:00
*
2014-03-15 16:59:03 +00:00
*/
UINT8 * PutFileNeeded ( void )
{
size_t i , count = 0 ;
UINT8 * p = netbuffer - > u . serverinfo . fileneeded ;
char wadfilename [ MAX_WADPATH ] = " " ;
2021-03-23 02:56:55 +00:00
UINT8 filestatus , folder ;
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < numwadfiles ; i + + )
{
2017-05-25 16:58:32 +00:00
// If it has only music/sound lumps, don't put it in the list
2017-05-27 13:01:26 +00:00
if ( ! wadfiles [ i ] - > important )
2017-05-25 16:58:32 +00:00
continue ;
2017-05-27 14:10:16 +00:00
filestatus = 1 ; // Importance - not really used any more, holds 1 by default for backwards compat with MS
2021-03-23 02:56:55 +00:00
folder = ( wadfiles [ i ] - > type = = RET_FOLDER ) ;
2014-03-15 16:59:03 +00:00
// Store in the upper four bits
2021-03-23 02:56:55 +00:00
if ( ! cv_downloading . value | | folder ) /// \todo Implement folder downloading.
2016-12-31 18:26:33 +00:00
filestatus + = ( 2 < < 4 ) ; // Won't send
2017-05-25 16:58:32 +00:00
else if ( ( wadfiles [ i ] - > filesize < = ( UINT32 ) cv_maxsend . value * 1024 ) )
2016-12-31 18:26:33 +00:00
filestatus + = ( 1 < < 4 ) ; // Will send if requested
2017-05-25 16:58:32 +00:00
// else
// filestatus += (0 << 4); -- Won't send, too big
2014-03-15 16:59:03 +00:00
WRITEUINT8 ( p , filestatus ) ;
2021-03-23 02:56:55 +00:00
WRITEUINT8 ( p , folder ) ;
2014-03-15 16:59:03 +00:00
count + + ;
WRITEUINT32 ( p , wadfiles [ i ] - > filesize ) ;
nameonly ( strcpy ( wadfilename , wadfiles [ i ] - > filename ) ) ;
WRITESTRINGN ( p , wadfilename , MAX_WADPATH ) ;
WRITEMEM ( p , wadfiles [ i ] - > md5sum , 16 ) ;
}
netbuffer - > u . serverinfo . fileneedednum = ( UINT8 ) count ;
return p ;
}
2016-12-31 18:26:33 +00:00
/** Parses the serverinfo packet and fills the fileneeded table on client
*
* \ param fileneedednum_parm The number of files needed to join the server
* \ param fileneededstr The memory block containing the list of needed files
*
*/
2014-03-15 16:59:03 +00:00
void D_ParseFileneeded ( INT32 fileneedednum_parm , UINT8 * fileneededstr )
{
INT32 i ;
UINT8 * p ;
UINT8 filestatus ;
fileneedednum = fileneedednum_parm ;
p = ( UINT8 * ) fileneededstr ;
for ( i = 0 ; i < fileneedednum ; i + + )
{
2016-12-31 18:26:33 +00:00
fileneeded [ i ] . status = FS_NOTFOUND ; // We haven't even started looking for the file yet
2020-05-16 20:09:00 +00:00
fileneeded [ i ] . justdownloaded = false ;
2016-12-31 18:26:33 +00:00
filestatus = READUINT8 ( p ) ; // The first byte is the file status
2021-03-23 02:56:55 +00:00
fileneeded [ i ] . folder = READUINT8 ( p ) ; // The second byte is the folder flag
2014-03-15 16:59:03 +00:00
fileneeded [ i ] . willsend = ( UINT8 ) ( filestatus > > 4 ) ;
2016-12-31 18:26:33 +00:00
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
2014-03-15 16:59:03 +00:00
}
}
void CL_PrepareDownloadSaveGame ( const char * tmpsave )
{
2020-06-27 00:01:16 +00:00
# ifndef NONET
2020-05-16 20:49:20 +00:00
lastfilenum = - 1 ;
# endif
2014-03-15 16:59:03 +00:00
fileneedednum = 1 ;
fileneeded [ 0 ] . status = FS_REQUESTED ;
2020-05-16 20:09:00 +00:00
fileneeded [ 0 ] . justdownloaded = false ;
2014-03-15 16:59:03 +00:00
fileneeded [ 0 ] . totalsize = UINT32_MAX ;
2016-12-31 18:26:33 +00:00
fileneeded [ 0 ] . file = NULL ;
2014-03-15 16:59:03 +00:00
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 .
2016-12-31 18:26:33 +00:00
*
* \ return True if we can download all the files
*
2014-03-15 16:59:03 +00:00
*/
boolean CL_CheckDownloadable ( void )
{
UINT8 i , dlstatus = 0 ;
for ( i = 0 ; i < fileneedednum ; i + + )
2017-05-25 16:58:32 +00:00
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN )
2014-03-15 16:59:03 +00:00
{
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 + + )
2017-05-25 16:58:32 +00:00
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN )
2014-03-15 16:59:03 +00:00
{
CONS_Printf ( " * \" %s \" (%dK) " , fileneeded [ i ] . filename , fileneeded [ i ] . totalsize > > 10 ) ;
if ( fileneeded [ i ] . status = = FS_NOTFOUND )
CONS_Printf ( M_GetText ( " not found, md5: " ) ) ;
else if ( fileneeded [ i ] . status = = FS_MD5SUMBAD )
CONS_Printf ( M_GetText ( " wrong version, md5: " ) ) ;
{
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 ;
}
2020-05-19 09:28:24 +00:00
/** Returns true if a needed file transfer can be resumed
*
* \ param file The needed file to resume the transfer for
* \ return True if the transfer can be resumed
*
*/
static boolean CL_CanResumeDownload ( fileneeded_t * file )
{
return pauseddownload
& & ! strcmp ( pauseddownload - > filename , file - > filename ) // Same name
& & ! memcmp ( pauseddownload - > md5sum , file - > md5sum , 16 ) // Same checksum
& & pauseddownload - > fragmentsize = = file - > fragmentsize ; // Same fragment size
}
void CL_AbortDownloadResume ( void )
{
if ( ! pauseddownload )
return ;
free ( pauseddownload - > receivedfragments ) ;
remove ( pauseddownload - > filename ) ;
free ( pauseddownload ) ;
pauseddownload = NULL ;
}
2016-12-31 18:26:33 +00:00
/** Sends requests for files in the ::fileneeded table with a status of
2014-03-15 16:59:03 +00:00
* : : FS_NOTFOUND .
2016-12-31 18:26:33 +00:00
*
* \ return True if the packet was successfully sent
* \ note Sends a PT_REQUESTFILE packet
*
2014-03-15 16:59:03 +00:00
*/
2020-05-12 17:06:40 +00:00
boolean CL_SendFileRequest ( void )
2014-03-15 16:59:03 +00:00
{
char * p ;
INT32 i ;
INT64 totalfreespaceneeded = 0 , availablefreespace ;
# ifdef PARANOIA
if ( M_CheckParm ( " -nodownload " ) )
I_Error ( " Attempted to download files in -nodownload mode " ) ;
for ( i = 0 ; i < fileneedednum ; i + + )
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN
2017-05-25 16:58:32 +00:00
& & ( fileneeded [ i ] . willsend = = 0 | | fileneeded [ i ] . willsend = = 2 ) )
2014-03-15 16:59:03 +00:00
{
I_Error ( " Attempted to download files that were not sendable " ) ;
}
# endif
netbuffer - > packettype = PT_REQUESTFILE ;
p = ( char * ) netbuffer - > u . textcmd ;
for ( i = 0 ; i < fileneedednum ; i + + )
2017-05-25 16:58:32 +00:00
if ( ( fileneeded [ i ] . status = = FS_NOTFOUND | | fileneeded [ i ] . status = = FS_MD5SUMBAD ) )
2014-03-15 16:59:03 +00:00
{
totalfreespaceneeded + = fileneeded [ i ] . totalsize ;
nameonly ( fileneeded [ i ] . filename ) ;
WRITEUINT8 ( p , i ) ; // fileid
WRITESTRINGN ( p , fileneeded [ i ] . filename , MAX_WADPATH ) ;
// put it in download dir
strcatbf ( fileneeded [ i ] . filename , downloaddir , " / " ) ;
fileneeded [ i ] . status = FS_REQUESTED ;
}
WRITEUINT8 ( p , 0xFF ) ;
I_GetDiskFreeSpace ( & availablefreespace ) ;
if ( totalfreespaceneeded > availablefreespace )
I_Error ( " 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 ) ) ) ;
// prepare to download
I_mkdir ( downloaddir , 0755 ) ;
return HSendPacket ( servernode , true , 0 , p - ( char * ) netbuffer - > u . textcmd ) ;
}
// get request filepak and put it on the send queue
2017-05-26 12:39:54 +00:00
// returns false if a requested file was not found or cannot be sent
2020-05-12 17:06:40 +00:00
boolean PT_RequestFile ( INT32 node )
2014-03-15 16:59:03 +00:00
{
char wad [ MAX_WADPATH + 1 ] ;
UINT8 * p = netbuffer - > u . textcmd ;
UINT8 id ;
while ( p < netbuffer - > u . textcmd + MAXTEXTCMD - 1 ) // Don't allow hacked client to overflow
{
id = READUINT8 ( p ) ;
if ( id = = 0xFF )
break ;
READSTRINGN ( p , wad , MAX_WADPATH ) ;
2020-05-12 17:06:40 +00:00
if ( ! AddFileToSendQueue ( node , wad , id ) )
2017-05-26 12:39:54 +00:00
{
2017-05-26 13:19:18 +00:00
SV_AbortSendFiles ( node ) ;
2017-05-26 12:39:54 +00:00
return false ; // don't read the rest of the files
}
2014-03-15 16:59:03 +00:00
}
2017-05-26 12:39:54 +00:00
return true ; // no problems with any files
2014-03-15 16:59:03 +00:00
}
2016-12-31 18:26:33 +00:00
/** 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
*
*/
2014-03-15 16:59:03 +00:00
INT32 CL_CheckFiles ( void )
{
INT32 i , j ;
char wadfilename [ MAX_WADPATH ] ;
INT32 ret = 1 ;
2017-05-25 15:06:39 +00:00
size_t packetsize = 0 ;
2017-05-26 15:16:10 +00:00
size_t filestoget = 0 ;
2014-03-15 16:59:03 +00:00
// if (M_CheckParm("-nofiles"))
// return 1;
// the first is the iwad (the main wad file)
2017-12-07 18:26:12 +00:00
// we don't care if it's called srb2.pk3 or not.
2014-03-15 16:59:03 +00:00
// Never download the IWAD, just assume it's there and identical
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 = 1 , j = 1 ; i < fileneedednum | | j < numwadfiles ; )
{
2017-05-27 13:01:26 +00:00
if ( j < numwadfiles & & ! wadfiles [ j ] - > important )
2014-03-15 16:59:03 +00:00
{
2017-05-25 16:58:32 +00:00
// Unimportant on our side.
2014-03-15 16:59:03 +00:00
+ + 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 ;
2016-12-31 18:26:33 +00:00
// For the sake of speed, only bother with a md5 check
2014-03-15 16:59:03 +00:00
if ( memcmp ( wadfiles [ j ] - > md5sum , fileneeded [ i ] . md5sum , 16 ) )
return 2 ;
2016-12-31 18:26:33 +00:00
// It's accounted for! let's keep going.
2014-03-15 16:59:03 +00:00
CONS_Debug ( DBG_NETPLAY , " '%s' accounted for \n " , fileneeded [ i ] . filename ) ;
fileneeded [ i ] . status = FS_OPEN ;
+ + i ;
+ + j ;
}
return 1 ;
}
2021-03-23 02:56:55 +00:00
// See W_InitFile in w_wad.c
2018-06-18 11:49:06 +00:00
packetsize = packetsizetally ;
2017-05-25 15:06:39 +00:00
2014-03-15 16:59:03 +00:00
for ( i = 1 ; i < fileneedednum ; i + + )
{
CONS_Debug ( DBG_NETPLAY , " searching for '%s' " , fileneeded [ i ] . filename ) ;
2016-12-31 18:26:33 +00:00
// Check in already loaded files
2014-03-15 16:59:03 +00:00
for ( j = 1 ; wadfiles [ j ] ; j + + )
{
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 ;
break ;
}
}
2017-05-25 16:58:32 +00:00
if ( fileneeded [ i ] . status ! = FS_NOTFOUND )
2014-03-15 16:59:03 +00:00
continue ;
2021-03-23 02:56:55 +00:00
if ( fileneeded [ i ] . folder )
packetsize + = strlen ( fileneeded [ i ] . filename ) + FILENEEDEDSIZE ;
else
packetsize + = nameonlylength ( fileneeded [ i ] . filename ) + FILENEEDEDSIZE ;
2017-05-25 15:06:39 +00:00
2017-05-26 15:16:10 +00:00
if ( ( numwadfiles + filestoget > = MAX_WADFILES )
2018-06-18 11:49:06 +00:00
| | ( packetsize > MAXFILENEEDED * sizeof ( UINT8 ) ) )
2017-05-25 15:06:39 +00:00
return 3 ;
2017-05-26 15:16:10 +00:00
filestoget + + ;
2021-03-23 02:56:55 +00:00
if ( fileneeded [ i ] . folder )
fileneeded [ i ] . status = findfolder ( fileneeded [ i ] . filename ) ;
else
fileneeded [ i ] . status = findfile ( fileneeded [ i ] . filename , fileneeded [ i ] . md5sum , true ) ;
2014-03-15 16:59:03 +00:00
CONS_Debug ( DBG_NETPLAY , " found %d \n " , fileneeded [ i ] . status ) ;
if ( fileneeded [ i ] . status ! = FS_FOUND )
ret = 0 ;
}
return ret ;
}
2016-12-31 18:26:33 +00:00
// Load it now
2014-03-15 16:59:03 +00:00
void CL_LoadServerFiles ( void )
{
INT32 i ;
// if (M_CheckParm("-nofiles"))
// return;
for ( i = 1 ; i < fileneedednum ; i + + )
{
if ( fileneeded [ i ] . status = = FS_OPEN )
2016-12-31 18:26:33 +00:00
continue ; // Already loaded
2014-03-15 16:59:03 +00:00
else if ( fileneeded [ i ] . status = = FS_FOUND )
{
2021-03-23 02:56:55 +00:00
if ( fileneeded [ i ] . folder )
P_AddFolder ( fileneeded [ i ] . filename ) ;
else
P_AddWadFile ( fileneeded [ i ] . filename ) ;
2014-03-15 16:59:03 +00:00
G_SetGameModified ( true ) ;
fileneeded [ i ] . status = FS_OPEN ;
}
else if ( fileneeded [ i ] . status = = FS_MD5SUMBAD )
2017-05-25 16:58:32 +00:00
I_Error ( " Wrong version of file %s " , fileneeded [ i ] . filename ) ;
else
2016-12-31 18:26:33 +00:00
{
2017-01-01 22:27:06 +00:00
const char * s ;
2016-12-31 18:26:33 +00:00
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 ) ;
}
2014-03-15 16:59:03 +00:00
}
}
2020-01-22 22:08:57 +00:00
void AddLuaFileTransfer ( const char * filename , const char * mode )
{
luafiletransfer_t * * prevnext ; // A pointer to the "next" field of the last transfer in the list
luafiletransfer_t * filetransfer ;
static INT32 id ;
// Find the last transfer in the list and set a pointer to its "next" field
prevnext = & luafiletransfers ;
while ( * prevnext )
prevnext = & ( ( * prevnext ) - > next ) ;
// Allocate file transfer information and append it to the transfer list
filetransfer = malloc ( sizeof ( luafiletransfer_t ) ) ;
if ( ! filetransfer )
I_Error ( " AddLuaFileTransfer: Out of memory \n " ) ;
* prevnext = filetransfer ;
2020-02-19 21:01:33 +00:00
filetransfer - > next = NULL ;
2020-01-22 22:08:57 +00:00
2020-02-19 21:01:33 +00:00
// Allocate the file name
filetransfer - > filename = strdup ( filename ) ;
if ( ! filetransfer - > filename )
2020-01-22 22:08:57 +00:00
I_Error ( " AddLuaFileTransfer: Out of memory \n " ) ;
2020-02-19 21:01:33 +00:00
// Create and allocate the real file name
2020-01-22 22:08:57 +00:00
if ( server )
filetransfer - > realfilename = strdup ( va ( " %s " PATHSEP " %s " ,
luafiledir , filename ) ) ;
else
2020-01-24 16:11:00 +00:00
filetransfer - > realfilename = strdup ( va ( " %s " PATHSEP " client " PATHSEP " $$$%d%d.tmp " ,
2020-01-22 22:08:57 +00:00
luafiledir , rand ( ) , rand ( ) ) ) ;
2020-02-19 21:01:33 +00:00
if ( ! filetransfer - > realfilename )
2020-01-22 22:08:57 +00:00
I_Error ( " AddLuaFileTransfer: Out of memory \n " ) ;
strlcpy ( filetransfer - > mode , mode , sizeof ( filetransfer - > mode ) ) ;
2020-05-19 13:16:51 +00:00
// Only if there is no transfer already going on
if ( server & & filetransfer = = luafiletransfers )
SV_PrepareSendLuaFile ( ) ;
2020-05-19 21:50:37 +00:00
else
filetransfer - > ongoing = false ;
2020-01-22 22:08:57 +00:00
// Store the callback so it can be called once everyone has the file
filetransfer - > id = id ;
StoreLuaFileCallback ( id ) ;
id + + ;
if ( waitingforluafiletransfer )
{
waitingforluafiletransfer = false ;
CL_PrepareDownloadLuaFile ( ) ;
}
}
2020-05-19 13:16:51 +00:00
static void SV_PrepareSendLuaFileToNextNode ( void )
2020-01-22 22:08:57 +00:00
{
INT32 i ;
UINT8 success = 1 ;
// Find a client to send the file to
for ( i = 1 ; i < MAXNETNODES ; i + + )
2021-03-25 21:28:07 +00:00
if ( luafiletransfers - > nodestatus [ i ] = = LFTNS_WAITING ) // Node waiting
2020-01-22 22:08:57 +00:00
{
// Tell the client we're about to send them the file
netbuffer - > packettype = PT_SENDINGLUAFILE ;
if ( ! HSendPacket ( i , true , 0 , 0 ) )
I_Error ( " Failed to send a PT_SENDINGLUAFILE packet \n " ) ; // !!! Todo: Handle failure a bit better lol
luafiletransfers - > nodestatus [ i ] = LFTNS_ASKED ;
2021-03-25 21:28:07 +00:00
luafiletransfers - > nodetimeouts [ i ] = I_GetTime ( ) + 30 * TICRATE ;
2020-01-22 22:08:57 +00:00
return ;
}
// No client found, everyone has the file
// Send a net command with 1 as its first byte to indicate the file could be opened
SendNetXCmd ( XD_LUAFILE , & success , 1 ) ;
}
2020-05-19 13:16:51 +00:00
void SV_PrepareSendLuaFile ( void )
{
2020-05-19 19:36:21 +00:00
char * binfilename ;
2020-05-19 13:16:51 +00:00
INT32 i ;
2020-05-19 21:50:37 +00:00
luafiletransfers - > ongoing = true ;
2020-05-19 13:16:51 +00:00
// Set status to "waiting" for everyone
for ( i = 0 ; i < MAXNETNODES ; i + + )
2021-03-25 21:28:07 +00:00
luafiletransfers - > nodestatus [ i ] = ( nodeingame [ i ] ? LFTNS_WAITING : LFTNS_NONE ) ;
2020-05-19 13:16:51 +00:00
if ( FIL_ReadFileOK ( luafiletransfers - > realfilename ) )
2020-05-19 19:36:21 +00:00
{
// If opening in text mode, convert all newlines to LF
if ( ! strchr ( luafiletransfers - > mode , ' b ' ) )
{
binfilename = strdup ( va ( " %s " PATHSEP " $$$%d%d.tmp " ,
luafiledir , rand ( ) , rand ( ) ) ) ;
if ( ! binfilename )
I_Error ( " SV_PrepareSendLuaFile: Out of memory \n " ) ;
if ( ! FIL_ConvertTextFileToBinary ( luafiletransfers - > realfilename , binfilename ) )
I_Error ( " SV_PrepareSendLuaFile: Failed to convert file newlines \n " ) ;
// Use the temporary file instead
free ( luafiletransfers - > realfilename ) ;
luafiletransfers - > realfilename = binfilename ;
}
2020-05-19 13:16:51 +00:00
SV_PrepareSendLuaFileToNextNode ( ) ;
2020-05-19 19:36:21 +00:00
}
2020-05-19 13:16:51 +00:00
else
{
// Send a net command with 0 as its first byte to indicate the file couldn't be opened
UINT8 success = 0 ;
SendNetXCmd ( XD_LUAFILE , & success , 1 ) ;
}
}
2020-01-22 22:08:57 +00:00
void SV_HandleLuaFileSent ( UINT8 node )
{
luafiletransfers - > nodestatus [ node ] = LFTNS_SENT ;
2020-02-19 21:01:33 +00:00
SV_PrepareSendLuaFileToNextNode ( ) ;
2020-01-22 22:08:57 +00:00
}
void RemoveLuaFileTransfer ( void )
{
luafiletransfer_t * filetransfer = luafiletransfers ;
2020-05-19 19:36:21 +00:00
// If it was a temporary file, delete it
if ( server & & ! strchr ( filetransfer - > mode , ' b ' ) )
remove ( filetransfer - > realfilename ) ;
2020-01-22 22:08:57 +00:00
RemoveLuaFileCallback ( filetransfer - > id ) ;
luafiletransfers = filetransfer - > next ;
free ( filetransfer - > filename ) ;
free ( filetransfer - > realfilename ) ;
free ( filetransfer ) ;
}
2020-02-19 21:37:30 +00:00
void RemoveAllLuaFileTransfers ( void )
2020-01-22 22:08:57 +00:00
{
while ( luafiletransfers )
RemoveLuaFileTransfer ( ) ;
}
void SV_AbortLuaFileTransfer ( INT32 node )
{
2021-03-25 21:28:07 +00:00
if ( luafiletransfers )
2020-01-22 22:08:57 +00:00
{
2021-03-25 21:28:07 +00:00
if ( luafiletransfers - > nodestatus [ node ] = = LFTNS_ASKED
| | luafiletransfers - > nodestatus [ node ] = = LFTNS_SENDING )
{
SV_PrepareSendLuaFileToNextNode ( ) ;
}
luafiletransfers - > nodestatus [ node ] = LFTNS_NONE ;
2020-01-22 22:08:57 +00:00
}
}
void CL_PrepareDownloadLuaFile ( void )
{
// If there is no transfer in the list, this normally means the server
// called io.open before us, so we have to wait until we call it too
if ( ! luafiletransfers )
{
waitingforluafiletransfer = true ;
return ;
}
2020-05-19 21:50:37 +00:00
if ( luafiletransfers - > ongoing )
{
waitingforluafilecommand = true ;
return ;
}
2020-01-22 22:08:57 +00:00
// Tell the server we are ready to receive the file
netbuffer - > packettype = PT_ASKLUAFILE ;
HSendPacket ( servernode , true , 0 , 0 ) ;
fileneedednum = 1 ;
fileneeded [ 0 ] . status = FS_REQUESTED ;
2020-05-16 20:09:00 +00:00
fileneeded [ 0 ] . justdownloaded = false ;
2020-01-22 22:08:57 +00:00
fileneeded [ 0 ] . totalsize = UINT32_MAX ;
fileneeded [ 0 ] . file = NULL ;
memset ( fileneeded [ 0 ] . md5sum , 0 , 16 ) ;
strcpy ( fileneeded [ 0 ] . filename , luafiletransfers - > realfilename ) ;
// Make sure all directories in the file path exist
MakePathDirs ( fileneeded [ 0 ] . filename ) ;
2020-05-19 21:50:37 +00:00
luafiletransfers - > ongoing = true ;
2020-01-22 22:08:57 +00:00
}
2016-12-31 18:26:33 +00:00
// Number of files to send
// Little optimization to quickly test if there is a file in the queue
static INT32 filestosend = 0 ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
/** 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
2020-05-19 09:28:24 +00:00
* \ param fileid The index of the file in the list of added files
2020-05-12 17:06:40 +00:00
* \ sa AddRamToSendQueue
* \ sa AddLuaFileToSendQueue
2016-12-31 18:26:33 +00:00
*
*/
2020-05-12 17:06:40 +00:00
static boolean AddFileToSendQueue ( INT32 node , const char * filename , UINT8 fileid )
2014-03-15 16:59:03 +00:00
{
2016-12-31 18:26:33 +00:00
filetx_t * * q ; // A pointer to the "next" field of the last file in the list
filetx_t * p ; // The new file request
2014-03-15 16:59:03 +00:00
INT32 i ;
char wadfilename [ MAX_WADPATH ] ;
2017-01-13 19:53:52 +00:00
if ( cv_noticedownload . value )
2017-05-26 13:38:59 +00:00
CONS_Printf ( " Sending file \" %s \" to node %d (%s) \n " , filename , node , I_GetNodeAddress ( node ) ) ;
2017-01-13 19:53:52 +00:00
2016-12-31 18:26:33 +00:00
// Find the last file in the list and set a pointer to its "next" field
2014-03-15 16:59:03 +00:00
q = & transfer [ node ] . txlist ;
while ( * q )
q = & ( ( * q ) - > next ) ;
2016-12-31 18:26:33 +00:00
// Allocate a file request and append it to the file list
2014-03-15 16:59:03 +00:00
p = * q = ( filetx_t * ) malloc ( sizeof ( filetx_t ) ) ;
2016-12-31 18:26:33 +00:00
if ( ! p )
2020-05-12 17:06:40 +00:00
I_Error ( " AddFileToSendQueue: No more memory \n " ) ;
2016-12-31 18:26:33 +00:00
// Initialise with zeros
memset ( p , 0 , sizeof ( filetx_t ) ) ;
// Allocate the file name
p - > id . filename = ( char * ) malloc ( MAX_WADPATH ) ;
if ( ! p - > id . filename )
2020-05-12 17:06:40 +00:00
I_Error ( " AddFileToSendQueue: No more memory \n " ) ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Set the file name and get rid of the path
strlcpy ( p - > id . filename , filename , MAX_WADPATH ) ;
nameonly ( p - > id . filename ) ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Look for the requested file through all loaded files
2014-03-15 16:59:03 +00:00
for ( i = 0 ; wadfiles [ i ] ; i + + )
{
strlcpy ( wadfilename , wadfiles [ i ] - > filename , MAX_WADPATH ) ;
nameonly ( wadfilename ) ;
2016-12-31 18:26:33 +00:00
if ( ! stricmp ( wadfilename , p - > id . filename ) )
2014-03-15 16:59:03 +00:00
{
2016-12-31 18:26:33 +00:00
// Copy file name with full path
strlcpy ( p - > id . filename , wadfiles [ i ] - > filename , MAX_WADPATH ) ;
2014-03-15 16:59:03 +00:00
break ;
}
}
2016-12-31 18:26:33 +00:00
// Handle non-loaded file requests
2014-03-15 16:59:03 +00:00
if ( ! wadfiles [ i ] )
{
DEBFILE ( va ( " %s not found in wadfiles \n " , filename ) ) ;
2016-12-31 18:26:33 +00:00
// This formerly checked if (!findfile(p->id.filename, NULL, true))
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Not found
2021-03-23 02:56:55 +00:00
// Don't inform client
2014-03-15 16:59:03 +00:00
DEBFILE ( va ( " Client %d request %s: not found \n " , node , filename ) ) ;
2016-12-31 18:26:33 +00:00
free ( p - > id . filename ) ;
2014-03-15 16:59:03 +00:00
free ( p ) ;
* q = NULL ;
2017-05-26 12:39:54 +00:00
return false ; // cancel the rest of the requests
2014-03-15 16:59:03 +00:00
}
2016-12-31 18:26:33 +00:00
// Handle huge file requests (i.e. bigger than cv_maxsend.value KB)
2014-03-15 16:59:03 +00:00
if ( wadfiles [ i ] - > filesize > ( UINT32 ) cv_maxsend . value * 1024 )
{
2016-12-31 18:26:33 +00:00
// Too big
// Don't inform client (client sucks, man)
2014-03-15 16:59:03 +00:00
DEBFILE ( va ( " Client %d request %s: file too big, not sending \n " , node , filename ) ) ;
2016-12-31 18:26:33 +00:00
free ( p - > id . filename ) ;
2014-03-15 16:59:03 +00:00
free ( p ) ;
* q = NULL ;
2017-05-26 12:39:54 +00:00
return false ; // cancel the rest of the requests
2014-03-15 16:59:03 +00:00
}
DEBFILE ( va ( " Sending file %s (id=%d) to %d \n " , filename , fileid , node ) ) ;
2016-12-31 18:26:33 +00:00
p - > ram = SF_FILE ; // It's a file, we need to close it and free its name once we're done sending it
2014-03-15 16:59:03 +00:00
p - > fileid = fileid ;
2016-12-31 18:26:33 +00:00
p - > next = NULL ; // End of list
filestosend + + ;
2017-05-26 12:39:54 +00:00
return true ;
2014-03-15 16:59:03 +00:00
}
2016-12-31 18:26:33 +00:00
/** 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
2020-05-19 09:28:24 +00:00
* \ param fileid The index of the file in the list of added files
2020-05-12 17:06:40 +00:00
* \ sa AddFileToSendQueue
* \ sa AddLuaFileToSendQueue
2016-12-31 18:26:33 +00:00
*
*/
2020-05-12 17:06:40 +00:00
void AddRamToSendQueue ( INT32 node , void * data , size_t size , freemethod_t freemethod , UINT8 fileid )
2014-03-15 16:59:03 +00:00
{
2016-12-31 18:26:33 +00:00
filetx_t * * q ; // A pointer to the "next" field of the last file in the list
filetx_t * p ; // The new file request
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Find the last file in the list and set a pointer to its "next" field
2014-03-15 16:59:03 +00:00
q = & transfer [ node ] . txlist ;
while ( * q )
q = & ( ( * q ) - > next ) ;
2016-12-31 18:26:33 +00:00
// Allocate a file request and append it to the file list
2014-03-15 16:59:03 +00:00
p = * q = ( filetx_t * ) malloc ( sizeof ( filetx_t ) ) ;
2016-12-31 18:26:33 +00:00
if ( ! p )
2020-05-12 17:06:40 +00:00
I_Error ( " AddRamToSendQueue: No more memory \n " ) ;
2016-12-31 18:26:33 +00:00
// 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 ;
2014-03-15 16:59:03 +00:00
p - > size = ( UINT32 ) size ;
p - > fileid = fileid ;
2016-12-31 18:26:33 +00:00
p - > next = NULL ; // End of list
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
DEBFILE ( va ( " Sending ram %p(size:%u) to %d (id=%u) \n " , p - > id . ram , p - > size , node , fileid ) ) ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
filestosend + + ;
2014-03-15 16:59:03 +00:00
}
2020-01-22 22:08:57 +00:00
/** Adds a file requested by Lua to the file list for a node
*
* \ param node The node to send the file to
* \ param filename The file to send
2020-05-12 17:06:40 +00:00
* \ sa AddFileToSendQueue
* \ sa AddRamToSendQueue
2020-01-22 22:08:57 +00:00
*
*/
2020-05-19 19:36:21 +00:00
boolean AddLuaFileToSendQueue ( INT32 node , const char * filename )
2020-01-22 22:08:57 +00:00
{
filetx_t * * q ; // A pointer to the "next" field of the last file in the list
filetx_t * p ; // The new file request
//INT32 i;
//char wadfilename[MAX_WADPATH];
luafiletransfers - > nodestatus [ node ] = LFTNS_SENDING ;
// 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
p = * q = ( filetx_t * ) malloc ( sizeof ( filetx_t ) ) ;
if ( ! p )
2020-05-12 17:06:40 +00:00
I_Error ( " AddLuaFileToSendQueue: No more memory \n " ) ;
2020-01-22 22:08:57 +00:00
// Initialise with zeros
memset ( p , 0 , sizeof ( filetx_t ) ) ;
// Allocate the file name
p - > id . filename = ( char * ) malloc ( MAX_WADPATH ) ; // !!!
if ( ! p - > id . filename )
2020-05-12 17:06:40 +00:00
I_Error ( " AddLuaFileToSendQueue: No more memory \n " ) ;
2020-01-22 22:08:57 +00:00
// Set the file name and get rid of the path
strlcpy ( p - > id . filename , filename , MAX_WADPATH ) ; // !!!
//nameonly(p->id.filename);
DEBFILE ( va ( " Sending Lua file %s to %d \n " , filename , 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 + + ;
return true ;
}
2016-12-31 18:26:33 +00:00
/** 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 )
2014-03-15 16:59:03 +00:00
{
filetx_t * p = transfer [ node ] . txlist ;
2016-12-31 18:26:33 +00:00
2020-05-12 17:06:40 +00:00
// Free the file request according to the freemethod
// parameter used with AddFileToSendQueue/AddRamToSendQueue
2014-03-15 16:59:03 +00:00
switch ( p - > ram )
{
2016-12-31 18:26:33 +00:00
case SF_FILE : // It's a file, close it and free its filename
2017-01-13 19:53:52 +00:00
if ( cv_noticedownload . value )
CONS_Printf ( " Ending file transfer for node %d \n " , node ) ;
2014-03-15 16:59:03 +00:00
if ( transfer [ node ] . currentfile )
fclose ( transfer [ node ] . currentfile ) ;
2016-12-31 18:26:33 +00:00
free ( p - > id . filename ) ;
2014-03-15 16:59:03 +00:00
break ;
2016-12-31 18:26:33 +00:00
case SF_Z_RAM : // It's a memory block allocated with Z_Alloc or the likes, use Z_Free
Z_Free ( p - > id . ram ) ;
2014-03-15 16:59:03 +00:00
break ;
2016-12-31 18:26:33 +00:00
case SF_RAM : // It's a memory block allocated with malloc, use free
free ( p - > id . ram ) ;
case SF_NOFREERAM : // Nothing to free
2014-03-15 16:59:03 +00:00
break ;
}
2016-12-31 18:26:33 +00:00
// Remove the file request from the list
2014-03-15 16:59:03 +00:00
transfer [ node ] . txlist = p - > next ;
free ( p ) ;
2016-12-31 18:26:33 +00:00
// Indicate that the transmission is over
transfer [ node ] . currentfile = NULL ;
2020-05-16 20:09:00 +00:00
if ( transfer [ node ] . ackedfragments )
free ( transfer [ node ] . ackedfragments ) ;
transfer [ node ] . ackedfragments = NULL ;
2016-12-31 18:26:33 +00:00
filestosend - - ;
2014-03-15 16:59:03 +00:00
}
# define PACKETPERTIC net_bandwidth / (TICRATE*software_MAXPACKETLENGTH)
2020-05-16 20:09:00 +00:00
# define FILEFRAGMENTSIZE (software_MAXPACKETLENGTH - (FILETXHEADER + BASEPACKETSIZE))
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
/** Handles file transmission
*
*/
2020-05-12 17:06:40 +00:00
void FileSendTicker ( void )
2014-03-15 16:59:03 +00:00
{
static INT32 currentnode = 0 ;
filetx_pak * p ;
2020-05-12 17:58:16 +00:00
size_t fragmentsize ;
2014-03-15 16:59:03 +00:00
filetx_t * f ;
2017-01-13 19:53:52 +00:00
INT32 packetsent , ram , i , j ;
2014-03-15 16:59:03 +00:00
2021-03-25 21:28:07 +00:00
// If someone is taking too long to download, kick them with a timeout
// to prevent blocking the rest of the server...
if ( luafiletransfers )
{
for ( i = 1 ; i < MAXNETNODES ; i + + )
{
luafiletransfernodestatus_t status = luafiletransfers - > nodestatus [ i ] ;
if ( status ! = LFTNS_NONE & & status ! = LFTNS_WAITING & & status ! = LFTNS_SENT
& & I_GetTime ( ) > luafiletransfers - > nodetimeouts [ i ] )
{
Net_ConnectionTimeout ( i ) ;
}
}
}
2017-01-13 19:53:52 +00:00
if ( ! filestosend ) // No file to send
2014-03-15 16:59:03 +00:00
return ;
2017-01-13 19:53:52 +00:00
2020-05-16 20:09:00 +00:00
if ( cv_downloadspeed . value ) // New behavior
2017-01-13 19:53:52 +00:00
packetsent = cv_downloadspeed . value ;
else // Old behavior
{
packetsent = PACKETPERTIC ;
if ( ! packetsent )
packetsent = 1 ;
}
netbuffer - > packettype = PT_FILEFRAGMENT ;
2014-03-15 16:59:03 +00:00
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
2016-12-31 18:26:33 +00:00
while ( packetsent - - & & filestosend ! = 0 )
2014-03-15 16:59:03 +00:00
{
2017-01-13 19:53:52 +00:00
for ( i = currentnode , j = 0 ; j < MAXNETNODES ;
i = ( i + 1 ) % MAXNETNODES , j + + )
2014-03-15 16:59:03 +00:00
{
if ( transfer [ i ] . txlist )
2020-05-16 20:09:00 +00:00
break ;
2014-03-15 16:59:03 +00:00
}
// no transfer to do
2020-05-16 20:09:00 +00:00
if ( j > = MAXNETNODES )
I_Error ( " filestosend=%d but no file to send found \n " , filestosend ) ;
2014-03-15 16:59:03 +00:00
currentnode = ( i + 1 ) % MAXNETNODES ;
f = transfer [ i ] . txlist ;
ram = f - > ram ;
2016-12-31 18:26:33 +00:00
// Open the file if it isn't open yet, or
if ( ! transfer [ i ] . currentfile )
2014-03-15 16:59:03 +00:00
{
2016-12-31 18:26:33 +00:00
if ( ! ram ) // Sending a file
2014-03-15 16:59:03 +00:00
{
long filesize ;
transfer [ i ] . currentfile =
2020-05-19 19:36:21 +00:00
fopen ( f - > id . filename , " rb " ) ;
2014-03-15 16:59:03 +00:00
if ( ! transfer [ i ] . currentfile )
I_Error ( " File %s does not exist " ,
2016-12-31 18:26:33 +00:00
f - > id . filename ) ;
2014-03-15 16:59:03 +00:00
fseek ( transfer [ i ] . currentfile , 0 , SEEK_END ) ;
filesize = ftell ( transfer [ i ] . currentfile ) ;
// Nobody wants to transfer a file bigger
// than 4GB!
if ( filesize > = LONG_MAX )
2016-12-31 18:26:33 +00:00
I_Error ( " filesize of %s is too large " , f - > id . filename ) ;
if ( filesize = = - 1 )
I_Error ( " Error getting filesize of %s " , f - > id . filename ) ;
2014-03-15 16:59:03 +00:00
f - > size = ( UINT32 ) filesize ;
fseek ( transfer [ i ] . currentfile , 0 , SEEK_SET ) ;
}
2016-12-31 18:26:33 +00:00
else // Sending RAM
transfer [ i ] . currentfile = ( FILE * ) 1 ; // Set currentfile to a non-null value to indicate that it is open
2020-05-16 20:09:00 +00:00
2020-05-20 14:21:18 +00:00
transfer [ i ] . iteration = 1 ;
transfer [ i ] . ackediteration = 0 ;
2014-03-15 16:59:03 +00:00
transfer [ i ] . position = 0 ;
2020-05-16 20:09:00 +00:00
transfer [ i ] . ackedsize = 0 ;
transfer [ i ] . ackedfragments = calloc ( f - > size / FILEFRAGMENTSIZE + 1 , sizeof ( * transfer [ i ] . ackedfragments ) ) ;
if ( ! transfer [ i ] . ackedfragments )
I_Error ( " FileSendTicker: No more memory \n " ) ;
2020-05-20 14:21:18 +00:00
transfer [ i ] . dontsenduntil = 0 ;
2020-05-16 20:09:00 +00:00
}
2020-05-20 14:21:18 +00:00
// If the client hasn't acknowledged any fragment from the previous iteration,
// it is most likely because their acks haven't had enough time to reach the server
// yet, due to latency. In that case, we wait a little to avoid useless resend.
if ( I_GetTime ( ) < transfer [ i ] . dontsenduntil )
continue ;
2020-05-16 20:09:00 +00:00
// Find the first non-acknowledged fragment
while ( transfer [ i ] . ackedfragments [ transfer [ i ] . position / FILEFRAGMENTSIZE ] )
{
transfer [ i ] . position + = FILEFRAGMENTSIZE ;
if ( transfer [ i ] . position > = f - > size )
2020-05-20 14:21:18 +00:00
{
if ( transfer [ i ] . ackediteration < transfer [ i ] . iteration )
transfer [ i ] . dontsenduntil = I_GetTime ( ) + TICRATE / 2 ;
2020-05-16 20:09:00 +00:00
transfer [ i ] . position = 0 ;
2020-05-20 14:21:18 +00:00
transfer [ i ] . iteration + + ;
}
2014-03-15 16:59:03 +00:00
}
2016-12-31 18:26:33 +00:00
// Build a packet containing a file fragment
2014-03-15 16:59:03 +00:00
p = & netbuffer - > u . filetxpak ;
2020-05-16 20:09:00 +00:00
fragmentsize = FILEFRAGMENTSIZE ;
2020-05-12 17:58:16 +00:00
if ( f - > size - transfer [ i ] . position < fragmentsize )
fragmentsize = f - > size - transfer [ i ] . position ;
2014-03-15 16:59:03 +00:00
if ( ram )
2020-05-12 17:58:16 +00:00
M_Memcpy ( p - > data , & f - > id . ram [ transfer [ i ] . position ] , fragmentsize ) ;
2020-01-22 22:08:57 +00:00
else
{
2020-05-16 20:09:00 +00:00
fseek ( transfer [ i ] . currentfile , transfer [ i ] . position , SEEK_SET ) ;
2020-05-19 19:36:21 +00:00
if ( fread ( p - > data , 1 , fragmentsize , transfer [ i ] . currentfile ) ! = fragmentsize )
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 ) ) ;
2020-01-22 22:08:57 +00:00
}
2020-05-20 14:21:18 +00:00
p - > iteration = transfer [ i ] . iteration ;
2014-03-15 16:59:03 +00:00
p - > position = LONG ( transfer [ i ] . position ) ;
p - > fileid = f - > fileid ;
2020-05-16 20:09:00 +00:00
p - > filesize = LONG ( f - > size ) ;
p - > size = SHORT ( ( UINT16 ) FILEFRAGMENTSIZE ) ;
2016-12-31 18:26:33 +00:00
// Send the packet
2020-05-16 20:09:00 +00:00
if ( HSendPacket ( i , false , 0 , FILETXHEADER + fragmentsize ) ) // Don't use the default acknowledgement system
2016-12-31 18:26:33 +00:00
{ // Success
2020-05-12 17:58:16 +00:00
transfer [ i ] . position = ( UINT32 ) ( transfer [ i ] . position + fragmentsize ) ;
2020-05-16 20:09:00 +00:00
if ( transfer [ i ] . position > = f - > size )
2020-05-20 14:21:18 +00:00
{
if ( transfer [ i ] . ackediteration < transfer [ i ] . iteration )
transfer [ i ] . dontsenduntil = I_GetTime ( ) + TICRATE / 2 ;
2020-05-16 20:09:00 +00:00
transfer [ i ] . position = 0 ;
2020-05-20 14:21:18 +00:00
transfer [ i ] . iteration + + ;
}
2016-12-31 18:26:33 +00:00
}
else
{ // 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?)
2014-03-15 16:59:03 +00:00
break ;
}
}
}
2020-05-16 20:09:00 +00:00
void PT_FileAck ( void )
{
fileack_pak * packet = & netbuffer - > u . fileack ;
INT32 node = doomcom - > remotenode ;
filetran_t * trans = & transfer [ node ] ;
INT32 i , j ;
// Wrong file id? Ignore it, it's probably a late packet
if ( ! ( trans - > txlist & & packet - > fileid = = trans - > txlist - > fileid ) )
return ;
if ( packet - > numsegments * sizeof ( * packet - > segments ) ! = doomcom - > datalength - BASEPACKETSIZE - sizeof ( * packet ) )
{
Net_CloseConnection ( node ) ;
return ;
}
2020-05-20 14:21:18 +00:00
if ( packet - > iteration > trans - > ackediteration )
{
trans - > ackediteration = packet - > iteration ;
if ( trans - > ackediteration > = trans - > iteration - 1 )
trans - > dontsenduntil = 0 ;
}
2020-05-16 20:09:00 +00:00
for ( i = 0 ; i < packet - > numsegments ; i + + )
{
fileacksegment_t * segment = & packet - > segments [ i ] ;
for ( j = 0 ; j < 32 ; j + + )
if ( LONG ( segment - > acks ) & ( 1 < < j ) )
{
if ( LONG ( segment - > start ) * FILEFRAGMENTSIZE > = trans - > txlist - > size )
{
Net_CloseConnection ( node ) ;
return ;
}
if ( ! trans - > ackedfragments [ LONG ( segment - > start ) + j ] )
{
trans - > ackedfragments [ LONG ( segment - > start ) + j ] = true ;
trans - > ackedsize + = FILEFRAGMENTSIZE ;
// If the last missing fragment was acked, finish!
if ( trans - > ackedsize = = trans - > txlist - > size )
{
SV_EndFileSend ( node ) ;
return ;
}
}
}
}
}
void PT_FileReceived ( void )
{
filetx_t * trans = transfer [ doomcom - > remotenode ] . txlist ;
if ( trans & & netbuffer - > u . filereceived = = trans - > fileid )
SV_EndFileSend ( doomcom - > remotenode ) ;
}
static void SendAckPacket ( fileack_pak * packet , UINT8 fileid )
{
size_t packetsize ;
INT32 i ;
packetsize = sizeof ( * packet ) + packet - > numsegments * sizeof ( * packet - > segments ) ;
// Finalise the packet
packet - > fileid = fileid ;
for ( i = 0 ; i < packet - > numsegments ; i + + )
{
packet - > segments [ i ] . start = LONG ( packet - > segments [ i ] . start ) ;
packet - > segments [ i ] . acks = LONG ( packet - > segments [ i ] . acks ) ;
}
// Send the packet
netbuffer - > packettype = PT_FILEACK ;
M_Memcpy ( & netbuffer - > u . fileack , packet , packetsize ) ;
HSendPacket ( servernode , false , 0 , packetsize ) ;
// Clear the packet
memset ( packet , 0 , sizeof ( * packet ) + 512 ) ;
}
2020-05-20 14:21:18 +00:00
static void AddFragmentToAckPacket ( fileack_pak * packet , UINT8 iteration , UINT32 fragmentpos , UINT8 fileid )
2020-05-16 20:09:00 +00:00
{
fileacksegment_t * segment = & packet - > segments [ packet - > numsegments - 1 ] ;
2020-05-20 14:21:18 +00:00
packet - > iteration = max ( packet - > iteration , iteration ) ;
2020-05-16 20:09:00 +00:00
if ( packet - > numsegments = = 0
| | fragmentpos < segment - > start
| | fragmentpos - segment - > start > = 32 )
{
// If the packet becomes too big, send it
if ( ( packet - > numsegments + 1 ) * sizeof ( * segment ) > 512 )
SendAckPacket ( packet , fileid ) ;
packet - > numsegments + + ;
segment = & packet - > segments [ packet - > numsegments - 1 ] ;
segment - > start = fragmentpos ;
}
// Set the bit that represents the fragment
segment - > acks | = 1 < < ( fragmentpos - segment - > start ) ;
}
void FileReceiveTicker ( void )
{
INT32 i ;
2020-05-19 09:28:24 +00:00
for ( i = 0 ; i < fileneedednum ; i + + )
{
fileneeded_t * file = & fileneeded [ i ] ;
if ( file - > status = = FS_DOWNLOADING )
{
if ( lasttimeackpacketsent - I_GetTime ( ) > TICRATE / 2 )
SendAckPacket ( file - > ackpacket , i ) ;
// When resuming a tranfer, start with telling
// the server what parts we already received
if ( file - > ackresendposition ! = UINT32_MAX & & file - > status = = FS_DOWNLOADING )
2020-05-16 20:09:00 +00:00
{
2020-05-19 09:28:24 +00:00
// Acknowledge ~70 MB/s, whichs means the client sends ~18 KB/s
INT32 j ;
for ( j = 0 ; j < 2048 ; j + + )
{
if ( file - > receivedfragments [ file - > ackresendposition ] )
2020-05-20 14:21:18 +00:00
AddFragmentToAckPacket ( file - > ackpacket , file - > iteration , file - > ackresendposition , i ) ;
2020-05-19 09:28:24 +00:00
file - > ackresendposition + + ;
if ( file - > ackresendposition * file - > fragmentsize > = file - > totalsize )
{
file - > ackresendposition = UINT32_MAX ;
break ;
}
}
2020-05-16 20:09:00 +00:00
}
2020-05-19 09:28:24 +00:00
}
}
2020-05-16 20:09:00 +00:00
}
2020-05-12 17:06:40 +00:00
void PT_FileFragment ( void )
2014-03-15 16:59:03 +00:00
{
INT32 filenum = netbuffer - > u . filetxpak . fileid ;
2017-01-13 19:53:52 +00:00
fileneeded_t * file = & fileneeded [ filenum ] ;
2020-05-16 20:09:00 +00:00
UINT32 fragmentpos = LONG ( netbuffer - > u . filetxpak . position ) ;
UINT16 fragmentsize = SHORT ( netbuffer - > u . filetxpak . size ) ;
UINT16 boundedfragmentsize = doomcom - > datalength - BASEPACKETSIZE - sizeof ( netbuffer - > u . filetxpak ) ;
2019-08-23 18:00:05 +00:00
char * filename ;
2014-03-15 16:59:03 +00:00
2019-08-23 18:00:05 +00:00
filename = va ( " %s " , file - > filename ) ;
nameonly ( filename ) ;
2017-08-08 08:39:25 +00:00
if ( ! ( strcmp ( filename , " srb2.pk3 " )
2019-09-29 03:31:50 +00:00
& & strcmp ( filename , " zones.pk3 " )
2017-01-13 19:53:52 +00:00
& & strcmp ( filename , " player.dta " )
2019-09-29 03:31:50 +00:00
& & strcmp ( filename , " patch.pk3 " )
2017-01-13 19:53:52 +00:00
& & strcmp ( filename , " music.dta " )
) )
I_Error ( " Tried to download \" %s \" " , filename ) ;
2019-08-23 18:00:05 +00:00
filename = file - > filename ;
2014-03-15 16:59:03 +00:00
if ( filenum > = fileneedednum )
{
2016-12-31 18:26:33 +00:00
DEBFILE ( va ( " fileframent not needed %d>%d \n " , filenum , fileneedednum ) ) ;
2017-01-13 19:53:52 +00:00
//I_Error("Received an unneeded file fragment (file id received: %d, file id needed: %d)\n", filenum, fileneedednum);
2014-03-15 16:59:03 +00:00
return ;
}
2017-01-13 19:53:52 +00:00
if ( file - > status = = FS_REQUESTED )
2014-03-15 16:59:03 +00:00
{
2017-01-13 19:53:52 +00:00
if ( file - > file )
2020-05-12 17:06:40 +00:00
I_Error ( " PT_FileFragment: already open file \n " ) ;
2020-05-16 20:09:00 +00:00
2017-01-13 19:53:52 +00:00
file - > status = FS_DOWNLOADING ;
2020-05-19 09:28:24 +00:00
file - > fragmentsize = fragmentsize ;
2020-05-20 14:21:18 +00:00
file - > iteration = 0 ;
2020-05-16 20:09:00 +00:00
file - > ackpacket = calloc ( 1 , sizeof ( * file - > ackpacket ) + 512 ) ;
2020-05-19 09:28:24 +00:00
if ( ! file - > ackpacket )
2020-05-16 20:09:00 +00:00
I_Error ( " FileSendTicker: No more memory \n " ) ;
2020-05-19 09:28:24 +00:00
if ( CL_CanResumeDownload ( file ) )
{
2020-05-19 19:36:21 +00:00
file - > file = fopen ( filename , " r+b " ) ;
2020-05-19 09:28:24 +00:00
if ( ! file - > file )
I_Error ( " Can't reopen file %s: %s " , filename , strerror ( errno ) ) ;
CONS_Printf ( " \r %s... \n " , filename ) ;
CONS_Printf ( " Resuming download... \n " ) ;
file - > currentsize = pauseddownload - > currentsize ;
file - > receivedfragments = pauseddownload - > receivedfragments ;
file - > ackresendposition = 0 ;
free ( pauseddownload ) ;
pauseddownload = NULL ;
}
else
{
CL_AbortDownloadResume ( ) ;
2020-05-19 19:36:21 +00:00
file - > file = fopen ( filename , " wb " ) ;
2020-05-19 09:28:24 +00:00
if ( ! file - > file )
I_Error ( " Can't create file %s: %s " , filename , strerror ( errno ) ) ;
CONS_Printf ( " \r %s... \n " , filename ) ;
file - > currentsize = 0 ;
file - > totalsize = LONG ( netbuffer - > u . filetxpak . filesize ) ;
file - > ackresendposition = UINT32_MAX ; // Only used for resumed downloads
file - > receivedfragments = calloc ( file - > totalsize / fragmentsize + 1 , sizeof ( * file - > receivedfragments ) ) ;
if ( ! file - > receivedfragments )
I_Error ( " FileSendTicker: No more memory \n " ) ;
}
2020-05-16 20:09:00 +00:00
lasttimeackpacketsent = I_GetTime ( ) ;
2014-03-15 16:59:03 +00:00
}
2017-01-13 19:53:52 +00:00
if ( file - > status = = FS_DOWNLOADING )
2014-03-15 16:59:03 +00:00
{
2020-05-16 20:09:00 +00:00
if ( fragmentpos > = file - > totalsize )
I_Error ( " Invalid file fragment \n " ) ;
2020-05-20 14:21:18 +00:00
file - > iteration = max ( file - > iteration , netbuffer - > u . filetxpak . iteration ) ;
2020-05-16 20:09:00 +00:00
if ( ! file - > receivedfragments [ fragmentpos / fragmentsize ] ) // Not received yet
2014-03-15 16:59:03 +00:00
{
2020-05-16 20:09:00 +00:00
file - > receivedfragments [ fragmentpos / fragmentsize ] = true ;
// We can receive packets in the wrong order, anyway all OSes support gaped files
fseek ( file - > file , fragmentpos , SEEK_SET ) ;
if ( fragmentsize & & fwrite ( netbuffer - > u . filetxpak . data , boundedfragmentsize , 1 , file - > file ) ! = 1 )
I_Error ( " Can't write to %s: %s \n " , filename , M_FileError ( file - > file ) ) ;
file - > currentsize + = boundedfragmentsize ;
2020-05-20 14:21:18 +00:00
AddFragmentToAckPacket ( file - > ackpacket , file - > iteration , fragmentpos / fragmentsize , filenum ) ;
2020-05-16 20:09:00 +00:00
// Finished?
if ( file - > currentsize = = file - > totalsize )
2020-01-22 22:08:57 +00:00
{
2020-05-16 20:09:00 +00:00
fclose ( file - > file ) ;
file - > file = NULL ;
free ( file - > receivedfragments ) ;
free ( file - > ackpacket ) ;
file - > status = FS_FOUND ;
file - > justdownloaded = true ;
CONS_Printf ( M_GetText ( " Downloading %s...(done) \n " ) ,
filename ) ;
2020-02-20 00:15:54 +00:00
// Tell the server we have received the file
2020-05-16 20:09:00 +00:00
netbuffer - > packettype = PT_FILERECEIVED ;
netbuffer - > u . filereceived = filenum ;
HSendPacket ( servernode , true , 0 , 1 ) ;
if ( luafiletransfers )
{
// Tell the server we have received the file
netbuffer - > packettype = PT_HASLUAFILE ;
HSendPacket ( servernode , true , 0 , 0 ) ;
}
2020-01-22 22:08:57 +00:00
}
2014-03-15 16:59:03 +00:00
}
2020-05-16 20:09:00 +00:00
else // Already received
{
// If they are sending us the fragment again, it's probably because
// they missed our previous ack, so we must re-acknowledge it
2020-05-20 14:21:18 +00:00
AddFragmentToAckPacket ( file - > ackpacket , file - > iteration , fragmentpos / fragmentsize , filenum ) ;
2020-05-16 20:09:00 +00:00
}
2014-03-15 16:59:03 +00:00
}
2020-05-16 20:09:00 +00:00
else if ( ! file - > justdownloaded )
2017-01-13 19:53:52 +00:00
{
const char * s ;
switch ( file - > status )
{
case FS_NOTFOUND :
s = " FS_NOTFOUND " ;
break ;
case FS_FOUND :
s = " FS_FOUND " ;
break ;
case FS_OPEN :
s = " FS_OPEN " ;
break ;
case FS_MD5SUMBAD :
s = " FS_MD5SUMBAD " ;
break ;
default :
s = " unknown " ;
break ;
}
I_Error ( " Received a file not requested (file id: %d, file status: %s) \n " , filenum , s ) ;
}
2014-03-15 16:59:03 +00:00
2020-06-27 00:01:16 +00:00
# ifndef NONET
2014-03-15 16:59:03 +00:00
lastfilenum = filenum ;
# endif
}
2017-01-13 19:53:52 +00:00
/** \brief Checks if a node is downloading a file
2016-12-31 18:26:33 +00:00
*
2017-01-13 19:53:52 +00:00
* \ param node The node to check for
* \ return True if the node is downloading a file
2016-12-31 18:26:33 +00:00
*
*/
2020-05-12 17:06:40 +00:00
boolean SendingFile ( INT32 node )
2017-01-13 19:53:52 +00:00
{
return transfer [ node ] . txlist ! = NULL ;
}
/** Cancels all file requests for a node
*
* \ param node The destination
* \ sa SV_EndFileSend
*
*/
2016-12-31 18:26:33 +00:00
void SV_AbortSendFiles ( INT32 node )
2014-03-15 16:59:03 +00:00
{
while ( transfer [ node ] . txlist )
2016-12-31 18:26:33 +00:00
SV_EndFileSend ( node ) ;
2014-03-15 16:59:03 +00:00
}
void CloseNetFile ( void )
{
INT32 i ;
2016-12-31 18:26:33 +00:00
// Is sending?
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < MAXNETNODES ; i + + )
2016-12-31 18:26:33 +00:00
SV_AbortSendFiles ( i ) ;
2014-03-15 16:59:03 +00:00
2016-12-31 18:26:33 +00:00
// Receiving a file?
2014-03-15 16:59:03 +00:00
for ( i = 0 ; i < MAX_WADFILES ; i + + )
2016-12-31 18:26:33 +00:00
if ( fileneeded [ i ] . status = = FS_DOWNLOADING & & fileneeded [ i ] . file )
2014-03-15 16:59:03 +00:00
{
2016-12-31 18:26:33 +00:00
fclose ( fileneeded [ i ] . file ) ;
2020-05-16 20:09:00 +00:00
free ( fileneeded [ i ] . ackpacket ) ;
2014-03-15 16:59:03 +00:00
2020-05-19 09:28:24 +00:00
if ( ! pauseddownload & & i ! = 0 ) // 0 is either srb2.srb or the gamestate...
{
// Don't remove the file, save it for later in case we resume the download
pauseddownload = malloc ( sizeof ( * pauseddownload ) ) ;
if ( ! pauseddownload )
I_Error ( " CloseNetFile: No more memory \n " ) ;
strcpy ( pauseddownload - > filename , fileneeded [ i ] . filename ) ;
memcpy ( pauseddownload - > md5sum , fileneeded [ i ] . md5sum , 16 ) ;
pauseddownload - > currentsize = fileneeded [ i ] . currentsize ;
pauseddownload - > receivedfragments = fileneeded [ i ] . receivedfragments ;
pauseddownload - > fragmentsize = fileneeded [ i ] . fragmentsize ;
}
else
{
free ( fileneeded [ i ] . receivedfragments ) ;
// File is not complete delete it
remove ( fileneeded [ i ] . filename ) ;
}
}
2014-03-15 16:59:03 +00:00
}
2020-05-19 22:24:53 +00:00
void Command_Downloads_f ( void )
{
INT32 node ;
for ( node = 0 ; node < MAXNETNODES ; node + + )
if ( transfer [ node ] . txlist
& & transfer [ node ] . txlist - > ram = = SF_FILE ) // Node is downloading a file?
{
const char * name = transfer [ node ] . txlist - > id . filename ;
2020-06-01 08:37:05 +00:00
UINT32 position = transfer [ node ] . ackedsize ;
2020-05-19 22:24:53 +00:00
UINT32 size = transfer [ node ] . txlist - > size ;
char ratecolor ;
// Avoid division by zero errors
if ( ! size )
size = 1 ;
name = & name [ strlen ( name ) - nameonlylength ( name ) ] ;
switch ( 4 * ( position - 1 ) / size )
{
case 0 : ratecolor = ' \x85 ' ; break ;
case 1 : ratecolor = ' \x87 ' ; break ;
case 2 : ratecolor = ' \x82 ' ; break ;
case 3 : ratecolor = ' \x83 ' ; break ;
default : ratecolor = ' \x80 ' ;
}
CONS_Printf ( " %2d %c%s " , node , ratecolor , name ) ; // Node and file name
CONS_Printf ( " \x80 %uK \x84 / \x80 %uK " , position / 1024 , size / 1024 ) ; // Progress in kB
CONS_Printf ( " \x80 (%c%u%% \x80 ) " , ratecolor , ( UINT32 ) ( 100.0 * position / size ) ) ; // Progress in %
CONS_Printf ( " %s \n " , I_GetNodeAddress ( node ) ) ; // Address and newline
}
}
2016-12-31 18:26:33 +00:00
// Functions cut and pasted from Doomatic :)
2014-03-15 16:59:03 +00:00
void nameonly ( char * s )
{
size_t j , len ;
void * ns ;
for ( j = strlen ( s ) ; j ! = ( size_t ) - 1 ; j - - )
if ( ( s [ j ] = = ' \\ ' ) | | ( s [ j ] = = ' : ' ) | | ( s [ j ] = = ' / ' ) )
{
ns = & ( s [ j + 1 ] ) ;
len = strlen ( ns ) ;
2018-06-18 15:55:34 +00:00
#if 0
M_Memcpy ( s , ns , len + 1 ) ;
# else
memmove ( s , ns , len + 1 ) ;
# endif
2014-03-15 16:59:03 +00:00
return ;
}
}
// Returns the length in characters of the last element of a path.
size_t nameonlylength ( const char * s )
{
size_t j , len = strlen ( s ) ;
for ( j = len ; j ! = ( size_t ) - 1 ; j - - )
if ( ( s [ j ] = = ' \\ ' ) | | ( s [ j ] = = ' : ' ) | | ( s [ j ] = = ' / ' ) )
return len - j - 1 ;
return len ;
}
# ifndef O_BINARY
# define O_BINARY 0
# endif
filestatus_t checkfilemd5 ( char * filename , const UINT8 * wantedmd5sum )
{
2017-09-29 17:19:34 +00:00
# if defined (NOMD5)
2014-03-15 16:59:03 +00:00
( void ) wantedmd5sum ;
( void ) filename ;
# else
FILE * fhandle ;
UINT8 md5sum [ 16 ] ;
if ( ! wantedmd5sum )
return FS_FOUND ;
fhandle = fopen ( filename , " rb " ) ;
if ( fhandle )
{
md5_stream ( fhandle , md5sum ) ;
fclose ( fhandle ) ;
if ( ! memcmp ( wantedmd5sum , md5sum , 16 ) )
return FS_FOUND ;
return FS_MD5SUMBAD ;
}
I_Error ( " Couldn't open %s for md5 check " , filename ) ;
# endif
return FS_FOUND ; // will never happen, but makes the compiler shut up
}
2018-04-15 21:00:31 +00:00
// Rewritten by Monster Iestyn to be less stupid
// Note: if completepath is true, "filename" is modified, but only if FS_FOUND is going to be returned
// (Don't worry about WinCE's version of filesearch, nobody cares about that OS anymore)
2014-03-15 16:59:03 +00:00
filestatus_t findfile ( char * filename , const UINT8 * wantedmd5sum , boolean completepath )
{
2018-04-15 21:00:31 +00:00
filestatus_t homecheck ; // store result of last file search
boolean badmd5 = false ; // store whether md5 was bad from either of the first two searches (if nothing was found in the third)
2014-03-15 16:59:03 +00:00
2018-04-15 21:00:31 +00:00
// first, check SRB2's "home" directory
homecheck = filesearch ( filename , srb2home , wantedmd5sum , completepath , 10 ) ;
2014-03-15 16:59:03 +00:00
2018-04-15 21:00:31 +00:00
if ( homecheck = = FS_FOUND ) // we found the file, so return that we have :)
return FS_FOUND ;
else if ( homecheck = = FS_MD5SUMBAD ) / / file has a bad md5 ; move on and look for a file with the right md5
badmd5 = true ;
// if not found at all, just move on without doing anything
// next, check SRB2's "path" directory
homecheck = filesearch ( filename , srb2path , wantedmd5sum , completepath , 10 ) ;
if ( homecheck = = FS_FOUND ) // we found the file, so return that we have :)
return FS_FOUND ;
else if ( homecheck = = FS_MD5SUMBAD ) / / file has a bad md5 ; move on and look for a file with the right md5
badmd5 = true ;
// if not found at all, just move on without doing anything
// finally check "." directory
homecheck = filesearch ( filename , " . " , wantedmd5sum , completepath , 10 ) ;
if ( homecheck ! = FS_NOTFOUND ) // if not found this time, fall back on the below return statement
return homecheck ; // otherwise return the result we got
return ( badmd5 ? FS_MD5SUMBAD : FS_NOTFOUND ) ; // md5 sum bad or file not found
2014-03-15 16:59:03 +00:00
}
2021-03-23 02:56:55 +00:00
filestatus_t findfolder ( const char * path )
{
// Check the path by itself first.
if ( checkfolderpath ( path , NULL , true ) )
return FS_FOUND ;
# define checkpath(startpath) { \
if ( checkfolderpath ( path , startpath , true ) ) \
return FS_FOUND ; \
}
checkpath ( srb2home ) // Then, look in srb2home.
checkpath ( srb2path ) // Now, look in srb2path.
checkpath ( " . " ) // Finally, look in ".".
# undef checkpath
return FS_NOTFOUND ;
}