/* * CL_ParseGetServersResponseMessage * Handle a reply from getservers message to master server */ static void CL_ParseGetServersResponseMessage( msg_t *msg, qboolean extended ) { const char *header; char adrString[64]; qbyte addr[16]; unsigned short port; netadr_t adr; MSG_BeginReading( msg ); MSG_ReadLong( msg ); // skip the -1 //jump over the command name header = ( extended ? "getserversExtResponse" : "getserversResponse" ); if( !MSG_SkipData( msg, strlen( header ) ) ) { Com_Printf( "Invalid master packet ( missing %s )\n", header ); return; } while( msg->readcount + 7 <= msg->cursize ) { char prefix = MSG_ReadChar( msg ); switch( prefix ) { case '\\': MSG_ReadData( msg, addr, 4 ); port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped. Q_snprintfz( adrString, sizeof( adrString ), "%u.%u.%u.%u:%u", addr[0], addr[1], addr[2], addr[3], port ); break; case '/': if( extended ) { MSG_ReadData( msg, addr, 16 ); port = ShortSwap( MSG_ReadShort( msg ) ); // both endians need this swapped. Q_snprintfz( adrString, sizeof( adrString ), "[%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x]:%hu", addr[ 0], addr[ 1], addr[ 2], addr[ 3], addr[ 4], addr[ 5], addr[ 6], addr[ 7], addr[ 8], addr[ 9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15], port ); } else { Com_Printf( "Invalid master packet ( IPv6 prefix in a non-extended response )\n" ); return; } break; default: Com_Printf( "Invalid master packet ( missing separator )\n" ); return; } if( port == 0 ) // last server seen return; Com_DPrintf( "%s\n", adrString ); if( !NET_StringToAddress( adrString, &adr ) ) { Com_Printf( "Bad address: %s\n", adrString ); continue; } CL_AddServerToList( &masterList, adrString, 0 ); } }
/* * TV_Relay_ParseServerMessage */ void TV_Relay_ParseServerMessage( relay_t *relay, msg_t *msg ) { int cmd; assert( relay && relay->state >= CA_HANDSHAKE ); assert( msg ); // parse the message while( relay->state >= CA_HANDSHAKE ) { if( msg->readcount > msg->cursize ) TV_Relay_Error( relay, "Bad server message" ); cmd = MSG_ReadByte( msg ); /*if( cmd == -1 ) Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, "EOF" ); else Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, !svc_strings[cmd] ? "bad" : svc_strings[cmd] );*/ if( cmd == -1 ) break; // other commands switch( cmd ) { default: TV_Relay_Error( relay, "Illegible server message" ); case svc_nop: break; case svc_servercmd: if( !relay->reliable ) { int cmdNum = MSG_ReadLong( msg ); if( cmdNum < 0 ) TV_Relay_Error( relay, "Invalid cmdNum value" ); if( cmdNum <= relay->lastExecutedServerCommand ) { MSG_ReadString( msg ); // read but ignore break; } relay->lastExecutedServerCommand = cmdNum; } // fall trough case svc_servercs: // configstrings from demo files. they don't have acknowledge TV_Relay_ParseServerCommand( relay, msg ); break; case svc_serverdata: if( relay->upstream->demo.playing ) TV_Relay_ReconnectClients( relay ); if( relay->state == CA_HANDSHAKE ) { Cbuf_Execute(); // make sure any stuffed commands are done TV_Relay_ParseServerData( relay, msg ); } else { return; // ignore rest of the packet (serverdata is always sent alone) } break; case svc_spawnbaseline: TV_Relay_ParseBaseline( relay, msg ); break; case svc_download: //CL_ParseDownload( msg ); break; case svc_clcack: if( relay->reliable ) TV_Relay_Error( relay, "clack message while reliable" ); MSG_ReadLong( msg ); // reliableAcknowledge MSG_ReadLong( msg ); // ucmdAcknowledged break; case svc_frame: TV_Relay_ParseFrame( relay, msg ); break; case svc_demoinfo: { int length; length = MSG_ReadLong( msg ); MSG_SkipData( msg, length ); } break; case svc_playerinfo: case svc_packetentities: case svc_match: TV_Relay_Error( relay, "Out of place frame data" ); break; case svc_extension: if( 1 ) { int len; MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length MSG_SkipData( msg, len ); // command data } break; } } }
/* * CL_ParseServerMessage */ void CL_ParseServerMessage( msg_t *msg ) { int cmd; if( cl_shownet->integer == 1 ) { Com_Printf( "%i ", msg->cursize ); } else if( cl_shownet->integer >= 2 ) { Com_Printf( "------------------\n" ); } // parse the message while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Bad server message" ); break; } cmd = MSG_ReadByte( msg ); if( cl_debug_serverCmd->integer & 4 ) { if( cmd == -1 ) Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, "EOF" ); else Com_Printf( "%3i:CMD %i %s\n", msg->readcount-1, cmd, !svc_strings[cmd] ? "bad" : svc_strings[cmd] ); } if( cmd == -1 ) { SHOWNET( msg, "END OF MESSAGE" ); break; } if( cl_shownet->integer >= 2 ) { if( !svc_strings[cmd] ) Com_Printf( "%3i:BAD CMD %i\n", msg->readcount-1, cmd ); else SHOWNET( msg, svc_strings[cmd] ); } // other commands switch( cmd ) { default: Com_Error( ERR_DROP, "CL_ParseServerMessage: Illegible server message" ); break; case svc_nop: // Com_Printf( "svc_nop\n" ); break; case svc_servercmd: if( !cls.reliable ) { int cmdNum = MSG_ReadLong( msg ); if( cmdNum < 0 ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: Invalid cmdNum value received: %i\n", cmdNum ); return; } if( cmdNum <= cls.lastExecutedServerCommand ) { MSG_ReadString( msg ); // read but ignore break; } cls.lastExecutedServerCommand = cmdNum; } // fall through case svc_servercs: // configstrings from demo files. they don't have acknowledge CL_ParseServerCommand( msg ); break; case svc_serverdata: if( cls.state == CA_HANDSHAKE ) { Cbuf_Execute(); // make sure any stuffed commands are done CL_ParseServerData( msg ); } else { return; // ignore rest of the packet (serverdata is always sent alone) } break; case svc_spawnbaseline: CL_ParseBaseline( msg ); break; case svc_download: CL_ParseDownload( msg ); break; case svc_clcack: if( cls.reliable ) { Com_Error( ERR_DROP, "CL_ParseServerMessage: clack message for reliable client\n" ); return; } cls.reliableAcknowledge = (unsigned)MSG_ReadLong( msg ); cls.ucmdAcknowledged = (unsigned)MSG_ReadLong( msg ); if( cl_debug_serverCmd->integer & 4 ) Com_Printf( "svc_clcack:reliable cmd ack:%i ucmdack:%i\n", cls.reliableAcknowledge, cls.ucmdAcknowledged ); break; case svc_frame: CL_ParseFrame( msg ); break; case svc_demoinfo: assert( cls.demo.playing ); { size_t meta_data_maxsize; MSG_ReadLong( msg ); MSG_ReadLong( msg ); cls.demo.meta_data_realsize = (size_t)MSG_ReadLong( msg ); meta_data_maxsize = (size_t)MSG_ReadLong( msg ); // sanity check if( cls.demo.meta_data_realsize > meta_data_maxsize ) { cls.demo.meta_data_realsize = meta_data_maxsize; } if( cls.demo.meta_data_realsize > sizeof( cls.demo.meta_data ) ) { cls.demo.meta_data_realsize = sizeof( cls.demo.meta_data ); } MSG_ReadData( msg, cls.demo.meta_data, cls.demo.meta_data_realsize ); MSG_SkipData( msg, meta_data_maxsize - cls.demo.meta_data_realsize ); } break; case svc_playerinfo: case svc_packetentities: case svc_match: Com_Error( ERR_DROP, "Out of place frame data" ); break; case svc_extension: if( 1 ) { int ext, len; ext = MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length switch( ext ) { default: // unsupported MSG_SkipData( msg, len ); break; } } break; } } CL_AddNetgraph(); // // if recording demos, copy the message out // // // we don't know if it is ok to save a demo message until // after we have parsed the frame // if( cls.demo.recording && !cls.demo.waiting ) CL_WriteDemoMessage( msg ); }
/* * SV_ParseClientMessage * The current message is parsed for the given client */ void SV_ParseClientMessage( client_t *client, msg_t *msg ) { int c; char *s; qboolean move_issued; unsigned int cmdNum; if( !msg ) return; SV_UpdateActivity(); // only allow one move command move_issued = qfalse; while( 1 ) { if( msg->readcount > msg->cursize ) { Com_Printf( "SV_ParseClientMessage: badread\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Bad message" ); return; } c = MSG_ReadByte( msg ); if( c == -1 ) break; switch( c ) { default: Com_Printf( "SV_ParseClientMessage: unknown command char\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: Unknown command char" ); return; case clc_nop: break; case clc_move: { if( move_issued ) return; // someone is trying to cheat... move_issued = qtrue; SV_ParseMoveCommand( client, msg ); } break; case clc_svcack: { if( client->reliable ) { Com_Printf( "SV_ParseClientMessage: svack from reliable client\n" ); SV_DropClient( client, DROP_TYPE_GENERAL, "Error: svack from reliable client" ); return; } cmdNum = MSG_ReadLong( msg ); if( cmdNum < client->reliableAcknowledge || cmdNum > client->reliableSent ) { //SV_DropClient( client, DROP_TYPE_GENERAL, "Error: bad server command acknowledged" ); return; } client->reliableAcknowledge = cmdNum; } break; case clc_clientcommand: if( !client->reliable ) { cmdNum = MSG_ReadLong( msg ); if( cmdNum <= client->clientCommandExecuted ) { s = MSG_ReadString( msg ); // read but ignore continue; } client->clientCommandExecuted = cmdNum; } s = MSG_ReadString( msg ); SV_ExecuteUserCommand( client, s ); if( client->state == CS_ZOMBIE ) return; // disconnect command break; case clc_extension: if( 1 ) { int ext, len; ext = MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length switch( ext ) { default: // unsupported MSG_SkipData( msg, len ); break; } } break; } } }
/* * TV_Upstream_ParseServerMessage */ void TV_Upstream_ParseServerMessage( upstream_t *upstream, msg_t *msg ) { int cmd; assert( upstream && upstream->state >= CA_HANDSHAKE ); assert( msg ); // parse the message while( upstream->state >= CA_HANDSHAKE ) { if( msg->readcount > msg->cursize ) TV_Upstream_Error( upstream, "Bad server message" ); cmd = MSG_ReadByte( msg ); if( cmd == -1 ) break; // other commands switch( cmd ) { default: TV_Upstream_Error( upstream, "Illegible server message" ); case svc_nop: break; case svc_servercmd: if( !upstream->reliable ) { int cmdNum = MSG_ReadLong( msg ); if( cmdNum < 0 ) TV_Upstream_Error( upstream, "Invalid cmdNum value" ); if( cmdNum <= upstream->lastExecutedServerCommand ) { MSG_ReadString( msg ); // read but ignore break; } upstream->lastExecutedServerCommand = cmdNum; } // fall trough case svc_servercs: // configstrings from demo files. they don't have acknowledge TV_Upstream_ParseServerCommand( upstream, msg ); break; case svc_serverdata: if( upstream->state == CA_HANDSHAKE ) { Cbuf_Execute(); // make sure any stuffed commands are done FS_Rescan(); // FIXME? TV_Upstream_ParseServerData( upstream, msg ); } else { return; // ignore rest of the packet (serverdata is always sent alone) } break; case svc_spawnbaseline: TV_Upstream_ParseBaseline( upstream, msg ); break; case svc_download: //CL_ParseDownload( msg ); break; case svc_clcack: if( upstream->reliable ) TV_Upstream_Error( upstream, "clack message while reliable" ); upstream->reliableAcknowledge = (unsigned)MSG_ReadLong( msg ); MSG_ReadLong( msg ); // ucmdAcknowledged break; case svc_frame: TV_Upstream_ParseFrame( upstream, msg ); break; case svc_demoinfo: { int length; assert( upstream->demo.playing ); length = MSG_ReadLong( msg ); MSG_SkipData( msg, length ); } break; case svc_playerinfo: case svc_packetentities: case svc_match: TV_Upstream_Error( upstream, "Out of place frame data" ); break; case svc_extension: if( 1 ) { int len; MSG_ReadByte( msg ); // extension id MSG_ReadByte( msg ); // version number len = MSG_ReadShort( msg ); // command length MSG_SkipData( msg, len ); // command data } break; } } // if recording demos, copy the message out if( upstream->demo.recording && !upstream->demo.waiting ) TV_Upstream_WriteDemoMessage( upstream, msg ); }