/** * @brief Responds with all the info that the server browser can see * @sa SV_StatusString */ static void SVC_Status (struct net_stream* s) { if (SVC_RateLimitAddress(*s)) { Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s)); return; } /* Allow getstatus to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */ if (SVC_RateLimit(&outboundLeakyBucket, 10, 100)) { Com_DPrintf(DEBUG_SERVER, "SVC_Status: rate limit exceeded, dropping request\n"); return; } dbuffer msg; NET_WriteByte(&msg, svc_oob); NET_WriteRawString(&msg, SV_CMD_PRINT "\n"); char info[MAX_INFO_STRING]; NET_WriteRawString(&msg, Cvar_Serverinfo(info, sizeof(info))); NET_WriteRawString(&msg, "\n"); client_t* cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) { if (cl->state <= cs_free) continue; char player[1024]; Com_sprintf(player, sizeof(player), "%i \"%s\"\n", svs.ge->ClientGetTeamNum(*cl->player), cl->name); NET_WriteRawString(&msg, player); } NET_WriteMsg(s, msg); }
/* * =============== * SV_StatusString * * Builds the string that is sent as heartbeats and status replies * =============== */ char *SV_StatusString(void) { char player[1024]; static char status[MAX_MSGLEN - 16]; int i; client_t *cl; int statusLength; int playerLength; strcpy(status, Cvar_Serverinfo()); strcat(status, "\n"); statusLength = strlen(status); for (i = 0; i < maxclients->value; i++) { cl = &svs.clients[i]; if ((cl->state == cs_connected) || (cl->state == cs_spawned)) { Com_sprintf(player, sizeof(player), "%i %i \"%s\"\n", cl->edict->client->ps.stats[STAT_FRAGS], cl->ping, cl->name); playerLength = strlen(player); if (statusLength + playerLength >= sizeof(status)) { break; // can't hold any more } strcpy(status + statusLength, player); statusLength += playerLength; } } return status; }
/* ================== SV_ShowServerinfo_f Dumps the serverinfo info string ================== */ void SV_ShowServerinfo_f (void) { // Info_Print (Cvar_Serverinfo()); // r1ch: this is a client issued command ! char *s; char *p; int flip; s = Cvar_Serverinfo(); // skip beginning \\ char s++; flip = 0; p = s; // make it more readable while (p[0]) { if (p[0] == '\\') { if (flip) p[0] = '\n'; else p[0] = '='; flip ^= 1; } p++; } SV_ClientPrintf (sv_client, PRINT_HIGH, "%s\n", s); // end r1ch fix }
/* ================== SV_ShowServerinfo_f Dumps the serverinfo info string ================== */ void SV_ShowServerinfo_f(void){ cvar_t *cvar; char line[MAX_STRING_CHARS]; if(!sv_client){ //print to server console Info_Print(Cvar_Serverinfo()); return; } for(cvar = cvar_vars; cvar; cvar = cvar->next){ if(!(cvar->flags & CVAR_SERVERINFO)) continue; //only print serverinfo cvars snprintf(line, MAX_STRING_CHARS, "%s %s\n", cvar->name, cvar->string); SV_ClientPrintf(sv_client, PRINT_MEDIUM, line); } }
/** * @brief Responds with all the info that the server browser can see * @sa SV_StatusString */ static void SVC_Status (struct net_stream *s) { client_t *cl; char player[1024]; dbuffer msg; NET_WriteByte(&msg, clc_oob); NET_WriteRawString(&msg, "print\n"); NET_WriteRawString(&msg, Cvar_Serverinfo()); NET_WriteRawString(&msg, "\n"); cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { if (cl->state > cs_free) { Com_sprintf(player, sizeof(player), "%i \"%s\"\n", svs.ge->ClientGetTeamNum(cl->player), cl->name); NET_WriteRawString(&msg, player); } } NET_WriteMsg(s, msg); }
/* * SV_Serverinfo_f * Examine or change the serverinfo string */ static void SV_Serverinfo_f( void ) { Com_Printf( "Server info settings:\n" ); Info_Print( Cvar_Serverinfo() ); }
/* * SV_LongInfoString * Builds the string that is sent as heartbeats and status replies */ static char *SV_LongInfoString( qboolean fullStatus ) { char tempstr[1024] = { 0 }; const char *gametype; static char status[MAX_MSGLEN - 16]; int i, bots, count; client_t *cl; size_t statusLength; size_t tempstrLength; Q_strncpyz( status, Cvar_Serverinfo(), sizeof( status ) ); // convert "g_gametype" to "gametype" gametype = Info_ValueForKey( status, "g_gametype" ); if( gametype ) { Info_RemoveKey( status, "g_gametype" ); Info_SetValueForKey( status, "gametype", gametype ); } statusLength = strlen( status ); bots = 0; count = 0; for( i = 0; i < sv_maxclients->integer; i++ ) { cl = &svs.clients[i]; if( cl->state >= CS_CONNECTED ) { if( cl->edict->r.svflags & SVF_FAKECLIENT || cl->tvclient ) bots++; count++; } } if( bots ) Q_snprintfz( tempstr, sizeof( tempstr ), "\\bots\\%i", bots ); Q_snprintfz( tempstr + strlen( tempstr ), sizeof( tempstr ) - strlen( tempstr ), "\\clients\\%i%s", count, fullStatus ? "\n" : "" ); tempstrLength = strlen( tempstr ); if( statusLength + tempstrLength >= sizeof( status ) ) return status; // can't hold any more Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength ); statusLength += tempstrLength; if ( fullStatus ) { for( i = 0; i < sv_maxclients->integer; i++ ) { cl = &svs.clients[i]; if( cl->state >= CS_CONNECTED ) { Q_snprintfz( tempstr, sizeof( tempstr ), "%i %i \"%s\" %i\n", cl->edict->r.client->r.frags, cl->ping, cl->name, cl->edict->s.team ); tempstrLength = strlen( tempstr ); if( statusLength + tempstrLength >= sizeof( status ) ) break; // can't hold any more Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength ); statusLength += tempstrLength; } } } return status; }
/* =========== SV_ServerInfo_f Examine serverinfo string =========== */ void SV_ServerInfo_f( void ) { Msg( "Server info settings:\n" ); Info_Print( Cvar_Serverinfo( )); }
/* * SV_ShowServerinfo_f * Dumps the serverinfo info string */ static void SV_ShowServerinfo_f( client_t *client ) { Info_Print( Cvar_Serverinfo() ); }
/* * Dumps the serverinfo info string */ void SV_ShowServerinfo_f(void) { Info_Print(Cvar_Serverinfo()); }
/* * TV_Downstream_LongInfoString * Builds the string that is sent as heartbeats and status replies */ static char *TV_Downstream_LongInfoString( bool fullStatus ) { char tempstr[1024] = { 0 }; const char *p; static char status[MAX_MSGLEN - 16]; int i, count; upstream_t *upstream; size_t statusLength; size_t tempstrLength; Q_strncpyz( status, Cvar_Serverinfo(), sizeof( status ) ); p = Q_strlocate( status, "tv_maxclients", 0 ); if( p ) // master server expects a sv_maxclients cvar, so hack the name in status[p - status] = 's'; statusLength = strlen( status ); count = 0; for( i = 0; i < tv_maxclients->integer; i++ ) { if( tvs.clients[i].state >= CS_CONNECTED ) count++; } Q_snprintfz( tempstr, sizeof( tempstr ), "\\tv\\%i", 1 ); Q_snprintfz( tempstr + strlen( tempstr ), sizeof( tempstr ) - strlen( tempstr ), "\\clients\\%i%s", count, fullStatus ? "\n" : "" ); tempstrLength = strlen( tempstr ); if( statusLength + tempstrLength >= sizeof( status ) ) return status; // can't hold any more Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength ); statusLength += tempstrLength; if ( fullStatus ) { for( i = 0; i < tvs.numupstreams; i++ ) { upstream = tvs.upstreams[i]; if( upstream && upstream->relay.state > CA_CONNECTING ) { relay_t *relay = &upstream->relay; if( relay->state >= CA_ACTIVE ) { int numplayers; numplayers = TV_Relay_NumPlayers( relay ); Q_snprintfz( tempstr, sizeof( tempstr ), "%i \"%s\" %i \"%s\" %i\n", i+1, upstream->name, relay->delay/1000, relay->levelname, numplayers ); tempstrLength = strlen( tempstr ); if( statusLength + tempstrLength >= sizeof( status ) ) break; // can't hold any more Q_strncpyz( status + statusLength, tempstr, sizeof( status ) - statusLength ); statusLength += tempstrLength; } } } } return status; }