query_status_t send_ts2_request_packet( struct qserver *server ) { char buf[256]; int serverport = get_param_i_value( server, "port", 0 ); change_server_port( server, serverport, 1 ); if ( get_player_info ) { server->flags |= TF_PLAYER_QUERY|TF_RULES_QUERY; sprintf( buf, "si %d\npl %d\nquit\n", serverport, serverport ); server->saved_data.pkt_index = 2; } else { server->flags |= TF_STATUS_QUERY; sprintf( buf, "si %d\nquit\n", serverport ); server->saved_data.pkt_index = 1; } return send_packet( server, buf, strlen( buf ) ); }
query_status_t deal_with_ts2_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *end; int ping, connect_time, mode = 0; char name[256]; debug( 2, "processing..." ); server->n_servers++; server->n_requests++; server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); if ( 0 == pktlen ) { // Invalid password return REQ_ERROR; } rawpkt[pktlen]= '\0'; end = &rawpkt[pktlen]; s = rawpkt; s = strtok( rawpkt, "\015\012" ); while ( NULL != s ) { if ( 0 == mode ) { // Rules char *key = s; char *value = strchr( key, '=' ); if ( NULL != value ) { // Server Rule *value = '\0'; value++; if ( 0 == strcmp( "server_name", key ) ) { server->server_name = strdup( value ); } else if ( 0 == strcmp( "server_udpport", key ) ) { change_server_port( server, atoi( value ), 0 ); add_rule( server, key, value, NO_FLAGS ); } else if ( 0 == strcmp( "server_maxusers", key ) ) { server->max_players = atoi( value ); } else if ( 0 == strcmp( "server_currentusers", key ) ) { server->num_players = atoi( value); } else { add_rule( server, key, value, NO_FLAGS); } } else if ( 0 == strcmp( "OK", s ) ) { // end of rules request server->saved_data.pkt_index--; mode++; } else if ( 0 == strcmp( "[TS]", s ) ) { // nothing to do } else if ( 0 == strcmp( "ERROR, invalid id", s ) ) { // bad server server->server_name = DOWN; server->saved_data.pkt_index = 0; } } else if ( 1 == mode ) { // Player info if ( 3 == sscanf( s, "%*d %*d %*d %*d %*d %*d %*d %d %d %*d %*d %*d %*d \"0.0.0.0\" \"%255[^\"]", &ping, &connect_time, name ) ) { // Player info struct player *player = add_player( server, server->n_player_info ); if ( NULL != player ) { player->name = strdup( name ); player->ping = ping; player->connect_time = connect_time; } } else if ( 0 == strcmp( "OK", s ) ) { // end of rules request server->saved_data.pkt_index--; mode++; } else if ( 0 == strcmp( "[TS]", s ) ) { // nothing to do } else if ( 0 == strcmp( "ERROR, invalid id", s ) ) { // bad server server->server_name = DOWN; server->saved_data.pkt_index = 0; } } s = strtok( NULL, "\015\012" ); } gettimeofday( &server->packet_time1, NULL ); if ( 0 == server->saved_data.pkt_index ) { server->map_name = strdup( "N/A" ); return DONE_FORCE; } return INPROGRESS; }
query_status_t send_ts3_single_server_packet(struct qserver *server) { char buf[256], *password, *username; int serverport; switch (server->challenge) { case 0: // Not seen a challenge yet, wait for it server->n_servers = 999; return (INPROGRESS); case 1: // Login if needed password = get_param_value(server, "password", ""); if (0 != strlen(password)) { username = get_param_value(server, "username", "serveradmin"); sprintf(buf, "login %s %s\015\012", username, password); break; } // NOTE: no break so we fall through server->challenge++; case 2: // Select port serverport = get_param_i_value(server, "port", 0); change_server_port(server, serverport, 1); // NOTE: we use n_servers as an indication of how many responses we are expecting to get if (get_player_info) { server->flags |= TF_PLAYER_QUERY | TF_RULES_QUERY; server->n_servers = 5; } else { server->flags |= TF_STATUS_QUERY; server->n_servers = 4; } sprintf(buf, "use port=%d\015\012", serverport); break; case 3: // Server Info sprintf(buf, "serverinfo\015\012"); break; case 4: // Player Info, Quit or Done sprintf(buf, (get_player_info) ? "clientlist\015\012" : "quit\015\012"); break; case 5: // Quit or Done if (get_player_info) { sprintf(buf, "quit\015\012"); } else { return (DONE_FORCE); } break; } server->saved_data.pkt_max = -1; return (send_packet(server, buf, strlen(buf))); }
query_status_t deal_with_ts3_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *player_name = "unknown"; int valid_response = 0, mode = 0, all_servers = 0; char last_char; unsigned short port = 0, down = 0, auth_seen = 0; debug(2, "processing..."); if (0 == pktlen) { // Invalid password return (REQ_ERROR); } last_char = rawpkt[pktlen - 1]; rawpkt[pktlen - 1] = '\0'; s = rawpkt; all_servers = all_ts3_servers(server); debug(3, "packet: combined = %d, challenge = %ld, n_servers = %d", server->combined, server->challenge, server->n_servers); if (!server->combined) { server->retry1 = n_retries; if (0 == server->n_requests) { server->ping_total = time_delta(&packet_recv_time, &server->packet_time1); server->n_requests++; } if (server->n_servers >= server->challenge) { // response fragment recieved int pkt_id; int pkt_max; // We're expecting more to come debug(5, "fragment recieved..."); pkt_id = packet_count(server); pkt_max = pkt_id + 1; rawpkt[pktlen - 1] = last_char; // restore the last character if (!add_packet(server, 0, pkt_id, pkt_max, pktlen, rawpkt, 1)) { // fatal error e.g. out of memory return (MEM_ERROR); } // combine_packets will call us recursively return (combine_packets(server)); } } else { valid_response = valid_ts3_response(server, rawpkt + server->master_pkt_len, pktlen - server->master_pkt_len); debug(2, "combined packet: valid_response: %d, challenge: %ld, n_servers: %d, offset: %d", valid_response, server->challenge, server->n_servers, server->master_pkt_len); if (0 > valid_response) { // Error occured return (valid_response); } server->challenge += valid_response; if (valid_response) { // Got a valid response, send the next request int ret = send_ts3_request_packet(server); if (0 != ret) { // error sending packet debug(4, "Request failed: %d", ret); return (ret); } } if (server->n_servers > server->challenge) { // recursive call which is still incomplete return (INPROGRESS); } } // Correct ping // Not quite right but gives a good estimate server->ping_total = (server->ping_total * server->n_requests) / 2; debug(3, "processing response..."); s = strtok(rawpkt, "\012\015 |"); // NOTE: id=XXX and msg=XXX will be processed by the mod following the one they where the response of while (NULL != s) { debug(4, "LINE: %d, %s\n", mode, s); switch (mode) { case 0: // prompt, use or serverlist response if (0 == strcmp("TS3", s)) { // nothing to do unless in all servers mode if (1 == all_servers) { mode++; } } else if (0 == strncmp("error", s, 5)) { // end of use response mode++; } break; case 1: // serverinfo or serverlist response including condition authentication if ((0 == auth_seen) && (0 != strlen(get_param_value(server, "password", ""))) && (0 == strncmp("error", s, 5))) { // end of auth response auth_seen = 1; } else if (0 == strncmp("error", s, 5)) { // end of serverinfo response mode++; } else { // Server Rule char *key = s; char *value = strchr(key, '='); if (NULL != value) { *value = '\0'; value++; debug(6, "Rule: %s = %s\n", key, value); if (0 == strcmp("virtualserver_name", key)) { if (1 == all_servers) { struct qserver *new_server = add_qserver_byaddr(ntohl(server->ipaddr), port, server->type, NULL); if (NULL != new_server) { if (down) { // Status indicates this server is actually offline new_server->server_name = DOWN; } else { new_server->max_players = server->max_players; new_server->num_players = server->num_players; new_server->server_name = strdup(decode_ts3_val(value)); new_server->map_name = strdup("N/A"); new_server->ping_total = server->ping_total; new_server->n_requests = server->n_requests; } cleanup_qserver(new_server, FORCE); } down = 0; } else { server->server_name = strdup(decode_ts3_val(value)); } } else if (0 == strcmp("virtualserver_port", key)) { port = atoi(value); change_server_port(server, port, 0); add_rule(server, key, value, NO_FLAGS); } else if (0 == strcmp("virtualserver_maxclients", key)) { server->max_players = atoi(value); } else if (0 == strcmp("virtualserver_clientsonline", key)) { server->num_players = atoi(value); } else if (0 == strcmp("virtualserver_queryclientsonline", key)) { // clientsonline includes queryclientsonline so remove these from our count server->num_players -= atoi(value); } else if ((0 == strcmp("virtualserver_status", key)) && (0 != strcmp("online", value))) { // Server is actually offline to client so display as down down = 1; if (1 != all_servers) { server->server_name = DOWN; //server->saved_data.pkt_index = 0; return (DONE_FORCE); } } else if ((0 == strcmp("id", key)) || (0 == strcmp("msg", key))) { // Ignore details from the response code } else if (1 != all_servers) { add_rule(server, key, value, NO_FLAGS); } } } break; case 2: // clientlist response if (0 == strncmp("error", s, 5)) { // end of serverinfo response mode++; } else { // Client char *key = s; char *value = strchr(key, '='); if (NULL != value) { *value = '\0'; value++; debug(6, "Player: %s = %s\n", key, value); if (0 == strcmp("client_nickname", key)) { player_name = value; } else if (0 == strcmp("clid", key)) { } else if ((0 == strcmp("client_type", key)) && (0 == strcmp("0", value))) { struct player *player = add_player(server, server->n_player_info); if (NULL != player) { player->name = strdup(decode_ts3_val(player_name)); } } else if ((0 == strcmp("id", key)) || (0 == strcmp("msg", key))) { // Ignore details from the response code } } } break; } s = strtok(NULL, "\012\015 |"); } gettimeofday(&server->packet_time1, NULL); server->map_name = strdup("N/A"); return (DONE_FORCE); }
// See the following for protocol details: // http://dev.kquery.com/index.php?article=42 query_status_t deal_with_gs2_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *ptr = rawpkt; char *end = rawpkt + pktlen; unsigned char type = 0; unsigned char no_players = 0; unsigned char total_players = 0; unsigned char no_teams = 0; unsigned char total_teams = 0; unsigned char no_headers = 0; char **headers = NULL; debug( 2, "processing packet..." ); if ( pktlen < 15 ) { // invalid packet? return PKT_ERROR; } server->n_servers++; if ( server->server_name == NULL) { server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); } else { gettimeofday( &server->packet_time1, NULL); } // Could check the header here should // match the 4 byte id sent ptr += 5; while ( 0 == type && ptr < end ) { // server info: // name value pairs null seperated // empty name && value signifies the end of section char *var, *val; int var_len, val_len; var = ptr; var_len = strlen( var ); if ( ptr + var_len + 2 > end ) { if ( 0 != var_len ) { malformed_packet( server, "no rule value" ); } else if ( get_player_info ) { malformed_packet( server, "no player headers" ); } return PKT_ERROR; } ptr += var_len + 1; val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "var:%s (%d)=%s (%d)\n", var, var_len, val, val_len ); // Lets see what we've got if ( 0 == strcmp( var, "hostname" ) ) { server->server_name = strdup( val ); } else if( 0 == strcmp( var, "game_id" ) ) { server->game = strdup( val ); } else if( 0 == strcmp( var, "gamever" ) ) { // format: // v1.0 server->protocol_version = atoi( val+1 ); add_rule( server, var, val, NO_FLAGS ); } else if( 0 == strcmp( var, "mapname" ) ) { server->map_name = strdup( val ); } else if( 0 == strcmp( var, "map" ) ) { // For BF2MC compatibility server->map_name = strdup( val ); } else if( 0 == strcmp( var, "maxplayers" ) ) { server->max_players = atoi( val ); } else if( 0 == strcmp( var, "numplayers" ) ) { server->num_players = no_players = atoi( val ); } else if( 0 == strcmp( var, "hostport" ) ) { change_server_port( server, atoi( val ), 0 ); } else if ( 0 == var_len ) { // check for end of section type = 1; } else { add_rule( server, var, val, NO_FLAGS ); } } if ( 1 != type ) { // no more info should be player headers here as we // requested it malformed_packet( server, "no player headers" ); return PKT_ERROR; } // player info header // format: // first byte = player count // followed by null seperated header no_players = (unsigned char)*ptr; debug( 2, "No Players:%d\n", no_players ); ptr++; if ( ptr >= end ) { malformed_packet( server, "no player headers" ); return PKT_ERROR; } while ( 1 == type && ptr < end ) { // first we have the headers null seperated char **tmpp; char *head = ptr; int head_len = strlen( head ); no_headers++; tmpp = (char**)realloc( headers, no_headers * sizeof( char* ) ); if ( NULL == tmpp ) { debug( 0, "Failed to realloc memory for headers\n" ); if ( NULL != headers ) { free( headers ); } return MEM_ERROR; } headers = tmpp; headers[no_headers-1] = head; ptr += head_len + 1; // end of headers check if ( 0x00 == *ptr ) { type = 2; ptr++; } debug( 2, "player header[%d] = '%s'", no_headers-1, head ); } if ( 2 != type ) { // no more info should be player info here as we // requested it malformed_packet( server, "no players" ); return PKT_ERROR; } while( 2 == type && ptr < end ) { // now each player details // add the player if ( 0x00 == *ptr ) { // no players if ( 0 != no_players ) { malformed_packet( server, "no players" ); return PKT_ERROR; } } else { struct player *player = add_player( server, total_players ); int i; for ( i = 0; i < no_headers; i++ ) { char *header = headers[i]; char *val; int val_len; if ( ptr >= end ) { malformed_packet( server, "short player detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; // lets see what we got if ( 0 == strcmp( header, "player_" ) ) { player->name = strdup( val ); } else if ( 0 == strcmp( header, "score_" ) ) { player->score = atoi( val ); } else if ( 0 == strcmp( header, "deaths_" ) ) { player->deaths = atoi( val ); } else if ( 0 == strcmp( header, "ping_" ) ) { player->ping = atoi( val ); } else if ( 0 == strcmp( header, "kills_" ) ) { player->frags = atoi( val ); } else if ( 0 == strcmp( header, "team_" ) ) { player->team = atoi( val ); } else { int len = strlen( header ); if ( '_' == header[len-1] ) { header[len-1] = '\0'; } player_add_info( player, header, val, NO_FLAGS ); } debug( 2, "Player[%d][%s]=%s\n", total_players, headers[i], val ); } total_players++; } if ( total_players > no_players ) { malformed_packet( server, "to many players %d > %d", total_players, no_players ); return PKT_ERROR; } // check for end of player info if ( 0x00 == *ptr ) { if ( total_players != no_players ) { malformed_packet( server, "bad number of players %d != %d", total_players, no_players ); return PKT_ERROR; } type = 3; ptr++; } } if ( 3 != type ) { // no more info should be team info here as we // requested it malformed_packet( server, "no teams" ); return PKT_ERROR; } no_teams = (unsigned char)*ptr; ptr++; debug( 2, "No teams:%d\n", no_teams ); no_headers = 0; while ( 3 == type && ptr < end ) { // first we have the headers null seperated char **tmpp; char *head = ptr; int head_len = strlen( head ); no_headers++; tmpp = (char**)realloc( headers, no_headers * sizeof( char* ) ); if ( NULL == tmpp ) { debug( 0, "Failed to realloc memory for headers\n" ); if ( NULL != headers ) { free( headers ); } return MEM_ERROR; } headers = tmpp; headers[no_headers-1] = head; ptr += head_len + 1; // end of headers check if ( 0x00 == *ptr ) { type = 4; ptr++; } } if ( 4 != type ) { // no more info should be team info here as we // requested it malformed_packet( server, "no teams" ); return PKT_ERROR; } while( 4 == type && ptr < end ) { // now each teams details int i; for ( i = 0; i < no_headers; i++ ) { char *val; int val_len; if ( ptr >= end ) { malformed_packet( server, "short team detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; // lets see what we got if ( 0 == strcmp( headers[i], "team_t" ) ) { // BF being stupid again teams 1 based instead of 0 players_set_teamname( server, total_teams + 1, val ); } debug( 2, "Team[%d][%s]=%s\n", total_teams, headers[i], val ); } total_teams++; if ( total_teams > no_teams ) { malformed_packet( server, "to many teams" ); return PKT_ERROR; } } return DONE_FORCE; }
query_status_t deal_with_fl_packet(struct qserver *server, char *rawpkt, int pktlen) { struct fl_status* status = (struct fl_status*)server->master_query_tag; char* pkt = rawpkt; char buf[16]; char* str; unsigned cnt; unsigned short tmp_short; if(server->server_name == NULL) { server->ping_total += time_delta( &packet_recv_time, &server->packet_time1); server->n_requests++; } if(pktlen < 5) goto out_too_short; if( 0 == memcmp(pkt, "\xFF\xFF\xFF\xFE", 4) ) { // fragmented packet unsigned char pkt_index, pkt_max; unsigned int pkt_id; SavedData *sdata; if(pktlen < 9) goto out_too_short; // format: // int Header // int RequestId // byte PacketNumber // byte NumPackets // Short SizeOfPacketSplits // Header pkt += 4; // RequestId pkt_id = ntohl( *(long *)pkt ); debug( 3, "RequestID: %d", pkt_id ); pkt += 4; // The next two bytes are: // 1. the max packets sent ( byte ) // 2. the index of this packet starting from 0 ( byte ) // 3. Size of the split ( short ) if(pktlen < 10) goto out_too_short; // PacketNumber pkt_index = ((unsigned char)*pkt); // NumPackates pkt_max = ((unsigned char)*(pkt+1)); // SizeOfPacketSplits debug( 3, "packetid[2]: 0x%hhx => idx: %hhu, max: %hhu", *pkt, pkt_index, pkt_max ); pkt+=4; pktlen -= 12; // pkt_max is the total number of packets expected // pkt_index is a bit mask of the packets received. if ( server->saved_data.data == NULL ) { sdata = &server->saved_data; } else { sdata = (SavedData*) calloc( 1, sizeof(SavedData)); sdata->next = server->saved_data.next; server->saved_data.next = sdata; } sdata->pkt_index = pkt_index; sdata->pkt_max = pkt_max; sdata->pkt_id = pkt_id; sdata->datalen = pktlen; sdata->data= (char*)malloc( pktlen ); if ( NULL == sdata->data ) { malformed_packet(server, "Out of memory"); return MEM_ERROR; } memcpy( sdata->data, pkt, sdata->datalen ); // combine_packets will call us recursively return combine_packets( server ); } else if ( 0 != memcmp(pkt, "\xFF\xFF\xFF\xFF", 4) ) { malformed_packet(server, "invalid packet header"); return PKT_ERROR; } pkt += 4; pktlen -= 4; pktlen -= 1; debug( 2, "FL type = 0x%x", *pkt ); switch(*pkt++) { case FL_CHALLENGERESPONSE: if(pktlen < 4) goto out_too_short; memcpy(&status->challenge, pkt, 4); // do not count challenge as retry if(!status->have_challenge && server->retry1 != n_retries) { ++server->retry1; if(server->n_retries) { --server->n_retries; } } status->have_challenge = 1; debug(3, "challenge %x", status->challenge); break; case FL_INFORESPONSE: if(pktlen < 1) goto out_too_short; status->type = *pkt; if ( *pkt > 1 && ( get_server_rules || get_player_info ) ) { server->next_rule = ""; // trigger calling send_fl_rule_request_packet } snprintf(buf, sizeof(buf), "%hhX", *pkt); add_rule(server, "protocol", buf, 0); pktlen--; pkt++; // ServerName str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->server_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // MapName str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->map_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // ModName str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->game = strdup(pkt); add_rule(server, "modname", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // GameMode str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "gamemode", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // GameDescription str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "gamedescription", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // GameVersion str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "gameversion", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; if( pktlen < 13 ) { goto out_too_short; } // GamePort tmp_short = ((unsigned short)pkt[0] <<8 ) | ((unsigned short)pkt[1]); change_server_port( server, tmp_short, 0 ); pkt += 2; // Num Players server->num_players = (unsigned char)*pkt++; // Max Players server->max_players = (unsigned char)*pkt++; // Dedicated add_rule(server, "dedicated", ( 'd' == *pkt++) ? "1" : "0", 0); // OS switch( *pkt ) { case 'l': add_rule(server, "sv_os", "linux", 0); break; case 'w': add_rule(server, "sv_os", "windows", 0); break; default: buf[0] = *pkt; buf[1] = '\0'; add_rule(server, "sv_os", buf, 0); break; } pkt++; // Passworded add_rule(server, "passworded", ( *pkt++ ) ? "1" : "0" , 0); // Anticheat add_rule(server, "passworded", ( *pkt++ ) ? "1" : "0" , 0); // FrameTime sprintf( buf, "%hhu", *pkt++ ); add_rule(server, "frametime", buf , 0); // Round sprintf( buf, "%hhu", *pkt++ ); add_rule(server, "round", buf , 0); // RoundMax sprintf( buf, "%hhu", *pkt++ ); add_rule(server, "roundmax", buf , 0); // RoundSeconds tmp_short = ((unsigned short)pkt[0] <<8 ) | ((unsigned short)pkt[1]); sprintf( buf, "%hu", tmp_short ); add_rule(server, "roundseconds", buf , 0); pkt += 2; status->have_info = 1; server->retry1 = n_retries; server->next_player_info = server->num_players; break; case FL_RULESRESPONSE: if(pktlen < 2) goto out_too_short; cnt = ((unsigned char)pkt[0] << 8 ) + ((unsigned char)pkt[1]); pktlen -= 2; pkt += 2; debug(3, "num_rules: %d", cnt); for(;cnt && pktlen > 0; --cnt) { char* key, *value; str = memchr(pkt, '\0', pktlen); if(!str) break; key = pkt; pktlen -= str-pkt+1; pkt += str-pkt+1; str = memchr(pkt, '\0', pktlen); if(!str) break; value = pkt; pktlen -= str-pkt+1; pkt += str-pkt+1; add_rule(server, key, value, NO_FLAGS); } if(cnt) { malformed_packet(server, "packet contains too few rules, missing %d", cnt); server->missing_rules = 1; } if(pktlen) malformed_packet(server, "garbage at end of rules, %d bytes left", pktlen); status->have_rules = 1; server->retry1 = n_retries; break; case FL_PLAYERRESPONSE: if(pktlen < 1) goto out_too_short; cnt = (unsigned char)pkt[0]; pktlen -= 1; pkt += 1; debug(3, "num_players: %d", cnt); for(;cnt && pktlen > 0; --cnt) { unsigned idx; const char* name; struct player* p; // Index idx = *pkt++; --pktlen; // PlayerName str = memchr(pkt, '\0', pktlen); if(!str) break; name = pkt; pktlen -= str-pkt+1; pkt += str-pkt+1; if(pktlen < 8) goto out_too_short; debug(3, "player index %d", idx); p = add_player(server, server->n_player_info); if(p) { union { int i; float fl; } temp; p->name = strdup(name); // Score p->frags = ntohl( *(unsigned int *)pkt ); // TimeConnected temp.i = ntohl( *(unsigned int *)(pkt+4) ); p->connect_time = temp.fl; // Ping p->ping = 0; p->ping = ntohs( *(unsigned int *)(pkt+8) ); //((unsigned char*)&p->ping)[0] = pkt[9]; //((unsigned char*)&p->ping)[1] = pkt[8]; // ProfileId //p->profileid = ntohl( *(unsigned int *)pkt+10 ); // Team p->team = *(pkt+14); //fprintf( stderr, "Player: '%s', Frags: %u, Time: %u, Ping: %hu, Team: %d\n", p->name, p->frags, p->connect_time, p->ping, p->team ); } pktlen -= 15; pkt += 15; } #if 0 // seems to be a rather normal condition if(cnt) { malformed_packet(server, "packet contains too few players, missing %d", cnt); } #endif if(pktlen) malformed_packet(server, "garbage at end of player info, %d bytes left", pktlen); status->have_player = 1; server->retry1 = n_retries; break; default: malformed_packet(server, "invalid packet id %hhx", *--pkt); return PKT_ERROR; } if( (!get_player_info || (get_player_info && status->have_player)) && (!get_server_rules || (get_server_rules && status->have_rules)) ) { server->next_rule = NULL; } return DONE_AUTO; out_too_short: malformed_packet(server, "packet too short"); return PKT_ERROR; }