/* * CL_WriteServerCache */ void CL_WriteServerCache( void ) { serverlist_t *server; int filehandle; char str[256]; netadr_t adr; if( FS_FOpenFile( SERVERSFILE, &filehandle, FS_WRITE ) == -1 ) { Com_Printf( "CL_WriteServerList: Couldn't create the cache file\n" ); return; } Q_snprintfz( str, sizeof( str ), "// servers cache file generated by %s. Do not modify\n", APPLICATION ); FS_Print( filehandle, str ); FS_Print( filehandle, "master\n" ); server = masterList; while( server ) { if( server->lastValidPing + 7 > Com_DaysSince1900() ) { if( NET_StringToAddress( server->address, &adr ) ) { Q_snprintfz( str, sizeof( str ), "%s %i\n", server->address, (int)server->lastValidPing ); FS_Print( filehandle, str ); } } server = server->pnext; } FS_Print( filehandle, "favorites\n" ); server = favoritesList; while( server ) { if( server->lastValidPing + 7 > Com_DaysSince1900() ) { if( NET_StringToAddress( server->address, &adr ) ) { Q_snprintfz( str, sizeof( str ), "%s %i\n", server->address, (int)server->lastValidPing ); FS_Print( filehandle, str ); } } server = server->pnext; } FS_FCloseFile( filehandle ); }
/* * CL_ParseStatusMessage * Handle a reply from a ping */ void CL_ParseStatusMessage( const socket_t *socket, const netadr_t *address, msg_t *msg ) { char *s = MSG_ReadString( msg ); serverlist_t *pingserver; char adrString[64]; Com_DPrintf( "%s\n", s ); Q_strncpyz( adrString, NET_AddressToString( address ), sizeof( adrString ) ); // ping response pingserver = CL_ServerFindInList( masterList, adrString ); if( !pingserver ) pingserver = CL_ServerFindInList( favoritesList, adrString ); if( pingserver && pingserver->pingTimeStamp ) // valid ping { unsigned int ping = Sys_Milliseconds() - pingserver->pingTimeStamp; CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) ); pingserver->pingTimeStamp = 0; pingserver->lastValidPing = Com_DaysSince1900(); return; } // assume LAN response if( NET_IsLANAddress( address ) && ( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) ) { unsigned int ping = Sys_Milliseconds() - localQueryTimeStamp; CL_UIModule_AddToServerList( adrString, va( "\\\\ping\\\\%i%s", ping, s ) ); return; } // add the server info, but ignore the ping, cause it's not valid CL_UIModule_AddToServerList( adrString, s ); }
/* * SV_AutoUpdateFromWeb */ void SV_AutoUpdateFromWeb( bool checkOnly ) { if( checkOnly ) { Com_Autoupdate_Run( true, NULL ); return; } Cvar_ForceSet( "sv_lastAutoUpdate", va( "%i", (int)Com_DaysSince1900() ) ); Com_Autoupdate_Run( false, &SV_AutoUpdateComplete_f ); }
/* * SV_CheckAutoUpdate */ static void SV_CheckAutoUpdate( void ) { unsigned int days; if( !sv_pure->integer && sv_autoUpdate->integer ) { Com_Printf( "WARNING: Autoupdate is not available for unpure servers.\n" ); Cvar_ForceSet( "sv_autoUpdate", "0" ); } if( !sv_autoUpdate->integer || !dedicated->integer ) return; // do not if there has been any activity in the last 2 hours if( ( svc.last_activity + 1800000 ) > Sys_Milliseconds() ) return; days = (unsigned int)sv_lastAutoUpdate->integer; // daily check if( days < Com_DaysSince1900() ) SV_AutoUpdateFromWeb( qfalse ); }
/* * CL_AddServerToList */ static qboolean CL_AddServerToList( serverlist_t **serversList, char *adr, unsigned int days ) { serverlist_t *newserv; netadr_t nadr; if( !adr || !strlen( adr ) ) return qfalse; if( !NET_StringToAddress( adr, &nadr ) ) return qfalse; newserv = CL_ServerFindInList( *serversList, adr ); if( newserv ) { // ignore excessive updates for about a second or so, which may happen // when we're querying multiple master servers at once if( !newserv->masterServerUpdateSeq || newserv->lastUpdatedByMasterServer + 1000 < Sys_Milliseconds() ) { newserv->lastUpdatedByMasterServer = Sys_Milliseconds(); newserv->masterServerUpdateSeq = masterServerUpdateSeq; } return qfalse; } newserv = (serverlist_t *)Mem_ZoneMalloc( sizeof( serverlist_t ) ); Q_strncpyz( newserv->address, adr, sizeof( newserv->address ) ); newserv->pingTimeStamp = 0; if( days == 0 ) newserv->lastValidPing = Com_DaysSince1900(); else newserv->lastValidPing = days; newserv->lastUpdatedByMasterServer = Sys_Milliseconds(); newserv->masterServerUpdateSeq = masterServerUpdateSeq; newserv->pnext = *serversList; *serversList = newserv; return qtrue; }
/* * SV_AutoUpdateFromWeb */ void SV_AutoUpdateFromWeb( qboolean checkOnly ) { static const char *autoUpdateBaseUrl = APP_UPDATE_URL APP_SERVER_UPDATE_DIRECTORY; char checksumString1[32], checksumString2[32]; unsigned int checksum; qboolean success; int length, filenum; qbyte *data; const char *token, *ptr; char path[MAX_QPATH]; int downloadCount = 0, downloadFailed = 0; char newVersionTag[MAX_QPATH]; qboolean newVersion = qfalse; if( !dedicated->integer ) return; assert( svs.mapcmd[0] ); if( !checkOnly ) SV_UpdateActivity(); Com_Printf( "\n" ); Com_Printf( "========== Starting Auto Update ===========\n" ); Com_Printf( "Checking for updates\n" ); // download the update file list success = SV_WebDownload( autoUpdateBaseUrl, APP_SERVER_UPDATE_FILE, qtrue, qtrue ); // set as last updated today if( !checkOnly ) Cvar_ForceSet( "sv_lastAutoUpdate", va( "%i", (int)Com_DaysSince1900() ) ); if( !success ) // no update to do goto done; // read the file list if( ( length = FS_FOpenBaseFile( APP_SERVER_UPDATE_FILE, &filenum, FS_READ ) ) == -1 ) { Com_Printf( "WARNING: Couldn't find %s\n", path ); goto done; } if( !length ) { FS_FCloseFile( filenum ); goto done; } data = Mem_TempMalloc( length + 1 ); FS_Read( data, length, filenum ); FS_FCloseFile( filenum ); FS_RemoveBaseFile( APP_SERVER_UPDATE_FILE ); ptr = (const char *)data; // first token is always the current release version token = COM_ParseExt( &ptr, qtrue ); if( !token[0] ) goto cancel; // compare versions Q_strncpyz( newVersionTag, token, sizeof( newVersionTag ) ); if( atof( newVersionTag ) > atof( va( "%4.3f", APP_VERSION ) ) ) newVersion = qtrue; while( ptr ) { // we got what should be a checksum token = COM_ParseExt( &ptr, qtrue ); if( !token[0] ) goto cancel; // copy checksum reported by server Q_strncpyz( checksumString1, token, sizeof( checksumString1 ) ); // get filename token = COM_ParseExt( &ptr, qtrue ); if( !token[0] ) goto cancel; // filename should never begin with a slash if( token[0] == '/' ) token++; Q_strncpyz( path, token, sizeof( path ) ); // we got what should be a file path if( !COM_ValidateRelativeFilename( path ) ) { Com_Printf( "WARNING: Invalid filename %s\n", path ); continue; } checksum = FS_ChecksumBaseFile( path ); Q_snprintfz( checksumString2, sizeof( checksumString2 ), "%u", checksum ); // if same checksum no need to update if( !strcmp( checksumString1, checksumString2 ) ) continue; // if it's a pack file and the file exists it can't be replaced, so skip if( FS_CheckPakExtension( path ) && checksum ) { Com_Printf( "WARNING: Purity check failed for: %s\n", path ); Com_Printf( "WARNING: This file has been locally modified. It is highly \n" ); Com_Printf( "WARNING: recommended to restore the original file.\n" ); Com_Printf( "WARNING: Reinstalling \""APPLICATION"\" might be convenient.\n" ); continue; } if( checkOnly ) { Com_Printf( "File update available : %s\n", path ); continue; } if( developer->integer ) Com_Printf( "Downloading update of %s (checksum %s local checksum %s)\n", path, checksumString1, checksumString2 ); else Com_Printf( "Updating %s\n", path ); if( !SV_WebDownload( autoUpdateBaseUrl, path, qtrue, qtrue ) ) { Com_Printf( "Failed to update %s\n", path ); downloadFailed++; } downloadCount++; } cancel: Mem_TempFree( data ); done: if( newVersion ) { if( downloadCount ) { if( downloadFailed ) Com_Printf( "This version of "APPLICATION" was updated incompletely\n" ); else Com_Printf( "This version of "APPLICATION" was updated successfully\n\n" ); } Com_Printf( "****** Version %s of "APPLICATION" is available. ******\n", newVersionTag ); Com_Printf( "****** Please download the new version at "APP_URL" ******\n" ); } else if( downloadCount ) { if( downloadFailed ) Com_Printf( APPLICATION" was updated incompletely\n" ); else Com_Printf( APPLICATION" was updated successfully\n" ); } else if( !checkOnly ) { if( downloadFailed ) Com_Printf( "At least one file failed to update\n" ); else Com_Printf( APPLICATION" is up to date\n" ); } Com_Printf( "========== Auto Update Finished ===========\n" ); Com_Printf( "\n" ); // update the map list, which also does a filesystem rescan ML_Update(); // if there are any new filesystem entries, restart if( FS_GetNotifications() & FS_NOTIFT_NEWPAKS ) { if( sv.state != ss_dead ) { // restart the current map, SV_Map also rescans the filesystem Com_Printf( "The server will now restart...\n\n" ); // start the default map if current map isn't available Cbuf_ExecuteText( EXEC_APPEND, va( "map %s\n", svs.mapcmd[0] ? svs.mapcmd : sv_defaultmap->string ) ); } } }