/** * @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); }
/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream *s) { client_t *cl; dbuffer msg; char infoGlobal[MAX_INFO_STRING] = ""; NET_WriteByte(&msg, clc_oob); NET_WriteRawString(&msg, "teaminfo\n"); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); NET_WriteString(&msg, infoGlobal); cl = NULL; while ((cl = SV_GetNextClient(cl)) != NULL) { if (cl->state >= cs_connected) { char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }
/** * @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); }
/** * @brief Responds with teaminfo such as free team num * @sa CL_ParseTeamInfoMessage */ static void SVC_TeamInfo (struct net_stream* s) { if (SVC_RateLimitAddress(*s)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit from %s exceeded, dropping request\n", NET_StreamToString(s)); return; } /* Allow getinfo to be DoSed relatively easily, but prevent excess outbound bandwidth usage when being flooded inbound */ if (SVC_RateLimit(&outboundLeakyBucket)) { Com_DPrintf(DEBUG_SERVER, "SVC_TeamInfo: rate limit exceeded, dropping request\n"); return; } char infoGlobal[MAX_INFO_STRING] = ""; Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_teamplay", Cvar_GetString("sv_teamplay")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxteams", Cvar_GetString("sv_maxteams")); Info_SetValueForKey(infoGlobal, sizeof(infoGlobal), "sv_maxplayersperteam", Cvar_GetString("sv_maxplayersperteam")); dbuffer msg; NET_WriteByte(&msg, svc_oob); NET_WriteRawString(&msg, "teaminfo\n"); NET_WriteString(&msg, infoGlobal); client_t* cl = nullptr; while ((cl = SV_GetNextClient(cl)) != nullptr) { if (cl->state < cs_connected) continue; char infoPlayer[MAX_INFO_STRING] = ""; /* show players that already have a team with their teamnum */ int teamId = svs.ge->ClientGetTeamNum(*cl->player); if (!teamId) teamId = TEAM_NO_ACTIVE; Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_team", teamId); Info_SetValueForKeyAsInteger(infoPlayer, sizeof(infoPlayer), "cl_ready", svs.ge->ClientIsReady(cl->player)); Info_SetValueForKey(infoPlayer, sizeof(infoPlayer), "cl_name", cl->name); NET_WriteString(&msg, infoPlayer); } NET_WriteByte(&msg, 0); NET_WriteMsg(s, msg); }