void SVC_Info( netadr_t* from ) { int i, count; char *gamedir; char infostring[MAX_INFO_STRING]; char* g_password; if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) { return; } g_password = Cvar_VariableString("g_password"); // don't count privateclients count = 0; for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) { if ( getclient(i)->state >= CS_CONNECTED ) { count++; } } infostring[0] = 0; // echo back the parameter to status. so servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) ); Info_SetValueForKey( infostring, "protocol", va("%i", protocol->integer)); Info_SetValueForKey( infostring, "hostname", sv_hostname->string ); Info_SetValueForKey( infostring, "mapname", mapname->string ); Info_SetValueForKey( infostring, "clients", va( "%i", count ) ); #ifdef xDEBUG Info_SetValueForKey( infostring, "sv_maxclients", va( "%i", sv_maxclients->integer - sv_privateClients->integer ) ); #else Info_SetValueForKey( infostring, "sv_maxclients", va( "%i", sv_maxclients->integer - sv_privateClients->integer ) ); #endif Info_SetValueForKey( infostring, "gametype", g_gametype->string ); Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ) ); Info_SetValueForKey(infostring, "codextended", va("v%d", CURRENTBUILD)); if ( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ) ); } if ( sv_maxPing->integer ) { Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ) ); } gamedir = Cvar_VariableString( "fs_game" ); if ( *gamedir ) { Info_SetValueForKey( infostring, "game", gamedir ); } Info_SetValueForKey( infostring, "sv_allowAnonymous", va( "%i", sv_allowAnonymous->integer ) ); if(*g_password) Info_SetValueForKey( infostring, "pswrd", "1"); else Info_SetValueForKey( infostring, "pswrd", "0"); NET_OutOfBandPrint( NS_SERVER, *from, "infoResponse\n%s", infostring ); }
void SVC_Status( netadr_t* from ) { char player[1024]; char status[MAX_MSGLEN]; int i; client_t *cl; int/*playerState_t*/ *ps; int statusLength; int playerLength; char infostring[MAX_INFO_STRING]; int custom_mod = 0; char *fs_game = Cvar_VariableString("fs_game"); if(fs_game && *fs_game) custom_mod = 1; challenge_t* challenge; if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) { return; } strcpy( infostring, Cvar_InfoString( 4 )); //1.5 uses 8196 Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) ); status[0] = 0; statusLength = 0; for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { cl = getclient(i); if ( cl->state >= CS_CONNECTED ) { //ps = SV_GameClientNum( i ); Com_sprintf( player, sizeof( player ), "%i %i \"%s\"\n", SV_GetClientScore(cl), cl->ping, cl->name ); playerLength = strlen( player ); if ( statusLength + playerLength >= sizeof( status ) ) { break; // can't hold any more } strcpy( status + statusLength, player ); statusLength += playerLength; } } #if CODPATCH == 5 if(sv_disableClientConsole->integer) Info_SetValueForKey(infostring, "con_disabled", va("%i", sv_disableClientConsole->integer)); #endif char *g_password = Cvar_VariableString("g_password"); Info_SetValueForKey(infostring, "pswrd", va("%i", (g_password && *g_password) ? 1 : 0)); Info_SetValueForKey(infostring, "mod", va("%i", custom_mod)); NET_OutOfBandPrint( NS_SERVER, *from, "statusResponse\n%s\n%s", infostring, status ); }
/* ================= SVC_GameCompleteStatus NERVE - SMF - Send serverinfo cvars, etc to master servers when game complete. Useful for tracking global player stats. ================= */ void SVC_GameCompleteStatus( netadr_t from ) { char player[1024]; char status[MAX_MSGLEN]; int i; client_t *cl; playerState_t *ps; int statusLength; int playerLength; char infostring[MAX_INFO_STRING]; // ignore if we are in single player if ( SV_GameIsSinglePlayer() ) { return; } //bani - bugtraq 12534 if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) { return; } strcpy( infostring, Cvar_InfoString( CVAR_SERVERINFO | CVAR_SERVERINFO_NOUPDATE ) ); // echo back the parameter to status. so master servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) ); // add "demo" to the sv_keywords if restricted if ( Cvar_VariableValue( "fs_restrict" ) ) { char keywords[MAX_INFO_STRING]; Com_sprintf( keywords, sizeof( keywords ), "ettest %s", Info_ValueForKey( infostring, "sv_keywords" ) ); Info_SetValueForKey( infostring, "sv_keywords", keywords ); } status[0] = 0; statusLength = 0; for ( i = 0 ; i < sv_maxclients->integer ; i++ ) { cl = &svs.clients[i]; if ( cl->state >= CS_CONNECTED ) { ps = SV_GameClientNum( i ); Com_sprintf( player, sizeof( player ), "%i %i \"%s\"\n", ps->persistant[PERS_SCORE], cl->ping, cl->name ); playerLength = strlen( player ); if ( statusLength + playerLength >= sizeof( status ) ) { break; // can't hold any more } strcpy( status + statusLength, player ); statusLength += playerLength; } } NET_OutOfBandPrint( NS_SERVER, from, "gameCompleteStatus\n%s\n%s", infostring, status ); }
/* ================ SVC_Status Responds with all the info that qplug or qspy can see about the server and all connected players. Used for getting detailed information after the simple info query. ================ */ void SVC_Status( netadr_t from, const Cmd::Args& args ) { char player[ 1024 ]; char status[ MAX_MSGLEN ]; int i; client_t *cl; playerState_t *ps; int statusLength; int playerLength; char infostring[ MAX_INFO_STRING ]; //bani - bugtraq 12534 if ( args.Argc() > 1 && !SV_VerifyChallenge( args.Argv(1).c_str() ) ) { return; } Q_strncpyz( infostring, Cvar_InfoString( CVAR_SERVERINFO, false ), MAX_INFO_STRING ); if ( args.Argc() > 1 ) { // echo back the parameter to status. so master servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", args.Argv(1).c_str(), false ); } status[ 0 ] = 0; statusLength = 0; for ( i = 0; i < sv_maxclients->integer; i++ ) { cl = &svs.clients[ i ]; if ( cl->state >= CS_CONNECTED ) { ps = SV_GameClientNum( i ); Com_sprintf( player, sizeof( player ), "%i %i \"%s\"\n", ps->persistant[ PERS_SCORE ], cl->ping, cl->name ); playerLength = strlen( player ); if ( statusLength + playerLength >= (int) sizeof( status ) ) { break; // can't hold any more } strcpy( status + statusLength, player ); statusLength += playerLength; } } NET_OutOfBandPrint( NS_SERVER, from, "statusResponse\n%s\n%s", infostring, status ); }
/* ================ SVC_Info Responds with a short info message that should be enough to determine if a user is interested in a server to do a full status ================ */ void SVC_Info( netadr_t from ) { int i, count; const char *gamedir; char infostring[MAX_INFO_STRING]; #if defined RTCW_MP const char *antilag; // DHM - Nerve #ifdef UPDATE_SERVER return; #endif #endif // RTCW_XX #if defined RTCW_ET const char *antilag; const char *weaprestrict; const char *balancedteams; // ignore if we are in single player if ( SV_GameIsSinglePlayer() ) { return; } #endif // RTCW_XX #if !defined RTCW_ET // ignore if we are in single player if ( Cvar_VariableValue( "g_gametype" ) == GT_SINGLE_PLAYER ) { return; } #endif // RTCW_XX #if defined RTCW_ET //bani - bugtraq 12534 if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) { return; } #endif // RTCW_XX // don't count privateclients count = 0; for ( i = sv_privateClients->integer ; i < sv_maxclients->integer ; i++ ) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; } } infostring[0] = 0; // echo back the parameter to status. so servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) ); Info_SetValueForKey( infostring, "protocol", va( "%i", PROTOCOL_VERSION ) ); Info_SetValueForKey( infostring, "hostname", sv_hostname->string ); #if defined RTCW_ET Info_SetValueForKey( infostring, "serverload", va( "%i", svs.serverLoad ) ); #endif // RTCW_XX Info_SetValueForKey( infostring, "mapname", sv_mapname->string ); Info_SetValueForKey( infostring, "clients", va( "%i", count ) ); Info_SetValueForKey( infostring, "sv_maxclients", va( "%i", sv_maxclients->integer - sv_privateClients->integer ) ); #if !defined RTCW_ET Info_SetValueForKey( infostring, "gametype", va( "%i", sv_gametype->integer ) ); #else Info_SetValueForKey( infostring, "gametype", Cvar_VariableString( "g_gametype" ) ); #endif // RTCW_XX Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ) ); if ( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ) ); } if ( sv_maxPing->integer ) { Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ) ); } gamedir = Cvar_VariableString( "fs_game" ); if ( *gamedir ) { Info_SetValueForKey( infostring, "game", gamedir ); } Info_SetValueForKey( infostring, "sv_allowAnonymous", va( "%i", sv_allowAnonymous->integer ) ); // Rafael gameskill #if !defined RTCW_ET Info_SetValueForKey( infostring, "gameskill", va( "%i", sv_gameskill->integer ) ); #else // Info_SetValueForKey (infostring, "gameskill", va ("%i", sv_gameskill->integer)); #endif // RTCW_XX // done #if !defined RTCW_SP Info_SetValueForKey( infostring, "friendlyFire", va( "%i", sv_friendlyFire->integer ) ); // NERVE - SMF Info_SetValueForKey( infostring, "maxlives", va( "%i", sv_maxlives->integer ? 1 : 0 ) ); // NERVE - SMF #if !defined RTCW_ET Info_SetValueForKey( infostring, "tourney", va( "%i", sv_tourney->integer ) ); // NERVE - SMF #endif // RTCW_XX #if defined RTCW_ET Info_SetValueForKey( infostring, "needpass", va( "%i", sv_needpass->integer ? 1 : 0 ) ); #endif // RTCW_XX Info_SetValueForKey( infostring, "gamename", GAMENAME_STRING ); // Arnout: to be able to filter out Quake servers // TTimo antilag = Cvar_VariableString( "g_antilag" ); if ( antilag ) { Info_SetValueForKey( infostring, "g_antilag", antilag ); } #endif // RTCW_XX #if defined RTCW_ET weaprestrict = Cvar_VariableString( "g_heavyWeaponRestriction" ); if ( weaprestrict ) { Info_SetValueForKey( infostring, "weaprestrict", weaprestrict ); } balancedteams = Cvar_VariableString( "g_balancedteams" ); if ( balancedteams ) { Info_SetValueForKey( infostring, "balancedteams", balancedteams ); } #endif // RTCW_XX NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring ); }
/* ================== SV_DirectConnect A "connect" OOB command has been received ================== */ void SV_DirectConnect( netadr_t from ) { char userinfo[MAX_INFO_STRING]; int i; client_t *cl, *newcl; client_t temp; sharedEntity_t *ent; int clientNum; int version; int qport; int challenge; char *password; int startIndex; char *denied; int count; char *ip; Com_DPrintf ("SVC_DirectConnect ()\n"); // Check whether this client is banned. if ( SV_IsBanned( &from, qfalse ) ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nYou are banned from this server.\n" ); Com_DPrintf( " rejected connect from %s (banned)\n", NET_AdrToString(from) ); return; } Q_strncpyz( userinfo, Cmd_Argv(1), sizeof(userinfo) ); version = atoi( Info_ValueForKey( userinfo, "protocol" ) ); if ( version != PROTOCOL_VERSION ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nServer uses protocol version %i (yours is %i).\n", PROTOCOL_VERSION, version ); Com_DPrintf (" rejected connect from version %i\n", version); return; } challenge = atoi( Info_ValueForKey( userinfo, "challenge" ) ); qport = atoi( Info_ValueForKey( userinfo, "qport" ) ); // quick reject for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { /* This was preventing sv_reconnectlimit from working. It seems like commenting this out has solved the problem. HOwever, if there is a future problem then it could be this. if ( cl->state == CS_FREE ) { continue; } */ if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { if (( svs.time - cl->lastConnectTime) < (sv_reconnectlimit->integer * 1000)) { NET_OutOfBandPrint( NS_SERVER, from, "print\nReconnect rejected : too soon\n" ); Com_DPrintf ("%s:reconnect rejected : too soon\n", NET_AdrToString (from)); return; } break; } } // don't let "ip" overflow userinfo string if ( NET_IsLocalAddress (from) ) ip = "localhost"; else ip = (char *)NET_AdrToString( from ); if( ( strlen( ip ) + strlen( userinfo ) + 4 ) >= MAX_INFO_STRING ) { NET_OutOfBandPrint( NS_SERVER, from, "print\nUserinfo string length exceeded. " "Try removing setu cvars from your config.\n" ); return; } Info_SetValueForKey( userinfo, "ip", ip ); // see if the challenge is valid (localhost clients don't need to challenge) if (!NET_IsLocalAddress(from)) { // Verify the received challenge against the expected challenge if (!SV_VerifyChallenge(challenge, from)) { NET_OutOfBandPrint( NS_SERVER, from, "print\nIncorrect challenge for your address.\n" ); return; } } newcl = &temp; Com_Memset (newcl, 0, sizeof(client_t)); // if there is already a slot for this ip, reuse it for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( cl->state == CS_FREE ) { continue; } if ( NET_CompareBaseAdr( from, cl->netchan.remoteAddress ) && ( cl->netchan.qport == qport || from.port == cl->netchan.remoteAddress.port ) ) { Com_Printf ("%s:reconnect\n", NET_AdrToString (from)); newcl = cl; // VVFIXME - both SOF2 and Wolf remove this call, claiming it blows away the user's info // disconnect the client from the game first so any flags the // player might have are dropped GVM_ClientDisconnect( newcl - svs.clients ); // goto gotnewcl; } } // find a client slot // if "sv_privateClients" is set > 0, then that number // of client slots will be reserved for connections that // have "password" set to the value of "sv_privatePassword" // Info requests will report the maxclients as if the private // slots didn't exist, to prevent people from trying to connect // to a full server. // This is to allow us to reserve a couple slots here on our // servers so we can play without having to kick people. // check for privateClient password password = Info_ValueForKey( userinfo, "password" ); if ( !strcmp( password, sv_privatePassword->string ) ) { startIndex = 0; } else { // skip past the reserved slots startIndex = sv_privateClients->integer; } newcl = NULL; for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { cl = &svs.clients[i]; if (cl->state == CS_FREE) { newcl = cl; break; } } if ( !newcl ) { if ( NET_IsLocalAddress( from ) ) { count = 0; for ( i = startIndex; i < sv_maxclients->integer ; i++ ) { cl = &svs.clients[i]; if (cl->netchan.remoteAddress.type == NA_BOT) { count++; } } // if they're all bots if (count >= sv_maxclients->integer - startIndex) { SV_DropClient(&svs.clients[sv_maxclients->integer - 1], "only bots on server"); newcl = &svs.clients[sv_maxclients->integer - 1]; } else { Com_Error( ERR_FATAL, "server is full on local connect\n" ); return; } } else { const char *SV_GetStringEdString(char *refSection, char *refName); NET_OutOfBandPrint( NS_SERVER, from, va("print\n%s\n", SV_GetStringEdString("MP_SVGAME","SERVER_IS_FULL"))); Com_DPrintf ("Rejected a connection.\n"); return; } } // we got a newcl, so reset the reliableSequence and reliableAcknowledge cl->reliableAcknowledge = 0; cl->reliableSequence = 0; gotnewcl: // build a new connection // accept the new client // this is the only place a client_t is ever initialized *newcl = temp; clientNum = newcl - svs.clients; ent = SV_GentityNum( clientNum ); newcl->gentity = ent; // save the challenge newcl->challenge = challenge; // save the address Netchan_Setup (NS_SERVER, &newcl->netchan , from, qport); // save the userinfo Q_strncpyz( newcl->userinfo, userinfo, sizeof(newcl->userinfo) ); // get the game a chance to reject this connection or modify the userinfo denied = GVM_ClientConnect( clientNum, qtrue, qfalse ); // firstTime = qtrue if ( denied ) { NET_OutOfBandPrint( NS_SERVER, from, "print\n%s\n", denied ); Com_DPrintf ("Game rejected a connection: %s.\n", denied); return; } SV_UserinfoChanged( newcl ); // send the connect packet to the client NET_OutOfBandPrint( NS_SERVER, from, "connectResponse" ); Com_DPrintf( "Going from CS_FREE to CS_CONNECTED for %s\n", newcl->name ); newcl->state = CS_CONNECTED; newcl->nextSnapshotTime = svs.time; newcl->lastPacketTime = svs.time; newcl->lastConnectTime = svs.time; // when we receive the first packet from the client, we will // notice that it is from a different serverid and that the // gamestate message was not just sent, forcing a retransmit newcl->gamestateMessageNum = -1; newcl->lastUserInfoChange = 0; //reset the delay newcl->lastUserInfoCount = 0; //reset the count // if this was the first client on the server, or the last client // the server can hold, send a heartbeat to the master. count = 0; for (i=0,cl=svs.clients ; i < sv_maxclients->integer ; i++,cl++) { if ( svs.clients[i].state >= CS_CONNECTED ) { count++; } } if ( count == 1 || count == sv_maxclients->integer ) { SV_Heartbeat_f(); } }
/* ================ SVC_Info Responds with a short info message that should be enough to determine if a user is interested in a server to do a full status ================ */ void SVC_Info( netadr_t from, const Cmd::Args& args ) { int i, count, botCount; char infostring[ MAX_INFO_STRING ]; if ( args.Argc() < 2 ) { return; } const char *challenge = args.Argv(1).c_str(); /* * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory. */ // A maximum challenge length of 128 should be more than plenty. if ( strlen( challenge ) > MAX_CHALLENGE_LEN ) { return; } //bani - bugtraq 12534 if ( !SV_VerifyChallenge( challenge ) ) { return; } SV_ResolveMasterServers(); // don't count privateclients botCount = count = 0; for ( i = sv_privateClients->integer; i < sv_maxclients->integer; i++ ) { if ( svs.clients[ i ].state >= CS_CONNECTED ) { if ( SV_IsBot(&svs.clients[ i ]) ) { ++botCount; } else { ++count; } } } infostring[ 0 ] = 0; // echo back the parameter to status. so servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", challenge, false ); // If the master server listens on IPv4 and IPv6, we want to send the // most recent challenge received from it over the OTHER protocol for ( i = 0; i < MAX_MASTER_SERVERS; i++ ) { // First, see if the challenge was sent by this master server if ( !NET_CompareBaseAdr( from, masterServerAddr[ i ].ipv4 ) && !NET_CompareBaseAdr( from, masterServerAddr[ i ].ipv6 ) ) { continue; } // It was - if the saved challenge is for the other protocol, send it and record the current one if ( challenges[ i ].type == NA_IP || challenges[ i ].type == NA_IP6 ) { if ( challenges[ i ].type != from.type ) { Info_SetValueForKey( infostring, "challenge2", challenges[ i ].text, false ); challenges[ i ].type = from.type; strcpy( challenges[ i ].text, challenge ); break; } } // Otherwise record the current one regardless and check the next server challenges[ i ].type = from.type; strcpy( challenges[ i ].text, challenge ); } Info_SetValueForKey( infostring, "protocol", va( "%i", PROTOCOL_VERSION ), false ); Info_SetValueForKey( infostring, "hostname", sv_hostname->string, false ); Info_SetValueForKey( infostring, "serverload", va( "%i", svs.serverLoad ), false ); Info_SetValueForKey( infostring, "mapname", sv_mapname->string, false ); Info_SetValueForKey( infostring, "clients", va( "%i", count ), false ); Info_SetValueForKey( infostring, "bots", va( "%i", botCount ), false ); Info_SetValueForKey( infostring, "sv_maxclients", va( "%i", sv_maxclients->integer - sv_privateClients->integer ), false ); Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ), false ); if ( sv_statsURL->string[0] ) { Info_SetValueForKey( infostring, "stats", sv_statsURL->string, false ); } #ifdef USE_VOIP if ( sv_voip->integer ) { Info_SetValueForKey( infostring, "voip", va( "%i", sv_voip->integer ), false ); } #endif if ( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ), false ); } if ( sv_maxPing->integer ) { Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ), false ); } Info_SetValueForKey( infostring, "gamename", GAMENAME_STRING, false ); // Arnout: to be able to filter out Quake servers NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring ); }
/* ================ SVC_Info Responds with a short info message that should be enough to determine if a user is interested in a server to do a full status ================ */ void SVC_Info(netadr_t from) { int i, count; char *gamedir, infostring[MAX_INFO_STRING], *antilag, *weaprestrict, *balancedteams; // ignore if we are in single player if(SV_GameIsSinglePlayer()) { return; } //bani - bugtraq 12534 if(!SV_VerifyChallenge(Cmd_Argv(1))) { return; } /* * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory. */ // A maximum challenge length of 128 should be more than plenty. if(strlen(Cmd_Argv(1)) > 128) { return; } #if defined (UPDATE_SERVER) return; #endif // don't count privateclients count = 0; for(i = sv_privateClients->integer; i < sv_maxclients->integer; i++) { if(svs.clients[i].state >= CS_CONNECTED) { count++; } } infostring[0] = 0; // echo back the parameter to status. so servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey(infostring, "challenge", Cmd_Argv(1)); Info_SetValueForKey(infostring, "protocol", va("%i", com_protocol->integer)); Info_SetValueForKey(infostring, "hostname", sv_hostname->string); Info_SetValueForKey(infostring, "serverload", va("%i", svs.serverLoad)); Info_SetValueForKey(infostring, "mapname", sv_mapname->string); Info_SetValueForKey(infostring, "clients", va("%i", count)); Info_SetValueForKey(infostring, "sv_maxclients", va("%i", sv_maxclients->integer - sv_privateClients->integer)); //Info_SetValueForKey( infostring, "gametype", va("%i", sv_gametype->integer ) ); Info_SetValueForKey(infostring, "gametype", Cvar_VariableString("g_gametype")); Info_SetValueForKey(infostring, "pure", va("%i", sv_pure->integer)); #ifdef USE_VOIP if (sv_voip->integer) { Info_SetValueForKey( infostring, "voip", va("%i", sv_voip->integer ) ); } #endif if(sv_minPing->integer) { Info_SetValueForKey(infostring, "minPing", va("%i", sv_minPing->integer)); } if(sv_maxPing->integer) { Info_SetValueForKey(infostring, "maxPing", va("%i", sv_maxPing->integer)); } gamedir = Cvar_VariableString("fs_game"); if(*gamedir) { Info_SetValueForKey(infostring, "game", gamedir); } Info_SetValueForKey(infostring, "sv_allowAnonymous", va("%i", sv_allowAnonymous->integer)); // Rafael gameskill // Info_SetValueForKey (infostring, "gameskill", va ("%i", sv_gameskill->integer)); // done Info_SetValueForKey(infostring, "friendlyFire", va("%i", sv_friendlyFire->integer)); // NERVE - SMF Info_SetValueForKey(infostring, "maxlives", va("%i", sv_maxlives->integer ? 1 : 0)); // NERVE - SMF Info_SetValueForKey(infostring, "needpass", va("%i", sv_needpass->integer ? 1 : 0)); Info_SetValueForKey(infostring, "gamename", GAMENAME_STRING); // Arnout: to be able to filter out Quake servers // TTimo antilag = Cvar_VariableString("g_antilag"); if(antilag) { Info_SetValueForKey(infostring, "g_antilag", antilag); } weaprestrict = Cvar_VariableString("g_heavyWeaponRestriction"); if(weaprestrict) { Info_SetValueForKey(infostring, "weaprestrict", weaprestrict); } balancedteams = Cvar_VariableString("g_balancedteams"); if(balancedteams) { Info_SetValueForKey(infostring, "balancedteams", balancedteams); } NET_OutOfBandPrint(NS_SERVER, from, "infoResponse\n%s", infostring); }
/* ================ SVC_Info Responds with a short info message that should be enough to determine if a user is interested in a server to do a full status ================ */ void SVC_Info( netadr_t from ) { int i, count; char *gamedir; char infostring[ MAX_INFO_STRING ]; //bani - bugtraq 12534 if ( !SV_VerifyChallenge( Cmd_Argv( 1 ) ) ) { return; } /* * Check whether Cmd_Argv(1) has a sane length. This was not done in the original Quake3 version which led * to the Infostring bug discovered by Luigi Auriemma. See http://aluigi.altervista.org/ for the advisory. */ // A maximum challenge length of 128 should be more than plenty. if ( strlen( Cmd_Argv( 1 ) ) > 128 ) { return; } // don't count privateclients count = 0; for ( i = sv_privateClients->integer; i < sv_maxclients->integer; i++ ) { if ( svs.clients[ i ].state >= CS_CONNECTED ) { count++; } } infostring[ 0 ] = 0; // echo back the parameter to status. so servers can use it as a challenge // to prevent timed spoofed reply packets that add ghost servers Info_SetValueForKey( infostring, "challenge", Cmd_Argv( 1 ) ); Info_SetValueForKey( infostring, "protocol", va( "%i", PROTOCOL_VERSION ) ); Info_SetValueForKey( infostring, "hostname", sv_hostname->string ); Info_SetValueForKey( infostring, "serverload", va( "%i", svs.serverLoad ) ); Info_SetValueForKey( infostring, "mapname", sv_mapname->string ); Info_SetValueForKey( infostring, "clients", va( "%i", count ) ); Info_SetValueForKey( infostring, "sv_maxclients", va( "%i", sv_maxclients->integer - sv_privateClients->integer ) ); Info_SetValueForKey( infostring, "pure", va( "%i", sv_pure->integer ) ); #ifdef USE_VOIP if ( sv_voip->integer ) { Info_SetValueForKey( infostring, "voip", va( "%i", sv_voip->integer ) ); } #endif if ( sv_minPing->integer ) { Info_SetValueForKey( infostring, "minPing", va( "%i", sv_minPing->integer ) ); } if ( sv_maxPing->integer ) { Info_SetValueForKey( infostring, "maxPing", va( "%i", sv_maxPing->integer ) ); } gamedir = Cvar_VariableString( "fs_game" ); if ( *gamedir ) { Info_SetValueForKey( infostring, "game", gamedir ); } Info_SetValueForKey( infostring, "gamename", GAMENAME_STRING ); // Arnout: to be able to filter out Quake servers NET_OutOfBandPrint( NS_SERVER, from, "infoResponse\n%s", infostring ); }