2014-10-29 08:02:03 +01:00
|
|
|
LICENSE: The Artistic License 2.0
|
|
|
|
|
|
|
|
/*
|
|
|
|
* qstat.h
|
|
|
|
* by Steve Jankowski
|
|
|
|
* steve@qstat.org
|
|
|
|
* http://www.qstat.org
|
|
|
|
*
|
|
|
|
* Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* TRIBES */
|
|
|
|
char tribes_info[] = { '`', '*', '*' };
|
|
|
|
char tribes_players[] = { 'b', '*', '*' };
|
|
|
|
/* This is what the game sends to get minimal status
|
|
|
|
{ '\020', '\03', '\377', 0, (unsigned char)0xc5, 6 };
|
|
|
|
*/
|
|
|
|
char tribes_info_reponse[] = { 'a', '*', '*', 'b' };
|
|
|
|
char tribes_players_reponse[] = { 'c', '*', '*', 'b' };
|
|
|
|
char tribes_masterquery[] = { 0x10, 0x3, '\377', 0, 0x2 };
|
|
|
|
char tribes_master_response[] = { 0x10, 0x6 };
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
/* TRIBES */
|
|
|
|
TRIBES_SERVER, /* id */
|
|
|
|
"TBS", /* type_prefix */
|
|
|
|
"tbs", /* type_string */
|
|
|
|
"-tbs", /* type_option */
|
|
|
|
"Tribes", /* game_name */
|
|
|
|
0, /* master */
|
|
|
|
TRIBES_DEFAULT_PORT, /* default_port */
|
|
|
|
0, /* port_offset */
|
|
|
|
TF_SINGLE_QUERY, /* flags */
|
|
|
|
"game", /* game_rule */
|
|
|
|
"TRIBES", /* template_var */
|
|
|
|
(char*) &tribes_info, /* status_packet */
|
|
|
|
sizeof( tribes_info), /* status_len */
|
|
|
|
(char*) &tribes_players, /* player_packet */
|
|
|
|
sizeof( tribes_players), /* player_len */
|
|
|
|
(char*) &tribes_players, /* rule_packet */
|
|
|
|
sizeof( tribes_players), /* rule_len */
|
|
|
|
NULL, /* master_packet */
|
|
|
|
0, /* master_len */
|
|
|
|
NULL, /* master_protocol */
|
|
|
|
NULL, /* master_query */
|
|
|
|
display_tribes_player_info, /* display_player_func */
|
|
|
|
display_server_rules, /* display_rule_func */
|
|
|
|
raw_display_tribes_player_info, /* display_raw_player_func */
|
|
|
|
raw_display_server_rules, /* display_raw_rule_func */
|
|
|
|
xml_display_tribes_player_info, /* display_xml_player_func */
|
|
|
|
xml_display_server_rules, /* display_xml_rule_func */
|
|
|
|
send_tribes_request_packet, /* status_query_func */
|
|
|
|
NULL, /* rule_query_func */
|
|
|
|
NULL, /* player_query_func */
|
|
|
|
deal_with_tribes_packet, /* packet_func */
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
query_status_t deal_with_tribes_packet(struct qserver *server, char *rawpkt, int pktlen)
|
|
|
|
{
|
|
|
|
unsigned char *pkt, *end;
|
|
|
|
int len, pnum, ping, packet_loss, n_teams, t;
|
|
|
|
struct player *player;
|
|
|
|
struct player **teams = NULL;
|
|
|
|
struct player **last_player = &server->players;
|
|
|
|
char buf[24];
|
|
|
|
|
|
|
|
debug( 2, "deal_with_tribes_packet %p, %d", server, pktlen );
|
|
|
|
|
|
|
|
if (server->server_name == NULL)
|
|
|
|
{
|
|
|
|
server->ping_total += time_delta(&packet_recv_time, &server->packet_time1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gettimeofday(&server->packet_time1, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pktlen < sizeof(tribes_info_reponse))
|
|
|
|
{
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strncmp(rawpkt, tribes_players_reponse, sizeof(tribes_players_reponse)) != 0)
|
|
|
|
{
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
pkt = (unsigned char*) &rawpkt[sizeof(tribes_info_reponse)];
|
|
|
|
|
|
|
|
len = *pkt; /* game name: "Tribes" */
|
|
|
|
add_nrule(server, "gamename", (char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
len = *pkt; /* version */
|
|
|
|
add_nrule(server, "version", (char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
len = *pkt; /* server name */
|
|
|
|
server->server_name = strndup((char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
add_rule(server, "dedicated", *pkt ? "1" : "0", NO_FLAGS);
|
|
|
|
pkt++; /* flag: dedicated server */
|
|
|
|
add_rule(server, "needpass", *pkt ? "1" : "0", NO_FLAGS);
|
|
|
|
pkt++; /* flag: password on server */
|
|
|
|
server->num_players = *pkt++;
|
|
|
|
server->max_players = *pkt++;
|
|
|
|
|
|
|
|
sprintf(buf, "%u", (unsigned int)pkt[0] + (unsigned int)pkt[1] *256);
|
|
|
|
add_rule(server, "cpu", buf, NO_FLAGS);
|
|
|
|
pkt++; /* cpu speed, lsb */
|
|
|
|
pkt++; /* cpu speed, msb */
|
|
|
|
|
|
|
|
len = *pkt; /* Mod (game) */
|
|
|
|
add_nrule(server, "mods", (char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
len = *pkt; /* game (mission): "C&H" */
|
|
|
|
add_nrule(server, "game", (char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
len = *pkt; /* Mission (map) */
|
|
|
|
server->map_name = strndup((char*)pkt + 1, len);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
len = *pkt; /* description (contains Admin: and Email: ) */
|
|
|
|
debug( 2, "%.*s\n", len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
n_teams = *pkt++; /* number of teams */
|
|
|
|
if (n_teams == 255)
|
|
|
|
{
|
|
|
|
return PKT_ERROR;
|
|
|
|
}
|
|
|
|
sprintf(buf, "%d", n_teams);
|
|
|
|
add_rule(server, "numteams", buf, NO_FLAGS);
|
|
|
|
|
|
|
|
len = *pkt; /* first title */
|
|
|
|
debug( 2, "%.*s\n", len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
len = *pkt; /* second title */
|
|
|
|
debug( 2, "%.*s\n", len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
if (n_teams > 1)
|
|
|
|
{
|
|
|
|
teams = (struct player **)calloc(1, sizeof(struct player*) * n_teams);
|
|
|
|
for (t = 0; t < n_teams; t++)
|
|
|
|
{
|
|
|
|
teams[t] = (struct player*)calloc(1, sizeof(struct player));
|
|
|
|
teams[t]->number = TRIBES_TEAM;
|
|
|
|
teams[t]->team = t;
|
|
|
|
len = *pkt; /* team name */
|
|
|
|
teams[t]->name = strndup((char*)pkt + 1, len);
|
|
|
|
debug( 2, "team#0 <%.*s>\n", len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
|
|
|
|
len = *pkt; /* team score */
|
|
|
|
if (len > 2)
|
|
|
|
{
|
|
|
|
strncpy(buf, (char*)pkt + 1+3, len - 3);
|
|
|
|
buf[len - 3] = '\0';
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
debug( 2, "%s score len %d\n", server->arg, len);
|
|
|
|
buf[0] = '\0';
|
|
|
|
}
|
|
|
|
teams[t]->frags = atoi(buf);
|
|
|
|
debug( 2, "team#0 <%.*s>\n", len - 3, pkt + 1+3);
|
|
|
|
pkt += len + 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
len = *pkt; /* DM team? */
|
|
|
|
debug( 2, "%.*s\n", len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
pkt++;
|
|
|
|
n_teams = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
pnum = 0;
|
|
|
|
while ((char*)pkt < (rawpkt + pktlen))
|
|
|
|
{
|
|
|
|
ping = (unsigned int) *pkt << 2;
|
|
|
|
pkt++;
|
|
|
|
packet_loss = *pkt;
|
|
|
|
pkt++;
|
|
|
|
debug( 2, "player#%d, team #%d\n", pnum, (int) *pkt);
|
|
|
|
pkt++;
|
|
|
|
len = *pkt;
|
|
|
|
if ((char*)pkt + len > (rawpkt + pktlen))
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
player = (struct player*)calloc(1, sizeof(struct player));
|
|
|
|
player->team = pkt[ - 1];
|
|
|
|
if (n_teams && player->team < n_teams)
|
|
|
|
{
|
|
|
|
player->team_name = teams[player->team]->name;
|
|
|
|
}
|
|
|
|
else if (player->team == 255 && n_teams)
|
|
|
|
{
|
|
|
|
player->team_name = "Unknown";
|
|
|
|
}
|
|
|
|
player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM;
|
|
|
|
player->ping = ping;
|
|
|
|
player->packet_loss = packet_loss;
|
|
|
|
player->name = strndup((char*)pkt + 1, len);
|
|
|
|
debug( 2, "player#%d, name %.*s\n", pnum, len, pkt + 1);
|
|
|
|
pkt += len + 1;
|
|
|
|
len = *pkt;
|
|
|
|
debug( 2, "player#%d, info <%.*s>\n", pnum, len, pkt + 1);
|
|
|
|
end = (unsigned char*)strchr((char*)pkt + 9, 0x9);
|
|
|
|
if (end)
|
|
|
|
{
|
|
|
|
strncpy(buf, (char*)pkt + 9, end - (pkt + 9));
|
|
|
|
buf[end - (pkt + 9)] = '\0';
|
|
|
|
player->frags = atoi(buf);
|
|
|
|
debug( 2, "player#%d, score <%.*s>\n", pnum, (unsigned)(end - (pkt + 9)), pkt + 9);
|
|
|
|
}
|
|
|
|
|
|
|
|
*last_player = player;
|
|
|
|
last_player = &player->next;
|
|
|
|
|
|
|
|
pkt += len + 1;
|
|
|
|
pnum++;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (t = n_teams; t;)
|
|
|
|
{
|
|
|
|
t--;
|
|
|
|
teams[t]->next = server->players;
|
|
|
|
server->players = teams[t];
|
|
|
|
}
|
|
|
|
free(teams);
|
|
|
|
|
|
|
|
return DONE_AUTO;
|
|
|
|
}
|