/* * CL_QueryGetInfoMessage */ static void CL_QueryGetInfoMessage( const char *cmdname ) { netadr_t adr; char *requeststring; char *server; //get what master server = Cmd_Argv( 1 ); if( !server || !( *server ) ) { Com_Printf( "%s: no address provided %s...\n", Cmd_Argv( 0 ), server ? server : "" ); return; } requeststring = va( cmdname ); // send a broadcast packet Com_DPrintf( "quering %s...\n", server ); if( NET_StringToAddress( server, &adr ) ) { socket_t *socket; if( NET_GetAddressPort( &adr ) == 0 ) NET_SetAddressPort( &adr, PORT_SERVER ); socket = ( adr.type == NA_IP6 ? &cls.socket_udp6 : &cls.socket_udp ); Netchan_OutOfBandPrint( socket, &adr, requeststring ); } else { Com_Printf( "Bad address: %s\n", server ); } }
/* * TV_Downstream_AddMaster_f * Add a master server to the list */ static void TV_Downstream_AddMaster_f( const char *master ) { int i; if( !master || !master[0] ) return; if( !tv_public->integer ) { Com_Printf( "'TV_Downstream_AddMaster_f' Only public servers use masters.\n" ); return; } for( i = 0; i < MAX_MASTERS; i++ ) { if( tv_master_adr[i].type != NA_NOTRANSMIT ) continue; if( !NET_StringToAddress( master, &tv_master_adr[i] ) ) { Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", master ); return; } if( NET_GetAddressPort( &tv_master_adr[i] ) == 0 ) NET_SetAddressPort( &tv_master_adr[i], PORT_MASTER ); Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &tv_master_adr[i] ) ); return; } Com_Printf( "'TV_Downstream_AddMaster_f' List of master servers is already full\n" ); }
/* * SV_AddMaster_f * Add a master server to the list */ static void SV_AddMaster_f( char *address, bool steam ) { int i; if( !address || !address[0] ) return; if( !sv_public->integer ) { Com_Printf( "'SV_AddMaster_f' Only public servers use masters.\n" ); return; } //never go public when not acting as a game server if( sv.state > ss_game ) return; for( i = 0; i < MAX_MASTERS; i++ ) { sv_master_t *master = &sv_masters[i]; if( master->address.type != NA_NOTRANSMIT ) continue; if( !NET_StringToAddress( address, &master->address ) ) { Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", address ); return; } if( NET_GetAddressPort( &master->address ) == 0 ) NET_SetAddressPort( &master->address, steam ? PORT_MASTER_STEAM : PORT_MASTER ); master->steam = steam; Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &master->address ) ); return; } Com_Printf( "'SV_AddMaster_f' List of master servers is already full\n" ); }
/* * SV_AddMaster_f * Add a master server to the list */ static void SV_AddMaster_f( char *master ) { int i; if( !master || !master[0] ) return; if( !sv_public->integer ) { Com_Printf( "'SV_AddMaster_f' Only public servers use masters.\n" ); return; } //never go public when not acting as a game server if( sv.state > ss_game ) return; for( i = 0; i < MAX_MASTERS; i++ ) { if( master_adr[i].type != NA_NOTRANSMIT ) continue; if( !NET_StringToAddress( master, &master_adr[i] ) ) { Com_Printf( "'SV_AddMaster_f' Bad Master server address: %s\n", master ); return; } if( NET_GetAddressPort( &master_adr[i] ) == 0 ) NET_SetAddressPort( &master_adr[i], PORT_MASTER ); Com_Printf( "Added new master server #%i at %s\n", i, NET_AddressToString( &master_adr[i] ) ); return; } Com_Printf( "'SV_AddMaster_f' List of master servers is already full\n" ); }
/* * TV_Init * * Only called at plat.exe startup, not for each game */ void TV_Init( void ) { Com_Printf( "Initializing " APPLICATION " TV server\n" ); tv_mempool = Mem_AllocPool( NULL, "TV" ); TV_AddCommands(); Cvar_Get( "protocol", va( "%i", APP_PROTOCOL_VERSION ), CVAR_SERVERINFO | CVAR_NOSET ); Cvar_Get( "gamename", Cvar_String( "gamename" ), CVAR_SERVERINFO | CVAR_NOSET ); tv_password = Cvar_Get( "tv_password", "", 0 ); tv_ip = Cvar_Get( "tv_ip", "", CVAR_ARCHIVE | CVAR_NOSET ); tv_port = Cvar_Get( "tv_port", va( "%i", PORT_TV_SERVER ), CVAR_ARCHIVE | CVAR_NOSET ); tv_ip6 = Cvar_Get( "tv_ip6", "::", CVAR_ARCHIVE | CVAR_NOSET ); tv_port6 = Cvar_Get( "tv_port6", va( "%i", PORT_TV_SERVER ), CVAR_ARCHIVE | CVAR_NOSET ); #ifdef TCP_ALLOW_TVCONNECT tv_udp = Cvar_Get( "tv_udp", "1", CVAR_SERVERINFO | CVAR_NOSET ); tv_tcp = Cvar_Get( "tv_tcp", "1", CVAR_SERVERINFO | CVAR_NOSET ); #else tv_udp = Cvar_Get( "tv_udp", "1", CVAR_NOSET ); #endif #ifndef TCP_ALLOW_TVCONNECT Cvar_FullSet( "tv_tcp", "0", CVAR_READONLY, true ); #endif tv_reconnectlimit = Cvar_Get( "tv_reconnectlimit", "3", CVAR_ARCHIVE ); tv_timeout = Cvar_Get( "tv_timeout", "125", 0 ); tv_zombietime = Cvar_Get( "tv_zombietime", "2", 0 ); tv_name = Cvar_Get( "tv_name", APPLICATION "[TV]", CVAR_SERVERINFO | CVAR_ARCHIVE ); tv_compresspackets = Cvar_Get( "tv_compresspackets", "1", 0 ); tv_maxclients = Cvar_Get( "tv_maxclients", "32", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOSET ); tv_maxmvclients = Cvar_Get( "tv_maxmvclients", "4", CVAR_ARCHIVE | CVAR_SERVERINFO | CVAR_NOSET ); tv_public = Cvar_Get( "tv_public", "1", CVAR_ARCHIVE | CVAR_SERVERINFO ); tv_rcon_password = Cvar_Get( "tv_rcon_password", "", 0 ); tv_autorecord = Cvar_Get( "tv_autorecord", "", CVAR_ARCHIVE ); tv_lobbymusic = Cvar_Get( "tv_lobbymusic", "", CVAR_ARCHIVE ); tv_masterservers = Cvar_Get( "tv_masterservers", DEFAULT_MASTER_SERVERS_IPS, CVAR_LATCH ); tv_masterservers_steam = Cvar_Get( "tv_masterservers_steam", DEFAULT_MASTER_SERVERS_STEAM_IPS, CVAR_LATCH ); // flood control tv_floodprotection_messages = Cvar_Get( "tv_floodprotection_messages", "10", 0 ); tv_floodprotection_messages->modified = true; tv_floodprotection_seconds = Cvar_Get( "tv_floodprotection_seconds", "4", 0 ); tv_floodprotection_seconds->modified = true; tv_floodprotection_penalty = Cvar_Get( "tv_floodprotection_delay", "20", 0 ); tv_floodprotection_penalty->modified = true; if( tv_maxclients->integer < 0 ) Cvar_ForceSet( "tv_maxclients", "0" ); if( tv_maxclients->integer ) { tvs.clients = ( client_t * )Mem_Alloc( tv_mempool, sizeof( client_t ) * tv_maxclients->integer ); } else { tvs.clients = NULL; } tvs.lobby.spawncount = rand(); tvs.lobby.snapFrameTime = 100; // IPv4 if( !NET_StringToAddress( tv_ip->string, &tvs.address ) ) Com_Error( ERR_FATAL, "Couldn't understand address of tv_ip cvar: %s\n", NET_ErrorString() ); NET_SetAddressPort( &tvs.address, tv_port->integer ); if( tv_udp->integer ) { if( !NET_OpenSocket( &tvs.socket_udp, SOCKET_UDP, &tvs.address, true ) ) { Com_Printf( "Error: Couldn't open UDP socket: %s\n", NET_ErrorString() ); Cvar_ForceSet( tv_udp->name, "0" ); } } // IPv6 if( !NET_StringToAddress( tv_ip6->string, &tvs.addressIPv6 ) ) Com_Error( ERR_FATAL, "Couldn't understand address of tv_ip6 cvar: %s\n", NET_ErrorString() ); NET_SetAddressPort( &tvs.addressIPv6, tv_port6->integer ); if( tvs.addressIPv6.type != NA_NOTRANSMIT ) { if( !NET_OpenSocket( &tvs.socket_udp6, SOCKET_UDP, &tvs.addressIPv6, true ) ) { Com_Printf( "Error: Couldn't open UDP6 socket: %s\n", NET_ErrorString() ); } } #ifdef TCP_ALLOW_TVCONNECT if( tv_tcp->integer ) { bool err = true; if( !NET_OpenSocket( &tvs.socket_tcp, SOCKET_TCP, &tvs.address, true ) ) { Com_Printf( "Error: Couldn't open TCP socket: %s\n", NET_ErrorString() ); } else { NET_SetSocketNoDelay( &tvs.socket_tcp, 1 ); if( !NET_Listen( &tvs.socket_tcp ) ) { Com_Printf( "Error: Couldn't listen to TCP socket: %s\n", NET_ErrorString() ); } else { err = false; } } if( tvs.addressIPv6.type != NA_NOTRANSMIT ) { if( !NET_OpenSocket( &tvs.socket_tcp6, SOCKET_TCP, &tvs.addressIPv6, true ) ) { Com_Printf( "Error: Couldn't open TCP6 socket: %s\n", NET_ErrorString() ); } else { NET_SetSocketNoDelay( &tvs.socket_tcp6, 1 ); if( !NET_Listen( &tvs.socket_tcp6 ) ) { Com_Printf( "Error: Couldn't listen to TCP6 socket: %s\n", NET_ErrorString() ); } else { err = false; } } } if( err ) { Cvar_ForceSet( tv_tcp->name, "0" ); } } #endif TV_Downstream_InitMaster(); }
/* * CL_GetServers_f */ void CL_GetServers_f( void ) { netadr_t adr, *padr; char *requeststring; int i; char *modname, *master; trie_error_t err; filter_allow_full = qfalse; filter_allow_empty = qfalse; for( i = 2; i < Cmd_Argc(); i++ ) { if( !Q_stricmp( "full", Cmd_Argv( i ) ) ) filter_allow_full = qtrue; if( !Q_stricmp( "empty", Cmd_Argv( i ) ) ) filter_allow_empty = qtrue; } if( !Q_stricmp( Cmd_Argv( 1 ), "local" ) ) { if( localQueryTimeStamp + LAN_SERVER_PINGING_TIMEOUT > Sys_Milliseconds() ) { return; } padr = &adr; localQueryTimeStamp = Sys_Milliseconds(); // send a broadcast packet Com_DPrintf( "pinging broadcast...\n" ); // erm... modname isn't sent in local queries? requeststring = va( "info %i %s %s", SERVERBROWSER_PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); for( i = 0; i < NUM_BROADCAST_PORTS; i++ ) { NET_BroadcastAddress( padr, PORT_SERVER + i ); Netchan_OutOfBandPrint( &cls.socket_udp, padr, requeststring ); } return; } //get what master master = Cmd_Argv( 2 ); if( !master || !( *master ) ) return; modname = Cmd_Argv( 3 ); // never allow anyone to use DEFAULT_BASEGAME as mod name if( !modname || !modname[0] || !Q_stricmp( modname, DEFAULT_BASEGAME ) ) modname = APPLICATION; assert( modname[0] ); // check memory cache QMutex_Lock( resolveLock ); err = Trie_Find( serverlist_masters_trie, master, TRIE_EXACT_MATCH, (void **)&padr ); QMutex_Unlock( resolveLock ); if( err == TRIE_OK && ( padr->type == NA_IP || padr->type == NA_IP6 ) ) { const char *cmdname; socket_t *socket; if ( padr->type == NA_IP ) { cmdname = "getservers"; socket = &cls.socket_udp; } else { cmdname = "getserversExt"; socket = &cls.socket_udp6; } // create the message requeststring = va( "%s %c%s %i %s %s", cmdname, toupper( modname[0] ), modname+1, SERVERBROWSER_PROTOCOL_VERSION, filter_allow_full ? "full" : "", filter_allow_empty ? "empty" : "" ); if( NET_GetAddressPort( padr ) == 0 ) NET_SetAddressPort( padr, PORT_MASTER ); Netchan_OutOfBandPrint( socket, padr, requeststring ); Com_DPrintf( "quering %s...%s: %s\n", master, NET_AddressToString(padr), requeststring ); } else { Com_Printf( "Bad address: %s\n", master ); } }
/* * SV_InitGame * A brand new game has been started */ void SV_InitGame( void ) { int i; edict_t *ent; netadr_t address, ipv6_address; // make sure the client is down CL_Disconnect( NULL ); SCR_BeginLoadingPlaque(); if( svs.initialized ) { // cause any connected clients to reconnect SV_ShutdownGame( "Server restarted", qtrue ); // SV_ShutdownGame will also call Cvar_GetLatchedVars } else { // get any latched variable changes (sv_maxclients, etc) Cvar_GetLatchedVars( CVAR_LATCH ); } svs.initialized = qtrue; if( sv_skilllevel->integer > 2 ) Cvar_ForceSet( "sv_skilllevel", "2" ); if( sv_skilllevel->integer < 0 ) Cvar_ForceSet( "sv_skilllevel", "0" ); // init clients if( sv_maxclients->integer < 1 ) Cvar_FullSet( "sv_maxclients", "8", CVAR_SERVERINFO | CVAR_LATCH, qtrue ); else if( sv_maxclients->integer > MAX_CLIENTS ) Cvar_FullSet( "sv_maxclients", va( "%i", MAX_CLIENTS ), CVAR_SERVERINFO | CVAR_LATCH, qtrue ); svs.spawncount = rand(); svs.clients = Mem_Alloc( sv_mempool, sizeof( client_t )*sv_maxclients->integer ); svs.client_entities.num_entities = sv_maxclients->integer * UPDATE_BACKUP * MAX_SNAP_ENTITIES; svs.client_entities.entities = Mem_Alloc( sv_mempool, sizeof( entity_state_t ) * svs.client_entities.num_entities ); // init network stuff address.type = NA_NOTRANSMIT; ipv6_address.type = NA_NOTRANSMIT; if( !dedicated->integer ) { NET_InitAddress( &address, NA_LOOPBACK ); if( !NET_OpenSocket( &svs.socket_loopback, SOCKET_LOOPBACK, &address, qtrue ) ) Com_Error( ERR_FATAL, "Couldn't open loopback socket: %s\n", NET_ErrorString() ); } if( dedicated->integer || sv_maxclients->integer > 1 ) { qboolean socket_opened = qfalse; // IPv4 NET_StringToAddress( sv_ip->string, &address ); NET_SetAddressPort( &address, sv_port->integer ); if( !NET_OpenSocket( &svs.socket_udp, SOCKET_UDP, &address, qtrue ) ) Com_Printf( "Error: Couldn't open UDP socket: %s\n", NET_ErrorString() ); else socket_opened = qtrue; // IPv6 NET_StringToAddress( sv_ip6->string, &ipv6_address ); if( ipv6_address.type == NA_IP6 ) { NET_SetAddressPort( &ipv6_address, sv_port6->integer ); if( !NET_OpenSocket( &svs.socket_udp6, SOCKET_UDP, &ipv6_address, qtrue ) ) Com_Printf( "Error: Couldn't open UDP6 socket: %s\n", NET_ErrorString() ); else socket_opened = qtrue; } else Com_Printf( "Error: invalid IPv6 address: %s\n", sv_ip6->string ); if( dedicated->integer && !socket_opened ) Com_Error( ERR_FATAL, "Couldn't open any socket\n" ); } #ifdef TCP_ALLOW_CONNECT if( sv_tcp->integer && ( dedicated->integer || sv_maxclients->integer > 1 ) ) { if( !NET_OpenSocket( &svs.socket_tcp, SOCKET_TCP, &address, qtrue ) ) { Com_Printf( "Error: Couldn't open TCP socket: %s", NET_ErrorString() ); Cvar_ForceSet( "sv_tcp", "0" ); } else { if( !NET_Listen( &svs.socket_tcp ) ) { Com_Printf( "Error: Couldn't listen to TCP socket: %s", NET_ErrorString() ); NET_CloseSocket( &svs.socket_tcp ); Cvar_ForceSet( "sv_tcp", "0" ); } } } #endif // init mm // SV_MM_Init(); // init game SV_InitGameProgs(); for( i = 0; i < sv_maxclients->integer; i++ ) { ent = EDICT_NUM( i+1 ); ent->s.number = i+1; svs.clients[i].edict = ent; } // load the map assert( !svs.cms ); svs.cms = CM_New( NULL ); }
/* * SV_ReadPackets */ static void SV_ReadPackets( void ) { int i, socketind, ret; client_t *cl; #ifdef TCP_SUPPORT socket_t newsocket; netadr_t mmserver; #endif int game_port; socket_t *socket; netadr_t address; static msg_t msg; static qbyte msgData[MAX_MSGLEN]; socket_t* sockets [] = { &svs.socket_loopback, &svs.socket_udp, &svs.socket_udp6, }; #ifdef TCP_SUPPORT if( SV_MM_Initialized() ) SV_MM_NetAddress( &mmserver ); if( svs.socket_tcp.open ) { while( qtrue ) { // find a free slot for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !svs.incoming[i].active ) break; } if( i == MAX_INCOMING_CONNECTIONS ) break; if( ( ret = NET_Accept( &svs.socket_tcp, &newsocket, &address ) ) == 0 ) break; if( ret == -1 ) { Com_Printf( "NET_Accept: Error: %s\n", NET_ErrorString() ); continue; } Com_Printf( "New TCP connection from %s\n", NET_AddressToString( &address ) ); svs.incoming[i].active = qtrue; svs.incoming[i].socket = newsocket; svs.incoming[i].address = address; svs.incoming[i].time = svs.realtime; } } for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !svs.incoming[i].active ) continue; ret = NET_GetPacket( &svs.incoming[i].socket, &address, &msg ); if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); NET_CloseSocket( &svs.incoming[i].socket ); svs.incoming[i].active = qfalse; } else if( ret == 1 ) { if( SV_MM_Initialized() && NET_CompareBaseAddress( &mmserver, &address ) ) { Com_DPrintf( "TCP packet from matchmaker\n" ); SV_MM_SetConnection( &svs.incoming[i] ); SV_MM_Packet( &msg ); SV_MM_SetConnection( NULL ); continue; } if( *(int *)msg.data != -1 ) { Com_Printf( "Sequence packet without connection\n" ); NET_CloseSocket( &svs.incoming[i].socket ); svs.incoming[i].active = qfalse; continue; } Com_Printf( "Connectionless TCP packet from: %s\n", NET_AddressToString( &address ) ); SV_ConnectionlessPacket( &svs.incoming[i].socket, &address, &msg ); } } #endif MSG_Init( &msg, msgData, sizeof( msgData ) ); for( socketind = 0; socketind < sizeof( sockets ) / sizeof( sockets[0] ); socketind++ ) { socket = sockets[socketind]; if( !socket->open ) continue; while( ( ret = NET_GetPacket( socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); continue; } // check for connectionless packet (0xffffffff) first if( *(int *)msg.data == -1 ) { SV_ConnectionlessPacket( socket, &address, &msg ); continue; } // read the game port out of the message so we can fix up // stupid address translating routers MSG_BeginReading( &msg ); MSG_ReadLong( &msg ); // sequence number MSG_ReadLong( &msg ); // sequence number game_port = MSG_ReadShort( &msg ) & 0xffff; // data follows // check for packets from connected clients for( i = 0, cl = svs.clients; i < sv_maxclients->integer; i++, cl++ ) { unsigned short addr_port; if( cl->state == CS_FREE || cl->state == CS_ZOMBIE ) continue; if( cl->edict && ( cl->edict->r.svflags & SVF_FAKECLIENT ) ) continue; if( !NET_CompareBaseAddress( &address, &cl->netchan.remoteAddress ) ) continue; if( cl->netchan.game_port != game_port ) continue; addr_port = NET_GetAddressPort( &address ); if( NET_GetAddressPort( &cl->netchan.remoteAddress ) != addr_port ) { Com_Printf( "SV_ReadPackets: fixing up a translated port\n" ); NET_SetAddressPort( &cl->netchan.remoteAddress, addr_port ); } if( SV_ProcessPacket( &cl->netchan, &msg ) ) // this is a valid, sequenced packet, so process it { cl->lastPacketReceivedTime = svs.realtime; SV_ParseClientMessage( cl, &msg ); } break; } } } // handle clients with individual sockets for( i = 0; i < sv_maxclients->integer; i++ ) { cl = &svs.clients[i]; if( cl->state == CS_ZOMBIE || cl->state == CS_FREE ) continue; if( !cl->individual_socket ) continue; // not while, we only handle one packet per client at a time here if( ( ret = NET_GetPacket( cl->netchan.socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "Error receiving packet from %s: %s\n", NET_AddressToString( &cl->netchan.remoteAddress ), NET_ErrorString() ); if( cl->reliable ) SV_DropClient( cl, DROP_TYPE_GENERAL, "Error receiving packet: %s", NET_ErrorString() ); } else { if( SV_ProcessPacket( &cl->netchan, &msg ) ) { // this is a valid, sequenced packet, so process it cl->lastPacketReceivedTime = svs.realtime; SV_ParseClientMessage( cl, &msg ); } } } } }
/* * TV_Downstream_ReadPackets */ void TV_Downstream_ReadPackets( void ) { int i, socketind, ret, game_port; client_t *cl; #ifdef TCP_SUPPORT socket_t newsocket; #endif socket_t *socket; netadr_t address; msg_t msg; qbyte msgData[MAX_MSGLEN]; socket_t* sockets [] = { &tvs.socket_udp, &tvs.socket_udp6, }; #ifdef TCP_SUPPORT if( tvs.socket_tcp.open ) { while( qtrue ) { // find a free slot for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !tvs.incoming[i].active ) break; } if( i == MAX_INCOMING_CONNECTIONS ) break; if( ( ret = NET_Accept( &tvs.socket_tcp, &newsocket, &address ) ) == 0 ) break; if( ret == -1 ) { Com_Printf( "NET_Accept: Error: %s\n", NET_ErrorString() ); continue; } tvs.incoming[i].active = qtrue; tvs.incoming[i].socket = newsocket; tvs.incoming[i].address = address; tvs.incoming[i].time = tvs.realtime; } } for( i = 0; i < MAX_INCOMING_CONNECTIONS; i++ ) { if( !tvs.incoming[i].active ) continue; ret = NET_GetPacket( &tvs.incoming[i].socket, &address, &msg ); if( ret == -1 ) { NET_CloseSocket( &tvs.incoming[i].socket ); tvs.incoming[i].active = qfalse; } else if( ret == 1 ) { if( *(int *)msg.data != -1 ) { // sequence packet without upstreams NET_CloseSocket( &tvs.incoming[i].socket ); tvs.incoming[i].active = qfalse; continue; } TV_Downstream_UpstreamlessPacket( &tvs.incoming[i].socket, &address, &msg ); } } #endif MSG_Init( &msg, msgData, sizeof( msgData ) ); for( socketind = 0; socketind < sizeof( sockets ) / sizeof( sockets[0] ); socketind++ ) { socket = sockets[socketind]; while( socket->open && ( ret = NET_GetPacket( socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "NET_GetPacket: Error: %s\n", NET_ErrorString() ); continue; } // check for upstreamless packet (0xffffffff) first if( *(int *)msg.data == -1 ) { TV_Downstream_UpstreamlessPacket( socket, &address, &msg ); continue; } // read the game port out of the message so we can fix up // stupid address translating routers MSG_BeginReading( &msg ); MSG_ReadLong( &msg ); // sequence number MSG_ReadLong( &msg ); // sequence number game_port = MSG_ReadShort( &msg ) & 0xffff; // data follows // check for packets from connected clients for( i = 0, cl = tvs.clients; i < tv_maxclients->integer; i++, cl++ ) { unsigned short remoteaddr_port, addr_port; if( cl->state == CS_FREE || cl->state == CS_ZOMBIE ) continue; if( !NET_CompareBaseAddress( &address, &cl->netchan.remoteAddress ) ) continue; if( cl->netchan.game_port != game_port ) continue; remoteaddr_port = NET_GetAddressPort( &cl->netchan.remoteAddress ); addr_port = NET_GetAddressPort( &address ); if( remoteaddr_port != addr_port ) { Com_DPrintf( "%s" S_COLOR_WHITE ": Fixing up a translated port from %i to %i\n", cl->name, remoteaddr_port, addr_port ); NET_SetAddressPort( &cl->netchan.remoteAddress, addr_port ); } if( TV_Downstream_ProcessPacket( &cl->netchan, &msg ) ) { // this is a valid, sequenced packet, so process it cl->lastPacketReceivedTime = tvs.realtime; TV_Downstream_ParseClientMessage( cl, &msg ); } break; } } } // handle clients with individual sockets for( i = 0; i < tv_maxclients->integer; i++ ) { cl = &tvs.clients[i]; if( cl->state == CS_ZOMBIE || cl->state == CS_FREE ) continue; if( !cl->individual_socket ) continue; // not while, we only handle one packet per client at a time here if( ( ret = NET_GetPacket( cl->netchan.socket, &address, &msg ) ) != 0 ) { if( ret == -1 ) { Com_Printf( "%s" S_COLOR_WHITE ": Error receiving packet: %s\n", cl->name, NET_ErrorString() ); if( cl->reliable ) TV_Downstream_DropClient( cl, DROP_TYPE_GENERAL, "Error receiving packet: %s", NET_ErrorString() ); } else { if( *(int *)msg.data == -1 ) { TV_Downstream_UpstreamlessPacket( cl->netchan.socket, &address, &msg ); } else { if( TV_Downstream_ProcessPacket( &cl->netchan, &msg ) ) { cl->lastPacketReceivedTime = tvs.realtime; TV_Downstream_ParseClientMessage( cl, &msg ); } } } } } }