/* * SV_Download_f * Download command issued from server */ static void SV_Download_f( void ) { qboolean success; char *s; char url[MAX_STRING_CHARS], filepath[MAX_QPATH], writepath[MAX_QPATH]; if( Cmd_Argc() != 2 ) { Com_Printf( "Usage: %s <url>\n", Cmd_Argv( 0 ) ); Com_Printf( "Downloads .pk3 or .pak from URL to gamedir and adds it to the server\n" ); Com_Printf( "Note, server will not function properly while downloading\n" ); return; } s = Cmd_Argv( 1 ); if( !Com_GlobMatch( "*://*", s, qfalse ) ) Q_strncpyz( url, "http://", sizeof( url ) ); else url[0] = 0; Q_strncatz( url, s, sizeof( url ) ); s = strrchr( url, '/' ); if( !s ) { Com_Printf( "%s: invalid URL\n", Cmd_Argv( 0 ) ); return; } Q_strncpyz( filepath, va( "%s/%s", FS_GameDirectory(), s + 1 ), sizeof( filepath ) ); Q_strncpyz( writepath, va( "%s.tmp", filepath ), sizeof( writepath ) ); if( !FS_CheckPakExtension( writepath ) ) { Com_Printf( "Missing or invalid archive extension. Only download of pack files is supported\n" ); return; } Com_Printf( "download url: %s\n", url ); webDownloadPercentPrint = 0; success = Web_Get( url, NULL, writepath, qtrue, 60 * 30, 60, SV_WebDownloadProgress, qfalse ); if( !success ) { Com_Printf( "Server web download failed\n" ); return; } if( !FS_MoveBaseFile( writepath, filepath ) ) { Com_Printf( "Couldn't rename the downloaded file. Download failed\n" ); return; } Com_Printf( "Download successful\n" ); // update the map list, which also does a filesystem rescan ML_Update(); }
static int Dynvar_Console( void *dynvar, void *pattern ) { const dynvar_t *const var = ( (dynvar_t *) dynvar ); assert( var ); return var->console && ( !pattern || Com_GlobMatch( (const char *) pattern, var->name, qfalse ) ); }
/* * Sys_FS_FindNext */ const char *Sys_FS_FindNext( unsigned musthave, unsigned canhave ) { struct dirent64 *d; assert( fdir ); assert( findbase && findpattern ); if( !fdir ) return NULL; while( ( d = readdir64( fdir ) ) != NULL ) { if( !CompareAttributes( d, findbase, musthave, canhave ) ) continue; if( fdots > 0 ) { // . and .. never match const char *base = COM_FileBase( d->d_name ); if( !strcmp( base, "." ) || !strcmp( base, ".." ) ) { fdots--; continue; } } if( !*findpattern || Com_GlobMatch( findpattern, d->d_name, 0 ) ) { const char *dname = d->d_name; size_t dname_len = strlen( dname ); size_t size = sizeof( char ) * ( findbase_size + dname_len + 1 + 1 ); if( findpath_size < size ) { if( findpath ) Mem_TempFree( findpath ); findpath_size = size * 2; // extra size to reduce reallocs findpath = Mem_TempMalloc( findpath_size ); } Q_snprintfz( findpath, findpath_size, "%s/%s%s", findbase, dname, dname[dname_len-1] != '/' && FS_DirentIsDir( d, findbase ) ? "/" : "" ); if( CompareAttributesForPath( d, findpath, musthave, canhave ) ) return findpath; } } return NULL; }
static int ML_PatternMatchesMap( void *map, void *pattern ) { assert( map ); return !pattern || Com_GlobMatch( (const char *) pattern, ( (mapinfo_t *) map )->filename, false ); }
/* * TV_Upstream_NextDemo */ void TV_Upstream_NextDemo( const char *demoname, const char *curdemo, qboolean randomize, char **name, char **filepath ) { int i, j, total; size_t bufsize, len, dir_size; char *file, *buf, **match, *dir; const char *extension, *pattern, *p; *name = *filepath = NULL; assert( demoname ); assert( *demoname ); buf = NULL; bufsize = 0; total = 0; // check if user specified a demo pattern (e.g. "tutorials/*.wd10") or a demolist filename extension = COM_FileExtension( demoname ); if( extension && !Q_stricmp( extension, APP_DEMO_EXTENSION_STR ) ) pattern = demoname; else pattern = ""; dir_size = strlen( "demos" ) + strlen( pattern ) + 1; dir = Mem_TempMalloc( dir_size ); strcpy( dir, "demos" ); if( *pattern ) { // find first character that looks like a wildcard const char *last_slash = NULL; p = pattern; do { if( *p == '/' ) last_slash = p; else if( *p == '?' || *p == '*' || *p == '[' ) break; } while( *++p ); // append the path part of wildcard to dir and shift the pattern if( last_slash ) { Q_strncatz( dir, "/", dir_size ); Q_strncatz( dir, pattern, strlen( dir ) + (last_slash - pattern) + 1 ); pattern = last_slash + 1; } bufsize = 0; total = FS_GetFileListExt( dir, APP_DEMO_EXTENSION_STR, NULL, &bufsize, 0, 0 ); if( !total ) bufsize = 0; if( bufsize ) { buf = Mem_TempMalloc( bufsize ); FS_GetFileList( dir, APP_DEMO_EXTENSION_STR, buf, bufsize, 0, 0 ); } } else { // load demolist file and pick next available demo int filehandle = 0, filelen = -1; // load list from file filelen = FS_FOpenFile( demoname, &filehandle, FS_READ ); if( filehandle && filelen > 0 ) { bufsize = (size_t)(filelen + 1); buf = Mem_TempMalloc( bufsize ); FS_Read( buf, filelen, filehandle ); FS_FCloseFile( filehandle ); } // parse the list stripping CRLF characters if( buf ) { p = strtok( buf, "\r\n" ); if( p ) { char *newbuf; size_t newbufsize; newbufsize = 0; newbuf = Mem_TempMalloc( bufsize ); while( p != NULL ) { total++; Q_strncpyz( newbuf + newbufsize, p, bufsize - newbufsize ); newbufsize += strlen( p ) + 1; p = strtok( NULL, "\r\n" ); } Mem_TempFree( buf ); buf = newbuf; } } } if( buf ) { int next; // get the list of demo files match = Mem_TempMalloc( total * sizeof( char * ) ); total = 0; next = (randomize ? -1 : 0); for( len = 0; buf[len]; ) { file = buf + len; len += strlen( file ) + 1; if( *pattern ) { if( !Com_GlobMatch( pattern, file, qfalse ) ) continue; } // avoid replays if( curdemo && !Q_stricmp( file, curdemo ) ) { // if ordered, schedule the next map if( !randomize ) next = total; continue; } match[total++] = file; } // pick a new random demo if possible or otherwise try the old one if( total ) { if( next < 0 ) next = rand() % total; // walk the list until we find an existing file // in case of pattern match, the check is not necessary though for( i = 0; i < total; i++ ) { j = (i + next) % total; if( !*pattern ) { extension = COM_FileExtension( match[j] ); if( FS_FOpenFile( va( "demos/%s%s", match[j], (extension ? "" : APP_DEMO_EXTENSION_STR) ), NULL, FS_READ ) == -1 ) continue; } *name = TempCopyString( match[j] ); break; } } // fallback to current demo if( !*name && curdemo ) *name = TempCopyString( curdemo ); Mem_TempFree( match ); // append the dir to filename, sigh.. if( *name ) { size_t filepath_size; filepath_size = strlen( dir ) + strlen( "/" ) + strlen( *name ) + strlen( APP_DEMO_EXTENSION_STR ) + 1; *filepath = Mem_TempMalloc( filepath_size ); strcpy( *filepath, dir ); strcat( *filepath, "/" ); strcat( *filepath, *name ); COM_DefaultExtension( *filepath, APP_DEMO_EXTENSION_STR, filepath_size ); } Mem_TempFree( buf ); } Mem_TempFree( dir ); }
static int Cvar_PatternMatches( void *cvar, void *pattern ) { return !pattern || Com_GlobMatch( (const char *) pattern, ( (cvar_t *) cvar )->name, qfalse ); }
/* * TV_Upstream_ParseConfigstringCommand_f */ static void TV_Upstream_HandleConfigstring( upstream_t *upstream, int index, const char *val ) { char hostname[MAX_CONFIGSTRING_CHARS]; msg_t msg; qbyte msgbuf[MAX_MSGLEN]; if( !val || !val[0] ) return; if( index < 0 || index >= MAX_CONFIGSTRINGS ) TV_Upstream_Error( upstream, "configstring > MAX_CONFIGSTRINGS" ); Q_strncpyz( upstream->configstrings[index], val, sizeof( upstream->configstrings[index] ) ); if( index == CS_AUTORECORDSTATE ) { // don't do a thing until we receive a "precache" command if( upstream->precacheDone ) TV_Upstream_AutoRecordAction( upstream, upstream->configstrings[CS_AUTORECORDSTATE] ); return; } if( index != CS_HOSTNAME ) return; if( !upstream->demo.playing ) { TV_Upstream_SetName( upstream, val ); return; } // demos often come with generic hostnames, attempt to workaround that if( !Q_stricmp( val, APPLICATION " server" ) ) { char *temp; size_t temp_size; const char *filebase; filebase = COM_FileBase( upstream->demo.filename ); temp_size = strlen( filebase ) + strlen( APP_DEMO_EXTENSION_STR ) + 1; temp = Mem_TempMalloc( temp_size ); Q_strncpyz( temp, filebase, temp_size ); COM_ReplaceExtension( temp, APP_DEMO_EXTENSION_STR, temp_size ); if( Com_GlobMatch( "*_auto[0-9][0-9][0-9][0-9]" APP_DEMO_EXTENSION_STR, temp, qfalse ) || Com_GlobMatch( "*_mvd" APP_DEMO_EXTENSION_STR, temp, qfalse ) ) temp[strrchr( temp, '_' ) - temp] = '\0'; else COM_StripExtension( temp ); Q_strncpyz( hostname, va( S_COLOR_ORANGE "R: " S_COLOR_WHITE "%s", temp ), sizeof( hostname ) ); Mem_TempFree( temp ); } else { Q_strncpyz( hostname, va( S_COLOR_ORANGE "R: " S_COLOR_WHITE "%s", val ), sizeof( hostname ) ); } TV_Upstream_SetName( upstream, hostname ); // override CS_HOSTNAME in next packet MSG_Init( &msg, msgbuf, sizeof( msgbuf ) ); MSG_WriteByte( &msg, svc_servercs ); MSG_WriteString( &msg, va( "cs %i \"%s\"", CS_HOSTNAME, hostname ) ); TV_Upstream_SavePacket( upstream, &msg, 0 ); }
/* * SV_Init * * Only called at plat.exe startup, not for each game */ void SV_Init( void ) { cvar_t *sv_pps; cvar_t *sv_fps; assert( !sv_initialized ); memset( &svc, 0, sizeof( svc ) ); SV_InitOperatorCommands(); sv_mempool = Mem_AllocPool( NULL, "Server" ); Cvar_Get( "sv_cheats", "0", CVAR_SERVERINFO | CVAR_LATCH ); Cvar_Get( "protocol", va( "%i", APP_PROTOCOL_VERSION ), CVAR_SERVERINFO | CVAR_NOSET ); sv_ip = Cvar_Get( "sv_ip", "", CVAR_ARCHIVE | CVAR_LATCH ); sv_port = Cvar_Get( "sv_port", va( "%i", PORT_SERVER ), CVAR_ARCHIVE | CVAR_LATCH ); sv_ip6 = Cvar_Get( "sv_ip6", "::", CVAR_ARCHIVE | CVAR_LATCH ); sv_port6 = Cvar_Get( "sv_port6", va( "%i", PORT_SERVER ), CVAR_ARCHIVE | CVAR_LATCH ); #ifdef TCP_SUPPORT sv_tcp = Cvar_Get( "sv_tcp", "1", CVAR_SERVERINFO | CVAR_ARCHIVE | CVAR_LATCH ); #endif rcon_password = Cvar_Get( "rcon_password", "", 0 ); sv_hostname = Cvar_Get( "sv_hostname", APPLICATION " server", CVAR_SERVERINFO | CVAR_ARCHIVE ); sv_timeout = Cvar_Get( "sv_timeout", "125", 0 ); sv_zombietime = Cvar_Get( "sv_zombietime", "2", 0 ); sv_enforcetime = Cvar_Get( "sv_enforcetime", "1", 0 ); sv_showclamp = Cvar_Get( "sv_showclamp", "0", 0 ); sv_showRcon = Cvar_Get( "sv_showRcon", "1", 0 ); sv_showChallenge = Cvar_Get( "sv_showChallenge", "0", 0 ); sv_showInfoQueries = Cvar_Get( "sv_showInfoQueries", "0", 0 ); sv_highchars = Cvar_Get( "sv_highchars", "1", 0 ); sv_uploads_baseurl = Cvar_Get( "sv_uploads_baseurl", "", CVAR_ARCHIVE ); sv_uploads_demos_baseurl = Cvar_Get( "sv_uploads_demos_baseurl", "", CVAR_ARCHIVE ); if( dedicated->integer ) { sv_uploads = Cvar_Get( "sv_uploads", "1", CVAR_READONLY ); sv_uploads_from_server = Cvar_Get( "sv_uploads_from_server", "1", CVAR_READONLY ); sv_autoUpdate = Cvar_Get( "sv_autoUpdate", "1", CVAR_ARCHIVE ); sv_pure = Cvar_Get( "sv_pure", "1", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO ); #ifdef PUBLIC_BUILD sv_public = Cvar_Get( "sv_public", "1", CVAR_ARCHIVE | CVAR_LATCH ); #else sv_public = Cvar_Get( "sv_public", "0", CVAR_ARCHIVE | CVAR_LATCH ); #endif } else { sv_uploads = Cvar_Get( "sv_uploads", "1", CVAR_ARCHIVE ); sv_uploads_from_server = Cvar_Get( "sv_uploads_from_server", "1", CVAR_ARCHIVE ); sv_autoUpdate = Cvar_Get( "sv_autoUpdate", "0", CVAR_READONLY ); sv_pure = Cvar_Get( "sv_pure", "0", CVAR_ARCHIVE | CVAR_LATCH | CVAR_SERVERINFO ); sv_public = Cvar_Get( "sv_public", "0", CVAR_ARCHIVE ); } sv_iplimit = Cvar_Get( "sv_iplimit", "3", CVAR_ARCHIVE ); sv_lastAutoUpdate = Cvar_Get( "sv_lastAutoUpdate", "0", CVAR_READONLY|CVAR_ARCHIVE ); sv_pure_forcemodulepk3 = Cvar_Get( "sv_pure_forcemodulepk3", "", CVAR_LATCH ); sv_defaultmap = Cvar_Get( "sv_defaultmap", "wdm1", CVAR_ARCHIVE ); sv_write_defaultmap = Cvar_Get( "sv_write_defaultmap", "0", CVAR_ARCHIVE ); sv_reconnectlimit = Cvar_Get( "sv_reconnectlimit", "3", CVAR_ARCHIVE ); sv_maxclients = Cvar_Get( "sv_maxclients", "8", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_LATCH ); sv_maxmvclients = Cvar_Get( "sv_maxmvclients", "4", CVAR_ARCHIVE | CVAR_SERVERINFO ); Cvar_Get( "sv_modmanifest", "", CVAR_READONLY ); Cvar_ForceSet( "sv_modmanifest", "" ); // fix invalid sv_maxclients values if( sv_maxclients->integer < 1 ) Cvar_FullSet( "sv_maxclients", "1", CVAR_ARCHIVE|CVAR_SERVERINFO|CVAR_LATCH, qtrue ); else if( sv_maxclients->integer > MAX_CLIENTS ) Cvar_FullSet( "sv_maxclients", va( "%i", MAX_CLIENTS ), CVAR_ARCHIVE|CVAR_SERVERINFO|CVAR_LATCH, qtrue ); sv_demodir = Cvar_Get( "sv_demodir", "", CVAR_NOSET ); if( sv_demodir->string[0] && Com_GlobMatch( "*[^0-9a-zA-Z_@]*", sv_demodir->string, qfalse ) ) { Com_Printf( "Invalid demo prefix string: %s\n", sv_demodir->string ); Cvar_ForceSet( "sv_demodir", "" ); } // wsw : jal : cap client's exceding server rules sv_maxrate = Cvar_Get( "sv_maxrate", "0", CVAR_DEVELOPER ); sv_compresspackets = Cvar_Get( "sv_compresspackets", "1", CVAR_DEVELOPER ); sv_skilllevel = Cvar_Get( "sv_skilllevel", "1", CVAR_SERVERINFO|CVAR_ARCHIVE|CVAR_LATCH ); if( sv_skilllevel->integer > 2 ) Cvar_ForceSet( "sv_skilllevel", "2" ); if( sv_skilllevel->integer < 0 ) Cvar_ForceSet( "sv_skilllevel", "0" ); sv_masterservers = Cvar_Get( "masterservers", DEFAULT_MASTER_SERVERS_IPS, CVAR_LATCH ); sv_debug_serverCmd = Cvar_Get( "sv_debug_serverCmd", "0", CVAR_ARCHIVE ); sv_MOTD = Cvar_Get( "sv_MOTD", "0", CVAR_ARCHIVE ); sv_MOTDFile = Cvar_Get( "sv_MOTDFile", "", CVAR_ARCHIVE ); sv_MOTDString = Cvar_Get( "sv_MOTDString", "", CVAR_ARCHIVE ); SV_MOTD_Update(); // this is a message holder for shared use MSG_Init( &tmpMessage, tmpMessageData, sizeof( tmpMessageData ) ); // init server updates ratio if( dedicated->integer ) sv_pps = Cvar_Get( "sv_pps", "20", CVAR_SERVERINFO|CVAR_NOSET ); else sv_pps = Cvar_Get( "sv_pps", "20", CVAR_SERVERINFO ); svc.snapFrameTime = (int)( 1000 / sv_pps->value ); if( svc.snapFrameTime > 200 ) { // too slow, also, netcode uses a byte Cvar_ForceSet( "sv_pps", "5" ); svc.snapFrameTime = 200; } else if( svc.snapFrameTime < 10 ) { // abusive Cvar_ForceSet( "sv_pps", "100" ); svc.snapFrameTime = 10; } sv_fps = Cvar_Get( "sv_fps", "62", CVAR_NOSET ); svc.gameFrameTime = (int)( 1000 / sv_fps->value ); if( svc.gameFrameTime > svc.snapFrameTime ) { // gamecode can never be slower than snaps svc.gameFrameTime = svc.snapFrameTime; Cvar_ForceSet( "sv_fps", sv_pps->dvalue ); } Com_Printf( "Game running at %i fps. Server transmit at %i pps\n", sv_fps->integer, sv_pps->integer ); //init the master servers list SV_InitMaster(); SV_MM_Init(); ML_Init(); sv_initialized = qtrue; }