2
0
mirror of https://github.com/FWGS/xash3d-fwgs synced 2024-11-22 09:56:22 +01:00

engine: global refactoring of connectionless packets, now they can be customized from single protocol.h header

This commit is contained in:
Alibek Omarov 2024-10-19 14:05:00 +03:00
parent 2d546ccbf7
commit e3e4bcc015
8 changed files with 469 additions and 394 deletions

View File

@ -3485,7 +3485,7 @@ static void GAME_EXPORT NetAPI_SendRequest( int context, int request, int flags,
nr->flags = flags; nr->flags = flags;
// local servers request // local servers request
Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, "netinfo %i %i %i", FBitSet( flags, FNETAPI_LEGACY_PROTOCOL ) ? PROTOCOL_LEGACY_VERSION : PROTOCOL_VERSION, context, request ); Netchan_OutOfBandPrint( NS_CLIENT, nr->resp.remote_address, A2A_NETINFO" %i %i %i", FBitSet( flags, FNETAPI_LEGACY_PROTOCOL ) ? PROTOCOL_LEGACY_VERSION : PROTOCOL_VERSION, context, request );
} }
/* /*

View File

@ -1144,7 +1144,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
MSG_Init( &send, "GoldSrcConnect", send_buf, sizeof( send_buf )); MSG_Init( &send, "GoldSrcConnect", send_buf, sizeof( send_buf ));
MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET ); MSG_WriteLong( &send, NET_HEADER_OUTOFBANDPACKET );
MSG_WriteStringf( &send, "connect %i %i \"%s\" \"%s\"\n", MSG_WriteStringf( &send, C2S_CONNECT" %i %i \"%s\" \"%s\"\n",
PROTOCOL_GOLDSRC_VERSION, challenge, protinfo, cls.userinfo ); PROTOCOL_GOLDSRC_VERSION, challenge, protinfo, cls.userinfo );
MSG_SeekToBit( &send, -8, SEEK_CUR ); // rewrite null terminator MSG_SeekToBit( &send, -8, SEEK_CUR ); // rewrite null terminator
CL_WriteSteamTicket( &send ); CL_WriteSteamTicket( &send );
@ -1172,7 +1172,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
Info_SetValueForKey( protinfo, "i", key, sizeof( protinfo )); Info_SetValueForKey( protinfo, "i", key, sizeof( protinfo ));
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i %i \"%s\" %d \"%s\"\n", Netchan_OutOfBandPrint( NS_CLIENT, adr, C2S_CONNECT" %i %i %i \"%s\" %d \"%s\"\n",
PROTOCOL_LEGACY_VERSION, qport, challenge, cls.userinfo, NET_LEGACY_EXT_SPLIT, protinfo ); PROTOCOL_LEGACY_VERSION, qport, challenge, cls.userinfo, NET_LEGACY_EXT_SPLIT, protinfo );
Con_Printf( "Trying to connect with legacy protocol\n" ); Con_Printf( "Trying to connect with legacy protocol\n" );
} }
@ -1195,7 +1195,7 @@ static void CL_SendConnectPacket( connprotocol_t proto, int challenge )
Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo )); Info_SetValueForKey( protinfo, "qport", qport, sizeof( protinfo ));
Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", extensions); Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", extensions);
Netchan_OutOfBandPrint( NS_CLIENT, adr, "connect %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, challenge, protinfo, cls.userinfo ); Netchan_OutOfBandPrint( NS_CLIENT, adr, C2S_CONNECT" %i %i \"%s\" \"%s\"\n", PROTOCOL_VERSION, challenge, protinfo, cls.userinfo );
Con_Printf( "Trying to connect with modern protocol\n" ); Con_Printf( "Trying to connect with modern protocol\n" );
} }
@ -1223,7 +1223,7 @@ static void CL_SendGetChallenge( netadr_t to )
// always send GoldSrc-styled getchallenge message // always send GoldSrc-styled getchallenge message
// Xash servers will ignore it but for GoldSrc it will help // Xash servers will ignore it but for GoldSrc it will help
// in auto-detection // in auto-detection
Netchan_OutOfBandPrint( NS_CLIENT, to, "getchallenge steam\n" ); Netchan_OutOfBandPrint( NS_CLIENT, to, C2S_GETCHALLENGE" steam\n" );
} }
/* /*
@ -1314,14 +1314,15 @@ static void CL_CheckForResend( void )
cls.connect_retry++; cls.connect_retry++;
if( bandwidthTest ) if( bandwidthTest )
{
Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size ); Con_Printf( "Connecting to %s... (retry #%i, fragment size %i)\n", cls.servername, cls.connect_retry, cls.max_fragment_size );
Netchan_OutOfBandPrint( NS_CLIENT, adr, C2S_BANDWIDTHTEST" %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
}
else else
{
Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry ); Con_Printf( "Connecting to %s... (retry #%i)\n", cls.servername, cls.connect_retry );
if( bandwidthTest )
Netchan_OutOfBandPrint( NS_CLIENT, adr, "bandwidth %i %i\n", PROTOCOL_VERSION, cls.max_fragment_size );
else
CL_SendGetChallenge( adr ); CL_SendGetChallenge( adr );
}
} }
static resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index ) static resource_t *CL_AddResource( resourcetype_t type, const char *name, int size, qboolean bFatalIfMissing, int index )
@ -1470,7 +1471,7 @@ static void CL_Rcon_f( void )
NET_Config( true, false ); // allow remote NET_Config( true, false ); // allow remote
Q_strncat( message, "rcon ", sizeof( message )); Q_strncat( message, C2S_RCON" ", sizeof( message ));
Q_strncat( message, rcon_password.string, sizeof( message )); Q_strncat( message, rcon_password.string, sizeof( message ));
Q_strncat( message, " ", sizeof( message ) ); Q_strncat( message, " ", sizeof( message ) );
@ -1746,10 +1747,10 @@ static void CL_LocalServers_f( void )
// send a broadcast packet // send a broadcast packet
adr.type = NA_BROADCAST; adr.type = NA_BROADCAST;
adr.port = MSG_BigShort( PORT_SERVER ); adr.port = MSG_BigShort( PORT_SERVER );
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION ); Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
adr.type = NA_MULTICAST_IP6; adr.type = NA_MULTICAST_IP6;
Netchan_OutOfBandPrint( NS_CLIENT, adr, "info %i", PROTOCOL_VERSION ); Netchan_OutOfBandPrint( NS_CLIENT, adr, A2A_INFO" %i", PROTOCOL_VERSION );
} }
/* /*
@ -1951,7 +1952,7 @@ static void CL_ParseStatusMessage( netadr_t from, sizebuf_t *msg )
if( len >= magiclen && !Q_strcmp( s + len - magiclen, magic )) if( len >= magiclen && !Q_strcmp( s + len - magiclen, magic ))
{ {
Netchan_OutOfBandPrint( NS_CLIENT, from, "info %i", PROTOCOL_LEGACY_VERSION ); Netchan_OutOfBandPrint( NS_CLIENT, from, A2A_INFO" %i", PROTOCOL_LEGACY_VERSION );
return; return;
} }
@ -2155,6 +2156,235 @@ static qboolean CL_IsFromConnectingServer( netadr_t from )
NET_CompareAdr( cls.serveradr, from ); NET_CompareAdr( cls.serveradr, from );
} }
static void CL_HandleTestPacket( netadr_t from, sizebuf_t *msg )
{
byte recv_buf[NET_MAX_FRAGMENT];
dword crcValue;
int realsize;
dword crcValue2 = 0;
// this message only used during connection
// it doesn't make sense after client_connect
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
crcValue = MSG_ReadLong( msg );
realsize = MSG_GetMaxBytes( msg ) - MSG_GetNumBytesRead( msg );
if( cls.max_fragment_size != MSG_GetMaxBytes( msg ))
{
if( cls.connect_retry >= CL_TEST_RETRIES )
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", FRAGMENT_DEFAULT_SIZE );
cls.connect_time = host.realtime;
return;
}
// if we waiting more than cl_timeout or packet was trashed
cls.connect_time = MAX_HEARTBEAT;
return; // just wait for a next responce
}
// reading test buffer
MSG_ReadBytes( msg, recv_buf, realsize );
// procssing the CRC
CRC32_ProcessBuffer( &crcValue2, recv_buf, realsize );
if( crcValue == crcValue2 )
{
// packet was sucessfully delivered, adjust the fragment size and get challenge
Con_DPrintf( "CRC %x is matched, get challenge, fragment size %d\n", crcValue, cls.max_fragment_size );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", cls.max_fragment_size );
cls.connect_time = host.realtime;
}
else
{
if( cls.connect_retry >= CL_TEST_RETRIES )
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime;
return;
}
Msg( "got testpacket, CRC mismatched 0x%08x should be 0x%08x, trying next fragment size %d\n", crcValue2, crcValue, cls.max_fragment_size >> 1 );
// trying the next size of packet
cls.connect_time = MAX_HEARTBEAT;
}
}
static void CL_ClientConnect( const char *c, netadr_t from, sizebuf_t *msg )
{
if( !CL_IsFromConnectingServer( from ))
return;
if( cls.state == ca_connected )
{
Con_DPrintf( S_ERROR "dup connect received. ignored\n");
return;
}
if( cls.legacymode != PROTO_GOLDSRC && !Q_strcmp( c, S2C_GOLDSRC_CONNECTION ))
{
Con_DPrintf( S_ERROR "GoldSrc client connect received but wasn't expected, ignored\n");
return;
}
CL_Reconnect( true );
UI_SetActiveMenu( cl.background );
}
static void CL_Print( const char *c, const char *args, netadr_t from, sizebuf_t *msg )
{
const char *s;
s = c[0] == A2C_GOLDSRC_PRINT ? args + 1 : MSG_ReadString( msg );
if( !COM_CheckStringEmpty( s ))
return;
Con_Printf( "Remote message from %s:\n", NET_AdrToString( from ));
Con_Printf( "%s%c", s, s[Q_strlen( s ) - 1] != '\n' ? '\n' : '\0' );
}
static void CL_Challenge( const char *c, netadr_t from )
{
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
// try to autodetect protocol by challenge response
if( !Q_strcmp( c, S2C_GOLDSRC_CHALLENGE ))
cls.legacymode = PROTO_GOLDSRC;
// challenge from the server we are connecting to
CL_SendConnectPacket( cls.legacymode, Q_atoi( Cmd_Argv( 1 )));
}
static void CL_ErrorMsg( const char *c, const char *args, netadr_t from, sizebuf_t *msg )
{
char formatted_msg[MAX_VA_STRING];
if( !CL_IsFromConnectingServer( from ))
return;
if( msg != NULL && !Q_strcmp( c, S2C_ERRORMSG ))
{
const char *s = MSG_ReadString( msg );
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", s );
}
else if( c[0] == S2C_GOLDSRC_REJECT )
{
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args + 1 );
}
else if( c[0] == S2C_GOLDSRC_REJECT_BADPASSWORD )
{
if( !Q_strnicmp( &c[1], "BADPASSWORD", 11 ))
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args + 12 );
else
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args + 1 );
}
// in case we're in console or it's classic mainui which doesn't support messageboxes
if( !UI_IsVisible() || !UI_ShowMessageBox( formatted_msg ))
Msg( "%s\n", formatted_msg );
// don't disconnect, errormsg is a FWGS extension and
// always followed by disconnect message
}
static void CL_Reject( const char *c, const char *args, netadr_t from )
{
// this message only used during connection
// it doesn't make sense after client_connect
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
CL_ErrorMsg( c, args, from, NULL );
// a disconnect message from the server, which will happen if the server
// dropped the connection but it is still getting packets from us
CL_Disconnect_f();
}
static void CL_ServerList( netadr_t from, sizebuf_t *msg )
{
if( !NET_IsMasterAdr( from ))
{
Con_Printf( S_WARN "unexpected server list packet from %s\n", NET_AdrToString( from ));
return;
}
// check the extra header
if( MSG_ReadByte( msg ) == 0x7f )
{
uint32_t key = MSG_ReadDword( msg );
if( cls.internetservers_key != key )
{
Con_Printf( S_WARN "unexpected server list packet from %s (invalid key)\n", NET_AdrToString( from ));
return;
}
MSG_ReadByte( msg ); // reserved byte
}
else
{
Con_Printf( S_WARN "invalid server list packet from %s (missing extra header)\n", NET_AdrToString( from ));
return;
}
// serverlist got from masterserver
while( MSG_GetNumBitsLeft( msg ) > 8 )
{
uint8_t addr[16];
netadr_t servadr;
if( from.type6 == NA_IP6 ) // IPv6 master server only sends IPv6 addresses
{
MSG_ReadBytes( msg, addr, sizeof( addr ));
NET_IP6BytesToNetadr( &servadr, addr );
servadr.type6 = NA_IP6;
}
else
{
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
servadr.type = NA_IP;
}
servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
// list is ends here
if( !servadr.port )
break;
NET_Config( true, false ); // allow remote
Netchan_OutOfBandPrint( NS_CLIENT, servadr, A2A_INFO" %i", PROTOCOL_VERSION );
}
if( cls.internetservers_pending )
{
UI_ResetPing();
cls.internetservers_pending = false;
}
}
/* /*
================= =================
CL_ConnectionlessPacket CL_ConnectionlessPacket
@ -2166,9 +2396,6 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
{ {
char *args; char *args;
const char *c; const char *c;
char buf[MAX_SYSPATH];
int len = sizeof( buf );
netadr_t servadr;
MSG_Clear( msg ); MSG_Clear( msg );
MSG_ReadLong( msg ); // skip the -1 MSG_ReadLong( msg ); // skip the -1
@ -2181,290 +2408,70 @@ static void CL_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), c ); Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), c );
// server connection // server connection
if( !Q_strcmp( c, "client_connect" ) || !Q_strcmp( c, S2C_CONNECTION )) if( !Q_strcmp( c, S2C_GOLDSRC_CONNECTION ) || !Q_strcmp( c, S2C_CONNECTION ))
{ {
if( !CL_IsFromConnectingServer( from )) CL_ClientConnect( c, from, msg );
return; }
else if( !Q_strcmp( c, A2A_INFO ))
{
CL_ParseStatusMessage( from, msg ); // server responding to a status broadcast
}
else if( !Q_strcmp( c, A2A_NETINFO ))
{
CL_ParseNETInfoMessage( from, args ); // server responding to a status broadcast
}
else if( c[0] == A2C_GOLDSRC_PRINT || !Q_strcmp( c, A2C_PRINT ))
{
CL_Print( c, args, from, msg );
}
else if( !Q_strcmp( c, S2C_BANDWIDTHTEST ))
{
CL_HandleTestPacket( from, msg );
}
else if( !Q_strcmp( c, A2A_PING ))
{
Netchan_OutOfBandPrint( NS_CLIENT, from, A2A_ACK );
}
else if( !Q_strcmp( c, A2A_GOLDSRC_PING ))
{
Netchan_OutOfBandPrint( NS_CLIENT, from, A2A_GOLDSRC_ACK );
}
else if( !Q_strcmp( c, A2A_ACK ) || !Q_strcmp( c, A2A_GOLDSRC_ACK ))
{
// no-op
}
else if( !Q_strcmp( c, S2C_CHALLENGE ) || !Q_strcmp( c, S2C_GOLDSRC_CHALLENGE ))
{
CL_Challenge( c, from );
}
else if( !Q_strcmp( c, S2C_REJECT ) || c[0] == S2C_GOLDSRC_REJECT || c[0] == S2C_GOLDSRC_REJECT_BADPASSWORD )
{
CL_Reject( c, args, from );
}
else if( !Q_strcmp( c, S2C_ERRORMSG ))
{
CL_ErrorMsg( c, args, from, msg );
}
else if( !Q_strcmp( c, M2A_SERVERSLIST ))
{
CL_ServerList( from, msg );
}
else
{
char buf[MAX_SYSPATH];
int len = sizeof( buf );
if( cls.state == ca_connected ) if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{ {
Con_DPrintf( S_ERROR "dup connect received. ignored\n"); // user out of band message (must be handled in SV_ConnectionlessPacket)
return; if( len > 0 )
} Netchan_OutOfBand( NS_SERVER, from, len, (byte *)buf );
if( cls.legacymode != PROTO_GOLDSRC && !Q_strcmp( c, S2C_CONNECTION ))
{
Con_DPrintf( S_ERROR "GoldSrc client connect received but wasn't expected, ignored\n");
return;
}
CL_Reconnect( true );
UI_SetActiveMenu( cl.background );
}
else if( !Q_strcmp( c, "info" ))
{
// server responding to a status broadcast
CL_ParseStatusMessage( from, msg );
}
else if( !Q_strcmp( c, "netinfo" ))
{
// server responding to a status broadcast
CL_ParseNETInfoMessage( from, args );
}
else if( !Q_strcmp( c, "cmd" ))
{
// remote command from gui front end
if( !NET_IsLocalAddress( from ))
{
Con_Printf( "Command packet from remote host. Ignored.\n" );
return;
}
#if XASH_SDL == 2
SDL_ShowWindow( host.hWnd );
#endif
args = MSG_ReadString( msg );
Cbuf_AddText( args );
Cbuf_AddText( "\n" );
}
else if( c[0] == 'l' )
{
char *s = args + 1;
Con_Printf( S_CYAN "r:" S_DEFAULT " %s", s );
if( !COM_CheckStringEmpty( s ) || s[Q_strlen( s ) - 1] != '\n' )
Con_Printf( "\n" );
}
else if( !Q_strcmp( c, "print" ))
{
// print command from somewhere
char *s = MSG_ReadString( msg );
Con_Printf( S_CYAN "r:" S_DEFAULT " %s", s );
if( !COM_CheckStringEmpty( s ) || s[Q_strlen( s ) - 1] != '\n' )
Con_Printf( "\n" );
}
else if( !Q_strcmp( c, "testpacket" ))
{
byte recv_buf[NET_MAX_FRAGMENT];
dword crcValue;
int realsize;
dword crcValue2 = 0;
// this message only used during connection
// it doesn't make sense after client_connect
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
crcValue = MSG_ReadLong( msg );
realsize = MSG_GetMaxBytes( msg ) - MSG_GetNumBytesRead( msg );
if( cls.max_fragment_size != MSG_GetMaxBytes( msg ))
{
if( cls.connect_retry >= CL_TEST_RETRIES )
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", FRAGMENT_DEFAULT_SIZE );
cls.connect_time = host.realtime;
return;
}
// if we waiting more than cl_timeout or packet was trashed
cls.connect_time = MAX_HEARTBEAT;
return; // just wait for a next responce
}
// reading test buffer
MSG_ReadBytes( msg, recv_buf, realsize );
// procssing the CRC
CRC32_ProcessBuffer( &crcValue2, recv_buf, realsize );
if( crcValue == crcValue2 )
{
// packet was sucessfully delivered, adjust the fragment size and get challenge
Con_DPrintf( "CRC %x is matched, get challenge, fragment size %d\n", crcValue, cls.max_fragment_size );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", cls.max_fragment_size );
cls.connect_time = host.realtime;
} }
else else
{ {
if( cls.connect_retry >= CL_TEST_RETRIES ) Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
{
// too many fails use default connection method
Con_Printf( "hi-speed connection is failed, use default method\n" );
CL_SendGetChallenge( from );
Cvar_SetValue( "cl_dlmax", FRAGMENT_MIN_SIZE );
cls.connect_time = host.realtime;
return;
}
Msg( "got testpacket, CRC mismatched 0x%08x should be 0x%08x, trying next fragment size %d\n", crcValue2, crcValue, cls.max_fragment_size >> 1 );
// trying the next size of packet
cls.connect_time = MAX_HEARTBEAT;
} }
} }
else if( !Q_strcmp( c, "ping" ))
{
// ping from somewhere
Netchan_OutOfBandPrint( NS_CLIENT, from, "ack" );
}
else if( !Q_strcmp( c, "challenge" ) || !Q_strcmp( c, S2C_CHALLENGE ))
{
// this message only used during connection
// it doesn't make sense after client_connect
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
// try to autodetect protocol by challenge response
if( !Q_strcmp( c, S2C_CHALLENGE ))
cls.legacymode = PROTO_GOLDSRC;
// challenge from the server we are connecting to
CL_SendConnectPacket( cls.legacymode, Q_atoi( Cmd_Argv( 1 )));
return;
}
else if( !Q_strcmp( c, "echo" ))
{
if( !CL_IsFromConnectingServer( from ))
return;
// echo request from server
Netchan_OutOfBandPrint( NS_CLIENT, from, "%s", Cmd_Argv( 1 ));
}
else if( !Q_strcmp( c, "disconnect" ))
{
// this message only used during connection
// it doesn't make sense after client_connect
if( cls.state != ca_connecting )
return;
if( !CL_IsFromConnectingServer( from ))
return;
// a disconnect message from the server, which will happen if the server
// dropped the connection but it is still getting packets from us
CL_Disconnect_f();
}
else if( !Q_strcmp( c, "errormsg" ) || c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD )
{
char formatted_msg[MAX_VA_STRING];
if( !CL_IsFromConnectingServer( from ))
return;
args = MSG_ReadString( msg );
if( c[0] == S2C_REJECT || c[0] == S2C_REJECT_BADPASSWORD )
args++; // skip one byte
Q_snprintf( formatted_msg, sizeof( formatted_msg ), "^3Server message^7\n%s", args );
// in case we're in console or it's classic mainui which doesn't support messageboxes
if( !UI_IsVisible() || !UI_ShowMessageBox( formatted_msg ))
Msg( "%s\n", formatted_msg );
CL_Disconnect_f();
}
else if( !Q_strcmp( c, "updatemsg" ))
{
// got an update message from master server
// show update dialog from menu
netadr_t adr;
qboolean preferStore = true;
if( !Q_strcmp( Cmd_Argv( 1 ), "nostore" ) )
preferStore = false;
// trust only hardcoded master server
if( NET_StringToAdr( MASTERSERVER_ADR, &adr ) )
{
if( NET_CompareAdr( from, adr ))
{
UI_ShowUpdateDialog( preferStore );
}
}
else
{
// in case we don't have master anymore
UI_ShowUpdateDialog( preferStore );
}
}
else if( !Q_strcmp( c, "f" ))
{
if( !NET_IsMasterAdr( from ))
{
Con_Printf( S_WARN "unexpected server list packet from %s\n", NET_AdrToString( from ));
return;
}
// check the extra header
if( MSG_ReadByte( msg ) == 0x7f )
{
uint32_t key = MSG_ReadDword( msg );
if( cls.internetservers_key != key )
{
Con_Printf( S_WARN "unexpected server list packet from %s (invalid key)\n", NET_AdrToString( from ));
return;
}
MSG_ReadByte( msg ); // reserved byte
}
else
{
Con_Printf( S_WARN "invalid server list packet from %s (missing extra header)\n", NET_AdrToString( from ));
return;
}
// serverlist got from masterserver
while( MSG_GetNumBitsLeft( msg ) > 8 )
{
uint8_t addr[16];
if( from.type6 == NA_IP6 ) // IPv6 master server only sends IPv6 addresses
{
MSG_ReadBytes( msg, addr, sizeof( addr ));
NET_IP6BytesToNetadr( &servadr, addr );
servadr.type6 = NA_IP6;
}
else
{
MSG_ReadBytes( msg, servadr.ip, sizeof( servadr.ip )); // 4 bytes for IP
servadr.type = NA_IP;
}
servadr.port = MSG_ReadShort( msg ); // 2 bytes for Port
// list is ends here
if( !servadr.port )
break;
NET_Config( true, false ); // allow remote
Netchan_OutOfBandPrint( NS_CLIENT, servadr, "info %i", PROTOCOL_VERSION );
}
if( cls.internetservers_pending )
{
UI_ResetPing();
cls.internetservers_pending = false;
}
}
else if( clgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{
// user out of band message (must be handled in CL_ConnectionlessPacket)
if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, (byte *)buf );
}
else Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
} }
/* /*

View File

@ -343,12 +343,6 @@ extern const char *const clc_strings[clc_lastmsg+1];
#define clc_goldsrc_requestcvarvalue2 11 #define clc_goldsrc_requestcvarvalue2 11
#define clc_goldsrc_lastmsg 11 #define clc_goldsrc_lastmsg 11
#define S2C_REJECT_BADPASSWORD '8'
#define S2C_REJECT '9'
#define S2C_CHALLENGE "A00000000"
#define S2C_CONNECTION "B"
#define A2C_PRINT 'l'
#define MAX_GOLDSRC_BACKUP_CMDS 8 #define MAX_GOLDSRC_BACKUP_CMDS 8
#define MAX_GOLDSRC_TOTAL_CMDS 16 #define MAX_GOLDSRC_TOTAL_CMDS 16
#define MAX_GOLDSRC_MODEL_BITS 10 #define MAX_GOLDSRC_MODEL_BITS 10
@ -358,4 +352,55 @@ extern const char *const clc_strings[clc_lastmsg+1];
#define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 )) #define MAX_GOLDSRC_EDICTS ( BIT( MAX_ENTITY_BITS ) + ( MAX_CLIENTS * 15 ))
#define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 ) #define LAST_GOLDSRC_EDICT ( BIT( MAX_ENTITY_BITS ) - 1 )
// from any to any (must be handled on both server and client)
#define A2A_PING "ping" // reply with A2A_ACK
#define A2A_ACK "ack" // no-op
#define A2A_INFO "info" // different format for client and server, see code
#define A2A_NETINFO "netinfo" // different format for client and server, see code
#define A2A_GOLDSRC_PING "i" // reply with A2A_GOLDSRC_ACK
#define A2A_GOLDSRC_ACK "j" // no-op
// from any to server
#define A2S_GOLDSRC_INFO 'T'
#define A2S_GOLDSRC_RULES 'V'
#define A2S_GOLDSRC_PLAYERS 'U'
// from server to any
#define S2A_GOLDSRC_INFO 'I'
#define S2A_GOLDSRC_RULES 'E'
#define S2A_GOLDSRC_PLAYERS 'D'
// from master to server
#define M2S_CHALLENGE "s"
#define M2S_NAT_CONNECT "c"
// from server to master
#define S2M_INFO "0\n"
// from client to server
#define C2S_BANDWIDTHTEST "bandwidth"
#define C2S_GETCHALLENGE "getchallenge"
#define C2S_CONNECT "connect"
#define C2S_RCON "rcon"
// from server to client
#define S2C_BANDWIDTHTEST "testpacket"
#define S2C_CHALLENGE "challenge"
#define S2C_CONNECTION "client_connect"
#define S2C_ERRORMSG "errormsg"
#define S2C_REJECT "disconnect"
#define S2C_GOLDSRC_REJECT_BADPASSWORD '8'
#define S2C_GOLDSRC_REJECT '9'
#define S2C_GOLDSRC_CHALLENGE "A00000000"
#define S2C_GOLDSRC_CONNECTION "B"
// from any to client
#define A2C_PRINT "print"
#define A2C_GOLDSRC_PRINT 'l'
// from master to client
#define M2A_SERVERSLIST "f"
#endif//NET_PROTOCOL_H #endif//NET_PROTOCOL_H

View File

@ -683,6 +683,6 @@ int SV_LightForEntity( edict_t *pEdict );
// //
// sv_query.c // sv_query.c
// //
qboolean SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from ); void SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from );
#endif//SERVER_H #endif//SERVER_H

View File

@ -131,7 +131,7 @@ static void SV_GetChallenge( netadr_t from )
} }
// send it back // send it back
Netchan_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, "challenge %i", svs.challenges[i].challenge ); Netchan_OutOfBandPrint( NS_SERVER, svs.challenges[i].adr, S2C_CHALLENGE" %i", svs.challenges[i].challenge );
} }
static int SV_GetFragmentSize( void *pcl, fragsize_t mode ) static int SV_GetFragmentSize( void *pcl, fragsize_t mode )
@ -194,9 +194,9 @@ void SV_RejectConnection( netadr_t from, const char *fmt, ... )
va_end( argptr ); va_end( argptr );
Con_Reportf( "%s connection refused. Reason: %s\n", NET_AdrToString( from ), text ); Con_Reportf( "%s connection refused. Reason: %s\n", NET_AdrToString( from ), text );
Netchan_OutOfBandPrint( NS_SERVER, from, "errormsg\n^1Server was reject the connection:^7 %s", text ); Netchan_OutOfBandPrint( NS_SERVER, from, S2C_ERRORMSG"\n^1Server was reject the connection:^7 %s", text );
Netchan_OutOfBandPrint( NS_SERVER, from, "print\n^1Server was reject the connection:^7 %s", text ); Netchan_OutOfBandPrint( NS_SERVER, from, A2C_PRINT"\n^1Server was reject the connection:^7 %s", text );
Netchan_OutOfBandPrint( NS_SERVER, from, "disconnect\n" ); Netchan_OutOfBandPrint( NS_SERVER, from, S2C_REJECT"\n" );
} }
/* /*
@ -456,7 +456,7 @@ static void SV_ConnectClient( netadr_t from )
Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", newcl->extensions ); Info_SetValueForKeyf( protinfo, "ext", sizeof( protinfo ), "%d", newcl->extensions );
// send the connect packet to the client // send the connect packet to the client
Netchan_OutOfBandPrint( NS_SERVER, from, "client_connect %s", protinfo ); Netchan_OutOfBandPrint( NS_SERVER, from, S2C_CONNECTION" %s", protinfo );
newcl->upstate = us_inactive; newcl->upstate = us_inactive;
newcl->connection_started = host.realtime; newcl->connection_started = host.realtime;
@ -604,7 +604,7 @@ void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... )
SV_BroadcastPrintf( cl, "%s was kicked with message: \"%s\"\n", cl->name, buf ); SV_BroadcastPrintf( cl, "%s was kicked with message: \"%s\"\n", cl->name, buf );
SV_ClientPrintf( cl, "You were kicked from the game with message: \"%s\"\n", buf ); SV_ClientPrintf( cl, "You were kicked from the game with message: \"%s\"\n", buf );
if( cl->useragent[0] ) if( cl->useragent[0] )
Netchan_OutOfBandPrint( NS_SERVER, cl->netchan.remote_address, "errormsg\nKicked with message:\n%s\n", buf ); Netchan_OutOfBandPrint( NS_SERVER, cl->netchan.remote_address, S2C_ERRORMSG"\nKicked with message:\n%s\n", buf );
} }
else else
{ {
@ -612,7 +612,7 @@ void SV_KickPlayer( sv_client_t *cl, const char *fmt, ... )
SV_BroadcastPrintf( cl, "%s was kicked\n", cl->name ); SV_BroadcastPrintf( cl, "%s was kicked\n", cl->name );
SV_ClientPrintf( cl, "You were kicked from the game\n" ); SV_ClientPrintf( cl, "You were kicked from the game\n" );
if( cl->useragent[0] ) if( cl->useragent[0] )
Netchan_OutOfBandPrint( NS_SERVER, cl->netchan.remote_address, "errormsg\nYou were kicked from the game\n" ); Netchan_OutOfBandPrint( NS_SERVER, cl->netchan.remote_address, S2C_ERRORMSG"\nYou were kicked from the game\n" );
} }
SV_DropClient( cl, false ); SV_DropClient( cl, false );
@ -720,7 +720,7 @@ static void SV_FlushRedirect( netadr_t adr, int dest, char *buf )
switch( dest ) switch( dest )
{ {
case RD_PACKET: case RD_PACKET:
Netchan_OutOfBandPrint( NS_SERVER, adr, "print\n%s", buf ); Netchan_OutOfBandPrint( NS_SERVER, adr, A2C_PRINT"\n%s", buf );
break; break;
case RD_CLIENT: case RD_CLIENT:
if( !sv.current_client ) return; // client not set if( !sv.current_client ) return; // client not set
@ -960,7 +960,23 @@ static void SV_Info( netadr_t from, int protocolVersion )
Info_SetValueForKey( s, "host", temp, sizeof( s )); Info_SetValueForKey( s, "host", temp, sizeof( s ));
} }
Netchan_OutOfBandPrint( NS_SERVER, from, "info\n%s", s ); Netchan_OutOfBandPrint( NS_SERVER, from, A2A_INFO"\n%s", s );
}
static void SV_ConnectNatClient( netadr_t from )
{
netadr_t to;
if( !sv_nat.value || !NET_IsMasterAdr( from ))
return;
if( !NET_StringToAdr( Cmd_Argv( 1 ), &to ))
return;
if( NET_IsReservedAdr( to ))
return;
SV_Info( to, PROTOCOL_VERSION );
} }
/* /*
@ -994,7 +1010,7 @@ static void SV_BuildNetAnswer( netadr_t from )
{ {
// send error unsupported protocol // send error unsupported protocol
Info_SetValueForKey( string, "neterror", "protocol", sizeof( string )); Info_SetValueForKey( string, "neterror", "protocol", sizeof( string ));
Netchan_OutOfBandPrint( NS_SERVER, from, "netinfo %i %i %s\n", context, type, string ); Netchan_OutOfBandPrint( NS_SERVER, from, A2A_NETINFO" %i %i %s\n", context, type, string );
return; return;
} }
@ -1065,19 +1081,7 @@ static void SV_BuildNetAnswer( netadr_t from )
break; break;
} }
Netchan_OutOfBandPrint( NS_SERVER, from, "netinfo %i %i %s\n", context, type, string ); Netchan_OutOfBandPrint( NS_SERVER, from, A2A_NETINFO" %i %i %s\n", context, type, string );
}
/*
================
SV_Ping
Just responds with an acknowledgement
================
*/
static void SV_Ping( netadr_t from )
{
Netchan_OutOfBandPrint( NS_SERVER, from, "ack" );
} }
/* /*
@ -3148,17 +3152,14 @@ connectionless packets.
*/ */
void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg ) void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
{ {
char *args; const char *pcmd, *args;
const char *pcmd;
char buf[MAX_SYSPATH];
int len = sizeof( buf );
// prevent flooding from banned address // prevent flooding from banned address
if( SV_CheckIP( &from ) ) if( SV_CheckIP( &from ))
return; return;
MSG_Clear( msg ); MSG_Clear( msg );
MSG_ReadLong( msg );// skip the -1 marker MSG_SeekToBit( msg, sizeof( uint32_t ) << 3, SEEK_CUR ); // skip the -1 marker
args = MSG_ReadStringLine( msg ); args = MSG_ReadStringLine( msg );
Cmd_TokenizeString( args ); Cmd_TokenizeString( args );
@ -3168,29 +3169,79 @@ void SV_ConnectionlessPacket( netadr_t from, sizebuf_t *msg )
if( sv_log_outofband.value ) if( sv_log_outofband.value )
Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), pcmd ); Con_Reportf( "%s: %s : %s\n", __func__, NET_AdrToString( from ), pcmd );
if( !Q_strcmp( pcmd, "ping" )) SV_Ping( from ); if( !svs.initialized )
else if( !Q_strcmp( pcmd, "ack" )) SV_Ack( from );
else if( !Q_strcmp( pcmd, "info" )) SV_Info( from, Q_atoi( Cmd_Argv( 1 )));
else if( !Q_strcmp( pcmd, "bandwidth" )) SV_TestBandWidth( from );
else if( !Q_strcmp( pcmd, "getchallenge" )) SV_GetChallenge( from );
else if( !Q_strcmp( pcmd, "connect" )) SV_ConnectClient( from );
else if( !Q_strcmp( pcmd, "rcon" )) SV_RemoteCommand( from, msg );
else if( !Q_strcmp( pcmd, "netinfo" )) SV_BuildNetAnswer( from );
else if( !Q_strcmp( pcmd, "s" )) SV_AddToMaster( from, msg );
else if( !Q_strcmp( pcmd, "i" )) NET_SendPacket( NS_SERVER, 5, "\xFF\xFF\xFF\xFFj", from ); // A2A_PING
else if( SV_SourceQuery_HandleConnnectionlessPacket( pcmd, from )) { } // function handles replies
else if( !Q_strcmp( pcmd, "c" ) && sv_nat.value && NET_IsMasterAdr( from ))
{ {
netadr_t to; // only process rcon if server not initialized
if( NET_StringToAdr( Cmd_Argv( 1 ), &to ) && !NET_IsReservedAdr( to )) if( !Q_strcmp( pcmd, C2S_RCON ))
SV_Info( to, PROTOCOL_VERSION ); SV_RemoteCommand( net_from, &net_message );
return;
} }
else if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
if( pcmd[0] == A2S_GOLDSRC_INFO || pcmd[0] == A2S_GOLDSRC_PLAYERS || pcmd[0] == A2S_GOLDSRC_RULES )
{ {
// user out of band message (must be handled in CL_ConnectionlessPacket) SV_SourceQuery_HandleConnnectionlessPacket( pcmd, from );
if( len > 0 ) Netchan_OutOfBand( NS_SERVER, from, len, (byte*)buf ); }
else if( !Q_strcmp( pcmd, A2A_NETINFO ))
{
SV_BuildNetAnswer( from );
}
else if( !Q_strcmp( pcmd, A2A_INFO ))
{
SV_Info( from, Q_atoi( Cmd_Argv( 1 )));
}
else if( !Q_strcmp( pcmd, M2S_CHALLENGE ))
{
SV_AddToMaster( from, msg );
}
else if( !Q_strcmp( pcmd, M2S_NAT_CONNECT ))
{
SV_ConnectNatClient( from );
}
else if( !Q_strcmp( pcmd, C2S_BANDWIDTHTEST ))
{
SV_TestBandWidth( from );
}
else if( !Q_strcmp( pcmd, C2S_GETCHALLENGE ))
{
SV_GetChallenge( from );
}
else if( !Q_strcmp( pcmd, C2S_CONNECT ))
{
SV_ConnectClient( from );
}
else if( !Q_strcmp( pcmd, A2A_PING ))
{
Netchan_OutOfBandPrint( NS_SERVER, from, A2A_ACK );
}
else if( !Q_strcmp( pcmd, A2A_GOLDSRC_PING ))
{
Netchan_OutOfBandPrint( NS_SERVER, from, A2A_GOLDSRC_ACK );
}
else if( !Q_strcmp( pcmd, C2S_RCON ))
{
SV_RemoteCommand( from, msg );
}
else if( !Q_strcmp( pcmd, A2A_ACK ) || !Q_strcmp( pcmd, A2A_GOLDSRC_ACK ))
{
SV_Ack( from );
}
else
{
char buf[MAX_SYSPATH];
int len = sizeof( buf );
if( svgame.dllFuncs.pfnConnectionlessPacket( &from, args, buf, &len ))
{
// user out of band message (must be handled in CL_ConnectionlessPacket)
if( len > 0 )
Netchan_OutOfBand( NS_SERVER, from, len, (byte*)buf );
}
else
{
Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
}
} }
else Con_DPrintf( S_ERROR "bad connectionless packet from %s:\n%s\n", NET_AdrToString( from ), args );
} }
/* /*

View File

@ -973,7 +973,7 @@ static void SV_GenerateTestPacket( void )
// write packet base data // write packet base data
MSG_Init( &svs.testpacket, "BandWidthTest", svs.testpacket_buf, maxsize ); MSG_Init( &svs.testpacket, "BandWidthTest", svs.testpacket_buf, maxsize );
MSG_WriteLong( &svs.testpacket, -1 ); MSG_WriteLong( &svs.testpacket, -1 );
MSG_WriteString( &svs.testpacket, "testpacket" ); MSG_WriteString( &svs.testpacket, S2C_BANDWIDTHTEST );
svs.testpacket_crcpos = svs.testpacket.pData + MSG_GetNumBytesWritten( &svs.testpacket ); svs.testpacket_crcpos = svs.testpacket.pData + MSG_GetNumBytesWritten( &svs.testpacket );
MSG_WriteDword( &svs.testpacket, 0 ); // to be changed by crc MSG_WriteDword( &svs.testpacket, 0 ); // to be changed by crc

View File

@ -389,23 +389,7 @@ static void SV_ReadPackets( void )
// check for connectionless packet (0xffffffff) first // check for connectionless packet (0xffffffff) first
if( MSG_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 ) if( MSG_GetMaxBytes( &net_message ) >= 4 && *(int *)net_message.pData == -1 )
{ {
if( !svs.initialized ) SV_ConnectionlessPacket( net_from, &net_message );
{
char *args;
const char *c;
MSG_Clear( &net_message );
MSG_ReadLong( &net_message );// skip the -1 marker
args = MSG_ReadStringLine( &net_message );
Cmd_TokenizeString( args );
c = Cmd_Argv( 0 );
if( !Q_strcmp( c, "rcon" ))
SV_RemoteCommand( net_from, &net_message );
}
else SV_ConnectionlessPacket( net_from, &net_message );
continue; continue;
} }
@ -730,7 +714,7 @@ Master will validate challenge and this server to public list
void SV_AddToMaster( netadr_t from, sizebuf_t *msg ) void SV_AddToMaster( netadr_t from, sizebuf_t *msg )
{ {
uint challenge, challenge2, heartbeat_challenge; uint challenge, challenge2, heartbeat_challenge;
char s[MAX_INFO_STRING] = "0\n"; // skip 2 bytes of header char s[MAX_INFO_STRING] = S2M_INFO; // skip 2 bytes of header
int clients, bots; int clients, bots;
double last_heartbeat; double last_heartbeat;
const int len = sizeof( s ); const int len = sizeof( s );

View File

@ -16,15 +16,6 @@ GNU General Public License for more details.
#include "common.h" #include "common.h"
#include "server.h" #include "server.h"
#define SOURCE_QUERY_DETAILS 'T'
#define SOURCE_QUERY_DETAILS_RESPONSE 'I'
#define SOURCE_QUERY_RULES 'V'
#define SOURCE_QUERY_RULES_RESPONSE 'E'
#define SOURCE_QUERY_PLAYERS 'U'
#define SOURCE_QUERY_PLAYERS_RESPONSE 'D'
/* /*
================== ==================
SV_SourceQuery_Details SV_SourceQuery_Details
@ -41,7 +32,8 @@ static void SV_SourceQuery_Details( netadr_t from )
MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer )); MSG_Init( &buf, "TSourceEngineQuery", answer, sizeof( answer ));
MSG_WriteByte( &buf, SOURCE_QUERY_DETAILS_RESPONSE ); MSG_WriteDword( &buf, 0xFFFFFFFFU );
MSG_WriteByte( &buf, S2A_GOLDSRC_INFO );
MSG_WriteByte( &buf, PROTOCOL_VERSION ); MSG_WriteByte( &buf, PROTOCOL_VERSION );
MSG_WriteString( &buf, hostname.string ); MSG_WriteString( &buf, hostname.string );
@ -69,7 +61,7 @@ static void SV_SourceQuery_Details( netadr_t from )
MSG_WriteByte( &buf, GI->secure ); MSG_WriteByte( &buf, GI->secure );
MSG_WriteString( &buf, XASH_VERSION ); MSG_WriteString( &buf, XASH_VERSION );
Netchan_OutOfBand( NS_SERVER, from, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf )); NET_SendPacket( NS_SERVER, MSG_GetNumBytesWritten( &buf ), MSG_GetData( &buf ), from );
} }
/* /*
@ -87,7 +79,8 @@ static void SV_SourceQuery_Rules( netadr_t from )
MSG_Init( &buf, "TSourceEngineQueryRules", answer, sizeof( answer )); MSG_Init( &buf, "TSourceEngineQueryRules", answer, sizeof( answer ));
MSG_WriteByte( &buf, SOURCE_QUERY_RULES_RESPONSE ); MSG_WriteDword( &buf, 0xFFFFFFFFU );
MSG_WriteByte( &buf, S2A_GOLDSRC_RULES );
pos = MSG_GetNumBitsWritten( &buf ); pos = MSG_GetNumBitsWritten( &buf );
MSG_WriteShort( &buf, 0 ); MSG_WriteShort( &buf, 0 );
@ -117,7 +110,7 @@ static void SV_SourceQuery_Rules( netadr_t from )
MSG_SeekToBit( &buf, pos, SEEK_SET ); MSG_SeekToBit( &buf, pos, SEEK_SET );
MSG_WriteShort( &buf, cvar_count ); MSG_WriteShort( &buf, cvar_count );
Netchan_OutOfBand( NS_SERVER, from, total, MSG_GetData( &buf )); NET_SendPacket( NS_SERVER, total, MSG_GetData( &buf ), from );
} }
} }
@ -139,7 +132,8 @@ static void SV_SourceQuery_Players( netadr_t from )
MSG_Init( &buf, "TSourceEngineQueryPlayers", answer, sizeof( answer )); MSG_Init( &buf, "TSourceEngineQueryPlayers", answer, sizeof( answer ));
MSG_WriteByte( &buf, SOURCE_QUERY_PLAYERS_RESPONSE ); MSG_WriteDword( &buf, 0xFFFFFFFFU );
MSG_WriteByte( &buf, S2A_GOLDSRC_PLAYERS );
pos = MSG_GetNumBitsWritten( &buf ); pos = MSG_GetNumBitsWritten( &buf );
MSG_WriteByte( &buf, 0 ); MSG_WriteByte( &buf, 0 );
@ -168,7 +162,7 @@ static void SV_SourceQuery_Players( netadr_t from )
MSG_SeekToBit( &buf, pos, SEEK_SET ); MSG_SeekToBit( &buf, pos, SEEK_SET );
MSG_WriteByte( &buf, count ); MSG_WriteByte( &buf, count );
Netchan_OutOfBand( NS_SERVER, from, total, MSG_GetData( &buf )); NET_SendPacket( NS_SERVER, total, MSG_GetData( &buf ), from );
} }
} }
@ -177,24 +171,18 @@ static void SV_SourceQuery_Players( netadr_t from )
SV_SourceQuery_HandleConnnectionlessPacket SV_SourceQuery_HandleConnnectionlessPacket
================== ==================
*/ */
qboolean SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from ) void SV_SourceQuery_HandleConnnectionlessPacket( const char *c, netadr_t from )
{ {
switch( c[0] ) switch( c[0] )
{ {
case SOURCE_QUERY_DETAILS: case A2S_GOLDSRC_INFO:
SV_SourceQuery_Details( from ); SV_SourceQuery_Details( from );
return true; break;
case A2S_GOLDSRC_RULES:
case SOURCE_QUERY_RULES:
SV_SourceQuery_Rules( from ); SV_SourceQuery_Rules( from );
return true; break;
case A2S_GOLDSRC_PLAYERS:
case SOURCE_QUERY_PLAYERS:
SV_SourceQuery_Players( from ); SV_SourceQuery_Players( from );
return true; break;
default:
return false;
} }
return false;
} }