/* * TV_Upstream_ParseServerData */ static void TV_Upstream_ParseServerData( upstream_t *upstream, msg_t *msg ) { int i, numpure; TV_Upstream_ClearState( upstream ); upstream->state = CA_CONNECTED; // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION ) TV_Upstream_Error( upstream, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); upstream->servercount = MSG_ReadLong( msg ); upstream->snapFrameTime = (unsigned int) MSG_ReadShort( msg ); Q_strncpyz( upstream->basegame, MSG_ReadString( msg ), sizeof( upstream->basegame ) ); Q_strncpyz( upstream->game, MSG_ReadString( msg ), sizeof( upstream->game ) ); // parse player entity number upstream->playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( upstream->levelname, MSG_ReadString( msg ), sizeof( upstream->levelname ) ); upstream->sv_bitflags = MSG_ReadByte( msg ); upstream->reliable = ( ( upstream->sv_bitflags & SV_BITFLAGS_RELIABLE ) ? true : false ); if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( upstream->sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url MSG_ReadString( msg ); } else { // http port number MSG_ReadShort( msg ); } } // pure list // clean old, if necessary Com_FreePureList( &upstream->purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &upstream->purelist, pakname, checksum, upstream->mempool ); numpure--; } TV_Upstream_AddReliableCommand( upstream, va( "configstrings %i 0", upstream->servercount ) ); }
/* * SV_ReloadPureList */ static void SV_ReloadPureList( void ) { char **paks; int i, numpaks; Com_FreePureList( &svs.purelist ); // game modules if( sv_pure_forcemodulepk3->string[0] ) { if( Q_strnicmp( COM_FileBase( sv_pure_forcemodulepk3->string ), "modules", strlen( "modules" ) ) || !FS_IsPakValid( sv_pure_forcemodulepk3->string, NULL ) ) { Com_Printf( "Warning: Invalid value for sv_pure_forcemodulepk3, disabling\n" ); Cvar_ForceSet( "sv_pure_forcemodulepk3", "" ); } else { SV_AddPurePak( sv_pure_forcemodulepk3->string ); } } if( !sv_pure_forcemodulepk3->string[0] ) { char *libname; int libname_size; libname_size = strlen( LIB_PREFIX ) + 5 + strlen( ARCH ) + strlen( LIB_SUFFIX ) + 1; libname = Mem_TempMalloc( libname_size ); Q_snprintfz( libname, libname_size, LIB_PREFIX "game_" ARCH LIB_SUFFIX ); if( !FS_PakNameForFile( libname ) ) { if( sv_pure->integer ) { Com_Printf( "Warning: Game module not in pk3, disabling pure mode\n" ); Com_Printf( "sv_pure_forcemodulepk3 can be used to force the pure system to use a different module\n" ); Cvar_ForceSet( "sv_pure", "0" ); } } else { SV_AddPureFile( libname ); } Mem_TempFree( libname ); libname = NULL; } // *pure.(pk3|pak) paks = NULL; numpaks = FS_GetExplicitPurePakList( &paks ); if( numpaks ) { for( i = 0; i < numpaks; i++ ) { SV_AddPurePak( paks[i] ); Mem_ZoneFree( paks[i] ); } Mem_ZoneFree( paks ); } }
/* * TV_Relay_ParseServerData */ static void TV_Relay_ParseServerData( relay_t *relay, msg_t *msg ) { int i, numpure; TV_Relay_ClearState( relay ); relay->state = CA_CONNECTED; relay->map_checksum = 0; // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION ) TV_Relay_Error( relay, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); relay->servercount = MSG_ReadLong( msg ); relay->snapFrameTime = (unsigned int)MSG_ReadShort( msg ); Q_strncpyz( relay->basegame, MSG_ReadString( msg ), sizeof( relay->basegame ) ); Q_strncpyz( relay->game, MSG_ReadString( msg ), sizeof( relay->game ) ); // parse player entity number relay->playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( relay->levelname, MSG_ReadString( msg ), sizeof( relay->levelname ) ); relay->sv_bitflags = MSG_ReadByte( msg ); // using upstream->reliable won't work for TV_Relay_ParseServerMessage // in case of reliable demo following unreliable demo, causing "clack message while reliable" error relay->reliable = ( ( relay->sv_bitflags & SV_BITFLAGS_RELIABLE ) ? qtrue : qfalse ); // pure list // clean old, if necessary Com_FreePureList( &relay->purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &relay->purelist, pakname, checksum, relay->upstream->mempool ); numpure--; } }
/* * SV_ShutdownGame * * Called when each game quits */ void SV_ShutdownGame( const char *finalmsg, qboolean reconnect ) { if( !svs.initialized ) return; if( svs.demo.file ) SV_Demo_Stop_f(); if( svs.clients ) SV_FinalMessage( finalmsg, reconnect ); SV_ShutdownGameProgs(); // SV_MM_Shutdown(); NET_CloseSocket( &svs.socket_loopback ); NET_CloseSocket( &svs.socket_udp ); NET_CloseSocket( &svs.socket_udp6 ); #ifdef TCP_ALLOW_CONNECT if( sv_tcp->integer ) NET_CloseSocket( &svs.socket_tcp ); #endif // get any latched variable changes (sv_maxclients, etc) Cvar_GetLatchedVars( CVAR_LATCH ); if( svs.clients ) { Mem_Free( svs.clients ); svs.clients = NULL; } if( svs.client_entities.entities ) { Mem_Free( svs.client_entities.entities ); memset( &svs.client_entities, 0, sizeof( svs.client_entities ) ); } if( svs.cms ) { CM_Free( svs.cms ); svs.cms = NULL; } memset( &sv, 0, sizeof( sv ) ); Com_SetServerState( sv.state ); Com_FreePureList( &svs.purelist ); if( svs.motd ) { Mem_Free( svs.motd ); svs.motd = NULL; } if( sv_mempool ) Mem_EmptyPool( sv_mempool ); memset( &svs, 0, sizeof( svs ) ); svs.initialized = qfalse; }
/* * CL_ParseServerData */ static void CL_ParseServerData( msg_t *msg ) { const char *str, *gamedir; int i, sv_bitflags, numpure; int http_portnum; Com_DPrintf( "Serverdata packet received.\n" ); // wipe the client_state_t struct CL_ClearState(); CL_SetClientState( CA_CONNECTED ); // parse protocol version number i = MSG_ReadLong( msg ); if( i != APP_PROTOCOL_VERSION ) Com_Error( ERR_DROP, "Server returned version %i, not %i", i, APP_PROTOCOL_VERSION ); cl.servercount = MSG_ReadLong( msg ); cl.snapFrameTime = (unsigned int)MSG_ReadShort( msg ); // set extrapolation time to half snapshot time Cvar_ForceSet( "cl_extrapolationTime", va( "%i", (unsigned int)( cl.snapFrameTime * 0.5 ) ) ); cl_extrapolationTime->modified = qfalse; // base game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty base game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid base game directory: %s", str ); if( strcmp( FS_BaseGameDirectory(), str ) ) { Com_Error( ERR_DROP, "Server has different base game directory (%s) than the client (%s)", str, FS_BaseGameDirectory() ); } // game directory str = MSG_ReadString( msg ); if( !str || !str[0] ) Com_Error( ERR_DROP, "Server sent an empty game directory" ); if( !COM_ValidateRelativeFilename( str ) || strchr( str, '/' ) ) Com_Error( ERR_DROP, "Server sent an invalid game directory: %s", str ); gamedir = FS_GameDirectory(); if( strcmp( str, gamedir ) ) { // shutdown the cgame module first in case it is running for whatever reason // (happens on wswtv in lobby), otherwise precaches that are going to follow // will probably f**k up (like models trying to load before the world model) CL_GameModule_Shutdown(); if( !FS_SetGameDirectory( str, qtrue ) ) Com_Error( ERR_DROP, "Failed to load game directory set by server: %s", str ); ML_Restart( qtrue ); } // parse player entity number cl.playernum = MSG_ReadShort( msg ); // get the full level name Q_strncpyz( cl.servermessage, MSG_ReadString( msg ), sizeof( cl.servermessage ) ); sv_bitflags = MSG_ReadByte( msg ); if( cls.demo.playing ) { cls.reliable = ( sv_bitflags & SV_BITFLAGS_RELIABLE ); } else { if( cls.reliable != ( ( sv_bitflags & SV_BITFLAGS_RELIABLE ) != 0 ) ) Com_Error( ERR_DROP, "Server and client disagree about connection reliability" ); } // builting HTTP server port if( cls.httpbaseurl ) { Mem_Free( cls.httpbaseurl ); cls.httpbaseurl = NULL; } if( ( sv_bitflags & SV_BITFLAGS_HTTP ) != 0 ) { if( ( sv_bitflags & SV_BITFLAGS_HTTP_BASEURL ) != 0 ) { // read base upstream url cls.httpbaseurl = ZoneCopyString( MSG_ReadString( msg ) ); } else { http_portnum = MSG_ReadShort( msg ) & 0xffff; cls.httpaddress = cls.serveraddress; if( cls.httpaddress.type == NA_IP6 ) { cls.httpaddress.address.ipv6.port = BigShort( http_portnum ); } else { cls.httpaddress.address.ipv4.port = BigShort( http_portnum ); } if( http_portnum ) { if( cls.httpaddress.type == NA_LOOPBACK ) { cls.httpbaseurl = ZoneCopyString( va( "http://localhost:%hu/", http_portnum ) ); } else { cls.httpbaseurl = ZoneCopyString( va( "http://%s/", NET_AddressToString( &cls.httpaddress ) ) ); } } } } // pure list // clean old, if necessary Com_FreePureList( &cls.purelist ); // add new numpure = MSG_ReadShort( msg ); while( numpure > 0 ) { const char *pakname = MSG_ReadString( msg ); const unsigned checksum = MSG_ReadLong( msg ); Com_AddPakToPureList( &cls.purelist, pakname, checksum, NULL ); numpure--; } //assert( numpure == 0 ); // get the configstrings request CL_AddReliableCommand( va( "configstrings %i 0", cl.servercount ) ); cls.sv_pure = ( sv_bitflags & SV_BITFLAGS_PURE ) != 0; cls.sv_tv = ( sv_bitflags & SV_BITFLAGS_TVSERVER ) != 0; #ifdef PURE_CHEAT cls.sv_pure = qfalse; #endif // separate the printfs so the server message can have a color Com_Printf( S_COLOR_WHITE "\n" "=====================================\n" ); Com_Printf( S_COLOR_WHITE "%s\n\n", cl.servermessage ); }
/* * SV_ShutdownGame * * Called when each game quits */ void SV_ShutdownGame( const char *finalmsg, bool reconnect ) { if( !svs.initialized ) { return; } if( svs.demo.file ) { SV_Demo_Stop_f(); } if( svs.clients ) { SV_FinalMessage( finalmsg, reconnect ); } SV_ShutdownGameProgs(); // SV_MM_Shutdown(); SV_MasterSendQuit(); NET_CloseSocket( &svs.socket_loopback ); NET_CloseSocket( &svs.socket_udp ); NET_CloseSocket( &svs.socket_udp6 ); #ifdef TCP_ALLOW_CONNECT if( sv_tcp->integer ) { NET_CloseSocket( &svs.socket_tcp ); NET_CloseSocket( &svs.socket_tcp6 ); } #endif // get any latched variable changes (sv_maxclients, etc) Cvar_GetLatchedVars( CVAR_LATCH ); if( svs.clients ) { Mem_Free( svs.clients ); svs.clients = NULL; } if( svs.client_entities.entities ) { Mem_Free( svs.client_entities.entities ); memset( &svs.client_entities, 0, sizeof( svs.client_entities ) ); } if( svs.cms ) { // CM_ReleaseReference will take care of freeing up the memory // if there are no other modules referencing the collision model CM_ReleaseReference( svs.cms ); svs.cms = NULL; } Com_SetServerCM( NULL, 0 ); memset( &sv, 0, sizeof( sv ) ); Com_SetServerState( sv.state ); Com_FreePureList( &svs.purelist ); if( svs.motd ) { Mem_Free( svs.motd ); svs.motd = NULL; } if( sv_mempool ) { Mem_EmptyPool( sv_mempool ); } if( svs.wakelock ) { Sys_ReleaseWakeLock( svs.wakelock ); svs.wakelock = NULL; } memset( &svs, 0, sizeof( svs ) ); svs.initialized = false; }