void *Sys_LoadDll(const char *name, qboolean useSystemLib) { void *dllhandle = NULL; if(useSystemLib) Com_Printf("Trying to load \"%s\"...\n", name); if(!useSystemLib || !(dllhandle = Sys_LoadLibrary(name))) { const char *topDir; char libPath[MAX_OSPATH]; topDir = Sys_BinaryPath(); if(!*topDir) topDir = "."; Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir); Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name); if(!(dllhandle = Sys_LoadLibrary(libPath))) { const char *basePath = Cvar_VariableString("fs_basepath"); if(!basePath || !*basePath) basePath = "."; if(FS_FilenameCompare(topDir, basePath)) { Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath); Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name); dllhandle = Sys_LoadLibrary(libPath); } if(!dllhandle) { const char *cdPath = Cvar_VariableString("fs_cdpath"); if(!basePath || !*basePath) basePath = "."; if(FS_FilenameCompare(topDir, cdPath)) { Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, cdPath); Com_sprintf(libPath, sizeof(libPath), "%s%c%s", cdPath, PATH_SEP, name); dllhandle = Sys_LoadLibrary(libPath); } if(!dllhandle) { Com_Printf("Loading \"%s\" failed\n", name); } } } } return dllhandle; }
/* ================ FS_InitFilesystem Called only at inital startup, not when the filesystem is resetting due to a game change ================ */ void FS_InitFilesystem( void ) { // allow command line parms to override our defaults // we have to specially handle this, because normal command // line variable sets don't happen until after the filesystem // has already been initialized Com_StartupVariable( "fs_cdpath" ); Com_StartupVariable( "fs_basepath" ); Com_StartupVariable( "fs_homepath" ); Com_StartupVariable( "fs_game" ); Com_StartupVariable( "fs_copyfiles" ); Com_StartupVariable( "fs_dirbeforepak" ); if(!FS_FilenameCompare(Cvar_VariableString("fs_game"), BASEGAME)) Cvar_Set("fs_game", ""); // try to start up normally FS_Startup( BASEGAME ); initialized = qtrue; // if we can't find default.cfg, assume that the paths are // busted and error out now, rather than getting an unreadable // graphics screen when the font fails to load if ( FS_ReadFile( "mpdefault.cfg", NULL ) <= 0 ) { Com_Error( ERR_FATAL, "Couldn't load mpdefault.cfg" ); // bk001208 - SafeMode see below, FIXME? } Q_strncpyz(lastValidBase, fs_basepath->string, sizeof(lastValidBase)); Q_strncpyz(lastValidGame, fs_gamedirvar->string, sizeof(lastValidGame)); // bk001208 - SafeMode see below, FIXME? }
void CL_ParseSetGame( msg_t *msg ) { char newGameDir[MAX_QPATH]; int i = 0; char next; while (i < MAX_QPATH) { next = MSG_ReadByte( msg ); if (next) { //if next is 0 then we have finished reading to the end of the message newGameDir[i] = next; } else { break; } i++; } newGameDir[i] = 0; if(FS_CheckDirTraversal(newGameDir)) { Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", newGameDir); return; } if(!FS_FilenameCompare(newGameDir, BASEGAME)) Cvar_Set("fs_game", ""); else Cvar_Set("fs_game", newGameDir); if(!(Cvar_Flags("fs_game") & CVAR_MODIFIED)) return; //Update the search path for the mod dir FS_UpdateGamedir(); //Now update the overrides manually MSG_CheckNETFPSFOverrides(qfalse); MSG_CheckNETFPSFOverrides(qtrue); }
/* ================== SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client Fill up msg with data ================== */ void SV_WriteDownloadToClient(client_t *cl, msg_t *msg) { int curindex; int rate; int blockspersnap; int unreferenced = 1; char errorMessage[1024]; char pakbuf[MAX_QPATH], *pakptr; int numRefPaks; if (!*cl->downloadName) return; // Nothing being downloaded if(!cl->download) { qboolean idPack = qfalse; #ifndef STANDALONE qboolean missionPack = qfalse; #endif // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); pakptr = strrchr(pakbuf, '.'); if(pakptr) { *pakptr = '\0'; // Check for pk3 filename extension if(!Q_stricmp(pakptr + 1, "pk3")) { const char *referencedPaks = FS_ReferencedPakNames(); // Check whether the file appears in the list of referenced // paks to prevent downloading of arbitrary files. Cmd_TokenizeStringIgnoreQuotes(referencedPaks); numRefPaks = Cmd_Argc(); for(curindex = 0; curindex < numRefPaks; curindex++) { if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf)) { unreferenced = 0; // now that we know the file is referenced, // check whether it's legal to download it. missionPack = FS_idPak(pakbuf, "missionpack"); idPack = missionPack; idPack = (qboolean)(idPack || FS_idPak(pakbuf, "base")); break; } } } } cl->download = 0; // We open the file here if ( !sv_allowDownload->integer || idPack || unreferenced || ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName); } else if (idPack) { Com_Printf("clientDownload: %d : \"%s\" cannot download id pk3 files\n", (int) (cl - svs.clients), cl->downloadName); if(missionPack) { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload Team Arena file \"%s\"\n" "The Team Arena mission pack can be found in your local game store.", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload id pk3 file \"%s\"", cl->downloadName); } } else if ( !sv_allowDownload->integer ) { Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "You will need to get this file elsewhere before you " "can connect to this pure server.\n", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "The server you are connecting to is not a pure server, " "set autodownload to No in your settings and you might be " "able to join the game anyway.\n", cl->downloadName); } } else { // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme? // if the pk3 is referenced, it must have been found somewhere in the filesystem Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName); } MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, 0 ); // client is expecting block zero MSG_WriteLong( msg, -1 ); // illegal file size MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; if(cl->download) FS_FCloseFile(cl->download); return; } Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName ); // Init cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; cl->downloadCount = 0; cl->downloadEOF = qfalse; } // Perform any reads that we need to while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW && cl->downloadSize != cl->downloadCount) { curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) cl->downloadBlocks[curindex] = (unsigned char *)Z_Malloc( MAX_DOWNLOAD_BLKSIZE, TAG_DOWNLOAD, qtrue ); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); if (cl->downloadBlockSize[curindex] < 0) { // EOF right now cl->downloadCount = cl->downloadSize; break; } cl->downloadCount += cl->downloadBlockSize[curindex]; // Load in next block cl->downloadCurrentBlock++; } // Check to see if we have eof condition and add the EOF block if (cl->downloadCount == cl->downloadSize && !cl->downloadEOF && cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) { cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0; cl->downloadCurrentBlock++; cl->downloadEOF = qtrue; // We have added the EOF block } // Loop up to window size times based on how many blocks we can fit in the // client snapMsec and rate // based on the rate, how many bytes can we fit in the snapMsec time of the client // normal rate / snapshotMsec calculation rate = cl->rate; if ( sv_maxRate->integer ) { if ( sv_maxRate->integer < 1000 ) { Cvar_Set( "sv_MaxRate", "1000" ); } if ( sv_maxRate->integer < rate ) { rate = sv_maxRate->integer; } } if (!rate) { blockspersnap = 1; } else { blockspersnap = ( (rate * cl->snapshotMsec) / 1000 + MAX_DOWNLOAD_BLKSIZE ) / MAX_DOWNLOAD_BLKSIZE; } if (blockspersnap < 0) blockspersnap = 1; while (blockspersnap--) { // Write out the next section of the file, if we have already reached our window, // automatically start retransmitting if (cl->downloadClientBlock == cl->downloadCurrentBlock) return; // Nothing to transmit if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { // We have transmitted the complete window, should we start resending? //FIXME: This uses a hardcoded one second timeout for lost blocks //the timeout should be based on client rate somehow if (svs.time - cl->downloadSendTime > 1000) cl->downloadXmitBlock = cl->downloadClientBlock; else return; } // Send current block curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, cl->downloadXmitBlock ); // block zero is special, contains file size if ( cl->downloadXmitBlock == 0 ) MSG_WriteLong( msg, cl->downloadSize ); MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); // Write the block if ( cl->downloadBlockSize[curindex] ) { MSG_WriteData( msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex] ); } Com_DPrintf( "clientDownload: %d : writing block %d\n", cl - svs.clients, cl->downloadXmitBlock ); // Move on to the next block // It will get sent with next snap shot. The rate will keep us in line. cl->downloadXmitBlock++; cl->downloadSendTime = svs.time; } }
/* ================== CL_SystemInfoChanged The systeminfo configstring has been changed, so parse new information out of it. This will happen at every gamestate, and possibly during gameplay. ================== */ void CL_SystemInfoChanged( void ) { char *systemInfo; const char *s, *t; char key[BIG_INFO_KEY]; char value[BIG_INFO_VALUE]; qboolean gameSet; systemInfo = cl.gameState.stringData + cl.gameState.stringOffsets[ CS_SYSTEMINFO ]; // NOTE TTimo: // when the serverId changes, any further messages we send to the server will use this new serverId // https://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=475 // in some cases, outdated cp commands might get sent with this new serverId cl.serverId = atoi( Info_ValueForKey( systemInfo, "sv_serverid" ) ); // don't set any vars when playing a demo if ( clc.demoplaying ) { return; } s = Info_ValueForKey( systemInfo, "sv_cheats" ); cl_connectedToCheatServer = atoi( s ); if ( !cl_connectedToCheatServer ) { Cvar_SetCheatState(); } // check pure server string s = Info_ValueForKey( systemInfo, "sv_paks" ); t = Info_ValueForKey( systemInfo, "sv_pakNames" ); FS_PureServerSetLoadedPaks( s, t ); s = Info_ValueForKey( systemInfo, "sv_referencedPaks" ); t = Info_ValueForKey( systemInfo, "sv_referencedPakNames" ); FS_PureServerSetReferencedPaks( s, t ); gameSet = qfalse; // scan through all the variables in the systeminfo and locally set cvars to match s = systemInfo; while ( s ) { Info_NextPair( &s, key, value ); if ( !key[0] ) { break; } // ehw! if ( !Q_stricmp( key, "fs_game" ) ) { if(FS_CheckDirTraversal(value)) { Com_Printf(S_COLOR_YELLOW "WARNING: Server sent invalid fs_game value %s\n", value); continue; } if(!FS_FilenameCompare(value, BASEGAME)) { Com_Printf(S_COLOR_YELLOW "WARNING: Server sent \"%s\" fs_game value, clearing.\n", value); Q_strncpyz(value, "", sizeof(value)); } gameSet = qtrue; } Cvar_Server_Set( key, value ); } // if game folder should not be set and it is set at the client side if ( !gameSet && *Cvar_VariableString("fs_game") ) { Cvar_Set( "fs_game", "" ); } cl_connectedToPureServer = Cvar_VariableValue( "sv_pure" ); }
/* ================== SV_WriteDownloadToClient Check to see if the client wants a file, open it if needed and start pumping the client Fill up msg with data, return number of download blocks added ================== */ int SV_WriteDownloadToClient(client_t *cl, msg_t *msg) { int curindex; int unreferenced = 1; char errorMessage[1024]; char pakbuf[MAX_QPATH], *pakptr; int numRefPaks; if (!*cl->downloadName) return 0; // Nothing being downloaded if(!cl->download) { qboolean idPack = qfalse; // Chop off filename extension. Com_sprintf(pakbuf, sizeof(pakbuf), "%s", cl->downloadName); pakptr = strrchr(pakbuf, '.'); if(pakptr) { *pakptr = '\0'; // Check for pk3 filename extension if(!Q_stricmp(pakptr + 1, "pk3")) { const char *referencedPaks = FS_ReferencedPakNames(); // Check whether the file appears in the list of referenced // paks to prevent downloading of arbitrary files. Cmd_TokenizeStringIgnoreQuotes(referencedPaks); numRefPaks = Cmd_Argc(); for(curindex = 0; curindex < numRefPaks; curindex++) { if(!FS_FilenameCompare(Cmd_Argv(curindex), pakbuf)) { unreferenced = 0; // now that we know the file is referenced, // check whether it's legal to download it. idPack = idPack || FS_idPak(pakbuf, BASEGAME, NUM_RV_PAKS); break; } } } } cl->download = 0; // We open the file here if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) || idPack || unreferenced || ( cl->downloadSize = FS_SV_FOpenFileRead( cl->downloadName, &cl->download ) ) < 0 ) { // cannot auto-download file if(unreferenced) { Com_Printf("clientDownload: %d : \"%s\" is not referenced and cannot be downloaded.\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" is not referenced and cannot be downloaded.", cl->downloadName); } else if (idPack) { Com_Printf("clientDownload: %d : \"%s\" cannot download raven jk3 pk3 files\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "Cannot autodownload raven jk3 pk3 file \"%s\"", cl->downloadName); } else if ( !(sv_allowDownload->integer & DLF_ENABLE) || (sv_allowDownload->integer & DLF_NO_UDP) ) { Com_Printf("clientDownload: %d : \"%s\" download disabled\n", (int) (cl - svs.clients), cl->downloadName); if (sv_pure->integer) { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "You will need to get this file elsewhere before you " "can connect to this pure server.\n", cl->downloadName); } else { Com_sprintf(errorMessage, sizeof(errorMessage), "Could not download \"%s\" because autodownloading is disabled on the server.\n\n" "The server you are connecting to is not a pure server, " "set autodownload to No in your settings and you might be " "able to join the game anyway.\n", cl->downloadName); } } else { // NOTE TTimo this is NOT supposed to happen unless bug in our filesystem scheme? // if the pk3 is referenced, it must have been found somewhere in the filesystem Com_Printf("clientDownload: %d : \"%s\" file not found on server\n", (int) (cl - svs.clients), cl->downloadName); Com_sprintf(errorMessage, sizeof(errorMessage), "File \"%s\" not found on server for autodownloading.\n", cl->downloadName); } MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, 0 ); // client is expecting block zero MSG_WriteLong( msg, -1 ); // illegal file size MSG_WriteString( msg, errorMessage ); *cl->downloadName = 0; if(cl->download) FS_FCloseFile(cl->download); return 0; } Com_Printf( "clientDownload: %d : beginning \"%s\"\n", (int) (cl - svs.clients), cl->downloadName ); // Init cl->downloadCurrentBlock = cl->downloadClientBlock = cl->downloadXmitBlock = 0; cl->downloadCount = 0; cl->downloadEOF = qfalse; } // Perform any reads that we need to while (cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW && cl->downloadSize != cl->downloadCount) { curindex = (cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW); if (!cl->downloadBlocks[curindex]) cl->downloadBlocks[curindex] = Z_Malloc(MAX_DOWNLOAD_BLKSIZE); cl->downloadBlockSize[curindex] = FS_Read( cl->downloadBlocks[curindex], MAX_DOWNLOAD_BLKSIZE, cl->download ); if (cl->downloadBlockSize[curindex] < 0) { // EOF right now cl->downloadCount = cl->downloadSize; break; } cl->downloadCount += cl->downloadBlockSize[curindex]; // Load in next block cl->downloadCurrentBlock++; } // Check to see if we have eof condition and add the EOF block if (cl->downloadCount == cl->downloadSize && !cl->downloadEOF && cl->downloadCurrentBlock - cl->downloadClientBlock < MAX_DOWNLOAD_WINDOW) { cl->downloadBlockSize[cl->downloadCurrentBlock % MAX_DOWNLOAD_WINDOW] = 0; cl->downloadCurrentBlock++; cl->downloadEOF = qtrue; // We have added the EOF block } if (cl->downloadClientBlock == cl->downloadCurrentBlock) return 0; // Nothing to transmit // Write out the next section of the file, if we have already reached our window, // automatically start retransmitting if (cl->downloadXmitBlock == cl->downloadCurrentBlock) { // We have transmitted the complete window, should we start resending? if (svs.time - cl->downloadSendTime > 1000) cl->downloadXmitBlock = cl->downloadClientBlock; else return 0; } // Send current block curindex = (cl->downloadXmitBlock % MAX_DOWNLOAD_WINDOW); MSG_WriteByte( msg, svc_download ); MSG_WriteShort( msg, cl->downloadXmitBlock ); // block zero is special, contains file size if ( cl->downloadXmitBlock == 0 ) MSG_WriteLong( msg, cl->downloadSize ); MSG_WriteShort( msg, cl->downloadBlockSize[curindex] ); // Write the block if(cl->downloadBlockSize[curindex]) MSG_WriteData(msg, cl->downloadBlocks[curindex], cl->downloadBlockSize[curindex]); Com_DPrintf( "clientDownload: %d : writing block %d\n", (int) (cl - svs.clients), cl->downloadXmitBlock ); // Move on to the next block // It will get sent with next snap shot. The rate will keep us in line. cl->downloadXmitBlock++; cl->downloadSendTime = svs.time; return 1; }
void *Sys_LoadDll(const char *name, qboolean useSystemLib) { void *dllhandle = NULL; if(!Sys_DllExtension(name)) { Com_Printf("Refusing to attempt to load library \"%s\": Extension not allowed.\n", name); return NULL; } if(useSystemLib) { Com_Printf("Trying to load \"%s\"...\n", name); dllhandle = Sys_LoadLibrary(name); } if(!dllhandle) { const char *topDir; char libPath[MAX_OSPATH]; int len; topDir = Sys_BinaryPath(); if(!*topDir) topDir = "."; len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", topDir, PATH_SEP, name); if(len < sizeof(libPath)) { Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, topDir); dllhandle = Sys_LoadLibrary(libPath); } else { Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, topDir); } if(!dllhandle) { const char *basePath = Cvar_VariableString("fs_basepath"); if(!basePath || !*basePath) basePath = "."; if(FS_FilenameCompare(topDir, basePath)) { len = Com_sprintf(libPath, sizeof(libPath), "%s%c%s", basePath, PATH_SEP, name); if(len < sizeof(libPath)) { Com_Printf("Trying to load \"%s\" from \"%s\"...\n", name, basePath); dllhandle = Sys_LoadLibrary(libPath); } else { Com_Printf("Skipping trying to load \"%s\" from \"%s\", file name is too long.\n", name, basePath); } } if(!dllhandle) Com_Printf("Loading \"%s\" failed\n", name); } } return dllhandle; }