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 */ unsigned char savage_serverquery[] = { 0x9e,0x4c,0x23,0x00,0x00,0xc8,0x01,0x21,0x00,0x00 }; unsigned char savage_playerquery[] = { 0x9e,0x4c,0x23,0x00,0x00,0xce,0x76,0x46,0x00,0x00 }; { /* SAVAGE PROTOCOL */ SAVAGE_SERVER, /* id */ "SAS", /* type_prefix */ "sas", /* type_string */ "-sas", /* type_option */ "Savage", /* game_name */ 0, /* master */ SAVAGE_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUERY_ARG, /* flags */ "gametype", /* game_rule */ "SAVAGE", /* template_var */ (char*)savage_serverquery, /* status_packet */ sizeof( savage_serverquery ) - 1, /* status_len */ (char*)savage_playerquery, /* player_packet */ sizeof( savage_playerquery ) - 1, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_savage_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_savage_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_savage_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_savage_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_savage_packet, /* packet_func */ }, query_status_t send_savage_request_packet(struct qserver *server) { int len; char *pkt; if (get_player_info) { pkt = server->type->player_packet; len = server->type->player_len; } else { pkt = server->type->status_packet; len = server->type->status_len; } return send_packet(server, pkt, len); } query_status_t deal_with_savage_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *key, *value, *end; debug( 2, "deal_with_savage_packet %p, %d", server, pktlen ); server->n_servers++; if (NULL == server->server_name) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } else { gettimeofday(&server->packet_time1, NULL); } rawpkt[pktlen] = '\0'; end = s = rawpkt; end += pktlen; while (*s) { // Find the seperator while (s <= end && *s != '\xFF') { s++; } if (s >= end) { // Hit the end no more break; } // key start key = ++s; while (s < end && *s != '\xFE') { s++; } if (*s != '\xFE') { // malformed break; } *s++ = '\0'; // key end // value start value = s; while (s < end && *s != '\xFF') { s++; } if (*s == '\xFF') { *s = '\0'; } //fprintf( stderr, "'%s' = '%s'\n", key, value ); // Decode current key par if (0 == strcmp("cmax", key)) { // Max players server->max_players = atoi(value); } else if (0 == strcmp("cnum", key)) { // Current players server->num_players = atoi(value); } else if (0 == strcmp("bal", key)) { // Balance add_rule(server, "Balance", value, NO_FLAGS); } else if (0 == strcmp("world", key)) { // Current map server->map_name = strdup(value); } else if (0 == strcmp("gametype", key)) { // Game type server->game = find_savage_game(value); add_rule(server, server->type->game_rule, server->game, NO_FLAGS); } else if (0 == strcmp("pure", key)) { // Pure add_rule(server, "Pure", value, NO_FLAGS); } else if (0 == strcmp("time", key)) { // Current game time add_rule(server, "Time", value, NO_FLAGS); } else if (0 == strcmp("notes", key)) { // Notes add_rule(server, "Notes", value, NO_FLAGS); } else if (0 == strcmp("needcmdr", key)) { // Need Commander add_rule(server, "Need Commander", value, NO_FLAGS); } else if (0 == strcmp("name", key)) { // Server name server->server_name = strdup(value); } else if (0 == strcmp("fw", key)) { // Firewalled add_rule(server, "Firewalled", value, NO_FLAGS); } else if (0 == strcmp("players", key)) { // Players names int player_number = 0; int team_number = 1; char *team_name, *player_name, *n; n = team_name = value; // team name n++; while (*n && *n != '\x0a') { n++; } if (*n != '\x0a') { // Broken data break; } *n = '\0'; player_name = ++n; while (*n) { while (*n && *n != '\x0a') { n++; } if (*n != '\x0a') { // Broken data break; } *n = '\0'; n++; if (0 == strncmp("Team ", player_name, 5)) { team_name = player_name; team_number++; } else { if (0 != strlen(player_name)) { struct player *player = add_player(server, player_number); if (NULL != player) { player->name = strdup(player_name); player->team = team_number; player->team_name = strdup(team_name); } player_number++; } } player_name = n; } } *s = '\xFF'; } return DONE_FORCE; } char *find_savage_game(char *gametype) { if (0 == strcmp("RTSS", gametype)) { return strdup("RTSS"); } else { return strdup("Unknown"); } }