qstat-2.15/0000755000175000017500000000000012420766316007605 500000000000000qstat-2.15/ottd.c0000644000175000017500000001755512420765615010661 00000000000000/* * qstat * * opentTTD protocol * Copyright 2007 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #ifndef _WIN32 #include #endif #include #include #include "qstat.h" #include "qserver.h" #include "debug.h" enum { MAX_VEHICLE_TYPES = 5, MAX_STATION_TYPES = 5 }; static const char* vehicle_types[] = { "num_trains", "num_trucks", "num_busses", "num_aircrafts", "num_ships", }; static const char* station_types[] = { "num_stations", "num_truckbays", "num_busstations", "num_airports", "num_docks", }; query_status_t deal_with_ottdmaster_packet(struct qserver *server, char *rawpkt, int pktlen) { unsigned num; server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); server->server_name = MASTER; if(swap_short_from_little(rawpkt) != pktlen) { malformed_packet( server, "invalid packet length" ); return PKT_ERROR; } if(rawpkt[2] != 7) { malformed_packet( server, "invalid packet type" ); return PKT_ERROR; } if(rawpkt[3] != 1) { malformed_packet( server, "invalid packet version" ); return PKT_ERROR; } num = swap_short_from_little(&rawpkt[4]); rawpkt += 6; pktlen -= 6; if( num && num*6 <= pktlen ) { unsigned i; server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len + pktlen ); memset(server->master_pkt + server->master_pkt_len, 0, pktlen ); server->master_pkt_len += pktlen; for( i = 0; i < num * 6; i += 6 ) { memcpy(&server->master_pkt[i], &rawpkt[i], 4); server->master_pkt[i+4] = rawpkt[i+5]; server->master_pkt[i+5] = rawpkt[i+4]; } server->n_servers += num; } else { malformed_packet( server, "invalid packet" ); return PKT_ERROR; } bind_sockets(); return DONE_AUTO; } #define xstr(s) str(s) #define str(s) #s #define GET_STRING do { \ str = (char*)ptr; \ ptr = memchr(ptr, '\0', end-ptr); \ if ( !ptr ) \ { \ malformed_packet( server, "%s:%s invalid packet", __FILE__, xstr(__LINE__) ); \ return PKT_ERROR; \ } \ ++ptr; \ } while(0) #define FAIL_IF(cond, msg) \ if((cond)) { \ malformed_packet( server, "%s:%s %s", __FILE__, xstr(__LINE__), msg ); \ return PKT_ERROR; \ } #define INVALID_IF(cond) \ FAIL_IF(cond, "invalid packet") query_status_t deal_with_ottd_packet(struct qserver *server, char *rawpkt, int pktlen) { unsigned char *ptr = (unsigned char*)rawpkt; unsigned char *end = (unsigned char*)(rawpkt + pktlen); unsigned char type; char* str; char buf[32]; unsigned ver; server->n_servers++; if ( server->server_name == NULL) { server->ping_total += time_delta( &packet_recv_time, &server->packet_time1); server->n_requests++; } else { gettimeofday( &server->packet_time1, NULL); } FAIL_IF(pktlen < 4 || swap_short_from_little(rawpkt) > pktlen, "invalid packet"); type = ptr[2]; ver = ptr[3]; ptr += 4; debug(3, "len %hu type %hhu ver %u", swap_short_from_little(rawpkt), type, ver); FAIL_IF(ver != 4 && ver != 5, "only version 4 and 5 servers are supported"); if(type == 1) // info packet { unsigned numgrf = *ptr; FAIL_IF(ptr + numgrf * 20 + 1 > end, "invalid newgrf number"); ptr += numgrf * 20 + 1; snprintf(buf, sizeof(buf), "%u", swap_long_from_little(ptr)); add_rule(server, "date_days", buf, NO_FLAGS); ptr += 4; snprintf(buf, sizeof(buf), "%u", swap_long_from_little(ptr)); add_rule(server, "startdate_days", buf, NO_FLAGS); ptr += 4; FAIL_IF(ptr + 3 > end, "invalid packet"); snprintf(buf, sizeof(buf), "%hhu", ptr[0]); add_rule(server, "maxcompanies", buf, NO_FLAGS); snprintf(buf, sizeof(buf), "%hhu", ptr[1]); add_rule(server, "numcompanies", buf, NO_FLAGS); server->max_spectators = ptr[2]; ptr += 3; GET_STRING; server->server_name = strdup(str); GET_STRING; add_rule(server, "version", str, NO_FLAGS); FAIL_IF(ptr + 7 > end, "invalid packet"); { static const char* langs[] = { "any", "English", "German", "French" }; unsigned i = *ptr++; if(i > 3) i = 0; add_rule(server, "language", (char*)langs[i], NO_FLAGS); } add_rule(server, "password", *ptr++ ? "1" : "0", NO_FLAGS); server->max_players = *ptr++; server->num_players = *ptr++; server->num_spectators = *ptr++; GET_STRING; server->map_name = strdup(str); snprintf(buf, sizeof(buf), "%hu", swap_short_from_little(ptr)); add_rule(server, "map_width", buf, NO_FLAGS); snprintf(buf, sizeof(buf), "%hu", swap_short_from_little(ptr)); add_rule(server, "map_height", buf, NO_FLAGS); { static const char* sets[] = { "temperate", "arctic", "desert", "toyland" }; unsigned i = *ptr++; if(i > 3) i = 0; add_rule(server, "map_set", (char*)sets[i], NO_FLAGS); } add_rule(server, "dedicated", *ptr++ ? "1" : "0", NO_FLAGS); } else if(type == 3) // player packet { unsigned i, j; INVALID_IF(ptr + 2 > end); server->num_players = *ptr++; for(i = 0; i < server->num_players; ++i) { unsigned long long lli; struct player* player; unsigned char nr; nr = *ptr++; debug(3, "player number %d", nr); player = add_player(server, i); FAIL_IF(!player, "can't allocate player"); GET_STRING; player->name = strdup(str); debug(3, "name %s", str); player->frags = 0; INVALID_IF(ptr + 4 + 3*8 + 2 + 1 + 2*MAX_VEHICLE_TYPES + 2*MAX_STATION_TYPES > end); snprintf(buf, sizeof(buf), "%u", swap_long_from_little(ptr)); player_add_info(player, "startdate", buf, 0); ptr += 4; lli = swap_long_from_little(ptr+4); lli <<= 32; lli += swap_long_from_little(ptr); snprintf(buf, sizeof(buf), "%lld", lli); player_add_info(player, "value", buf, 0); ptr += 8; lli = swap_long_from_little(ptr+4); lli <<= 32; lli = swap_long_from_little(ptr); snprintf(buf, sizeof(buf), "%lld", lli); player_add_info(player, "money", buf, 0); ptr += 8; lli = swap_long_from_little(ptr+4); lli <<= 32; lli += swap_long_from_little(ptr); snprintf(buf, sizeof(buf), "%lld", lli); player_add_info(player, "income", buf, 0); ptr += 8; snprintf(buf, sizeof(buf), "%hu", swap_short_from_little(ptr)); player_add_info(player, "performance", buf, 0); ptr += 2; player_add_info(player, "password", *ptr?"1":"0", 0); ++ptr; for (j = 0; j < MAX_VEHICLE_TYPES; ++j) { snprintf(buf, sizeof(buf), "%hu", swap_short_from_little(ptr)); player_add_info(player, (char*)vehicle_types[j], buf, 0); ptr += 2; } for (j = 0; j < MAX_STATION_TYPES; ++j) { snprintf(buf, sizeof(buf), "%hu", swap_short_from_little(ptr)); player_add_info(player, (char*)station_types[j], buf, 0); ptr += 2; } if (ver != 5) { // connections while(ptr + 1 < end && *ptr) { ++ptr; GET_STRING; // client name debug(3, "%s played by %s", str, player->name); GET_STRING; // id INVALID_IF(ptr + 4 > end); ptr += 4; } ++ptr; // record terminated by zero byte } } // spectators while(ptr + 1 < end && *ptr) { ++ptr; GET_STRING; // client name debug(3, "spectator %s", str); GET_STRING; // id INVALID_IF(ptr + 4 > end); ptr += 4; } ++ptr; // record terminated by zero byte server->next_rule = NO_SERVER_RULES; // we're done server->next_player_info = server->num_players; // we're done } else { malformed_packet( server, "invalid type" ); return PKT_ERROR; } server->retry1 = n_retries; // we're done with this packet, reset retry counter return DONE_AUTO; } query_status_t send_ottdmaster_request_packet(struct qserver *server) { return qserver_send_initial(server, server->type->master_packet, server->type->master_len); } query_status_t send_ottd_request_packet(struct qserver *server) { qserver_send_initial(server, server->type->status_packet, server->type->status_len); if(get_server_rules || get_player_info) { server->next_rule = ""; // trigger calling send_a2s_rule_request_packet } return INPROGRESS; } qstat-2.15/haze.c0000644000175000017500000003150312420765615010623 00000000000000/* * qstat * by Steve Jankowski * * New Haze query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #endif #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" // Format: // 1 - 8: Challenge Request / Response char haze_challenge[] = { 'f', 'r', 'd', 'c', '_', '_', '_', '_' }; int process_haze_packet( struct qserver *server ); // Player headers #define PLAYER_NAME_HEADER 1 #define PLAYER_SCORE_HEADER 2 #define PLAYER_DEATHS_HEADER 3 #define PLAYER_PING_HEADER 4 #define PLAYER_KILLS_HEADER 5 #define PLAYER_TEAM_HEADER 6 #define PLAYER_OTHER_HEADER 7 // Team headers #define TEAM_NAME_HEADER 1 #define TEAM_OTHER_HEADER 2 // Challenge response algorithum // Before sending a qr2 query (type 0x00) the client must first send a // challenge request (type 0x09). The host will respond with the same // packet type containing a string signed integer. // // Once the challenge is received the client should convert the string to a // network byte order integer and embed it in the keys query. // // Example: // // challenge request: [0xFE][0xFD][0x09][0x.. 4-byte-instance] // challenge response: [0x09][0x.. 4-byte-instance]["-1287574694"] // query: [0xFE][0xFD][0x00][0x.. 4-byte-instance][0xb3412b5a "-1287574694"] // query_status_t deal_with_haze_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *ptr = rawpkt; unsigned int pkt_id; unsigned short len; unsigned char pkt_max, pkt_index; debug( 2, "packet..." ); if ( pktlen < 8 ) { // invalid packet malformed_packet( server, "too short" ); return PKT_ERROR; } if ( 0 == strncmp( ptr, "frdcr", 5 ) ) { // challenge response ptr += 8; server->challenge = 1; // Correct the stats due to two phase protocol server->retry1++; server->n_packets--; if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST ) { //server->n_requests--; } else { server->n_retries--; } return send_haze_request_packet( server ); } if ( pktlen < 12 ) { // invalid packet malformed_packet( server, "too short" ); 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); } // Query version ID ptr += 4; // Could check the header here should // match the 4 byte id sent memcpy( &pkt_id, ptr, 4 ); ptr += 4; // Max plackets pkt_max = ((unsigned char)*ptr); ptr++; // Packet ID pkt_index = ((unsigned char)*ptr); ptr++; // Query Length debug( 1, "%04hx, %04hx", (unsigned short)ptr[0], (unsigned short)(ptr[1] << 8)); // TODO: fix this crap memcpy( &len, ptr+1, 1 ); ptr += 2; debug( 1, "pkt_index = %d, pkt_max = %d, len = %d", pkt_index, pkt_max, len ); if ( 0 != pkt_max ) { // not a single packet response or callback debug( 2, "pkt_max %d", pkt_max ); if ( 0 == pkt_index ) { // to prevent reprocessing when we get the call back // override the packet flag so it looks like a single // packet response rawpkt[8] = '\0'; } // add the packet recalcing maxes if ( ! add_packet( server, pkt_id, pkt_index, 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 ); } // if we get here we have what should be a full packet return process_haze_packet( server ); } query_status_t deal_with_haze_status( struct qserver *server, char *rawpkt, int pktlen ) { char *pkt = rawpkt; int len; debug( 1, "status packet" ); // Server name server->server_name = strdup( pkt ); pkt += strlen( pkt ) + 1; // gametype add_rule( server, "gametype", pkt, NO_FLAGS ); pkt += strlen( pkt ) + 1; // map len = strlen( pkt ); // remove .res from map names if ( 0 == strncmp( pkt + len - 4, ".res", 4 ) ) { *(pkt + len - 4) = '\0'; } server->map_name = strdup( pkt ); pkt += len + 1; // num players server->num_players = atoi( pkt ); pkt += strlen( pkt ) + 1; // max_players server->max_players = atoi( pkt ); pkt += strlen( pkt ) + 1; // hostport change_server_port( server, atoi( pkt ), 0 ); pkt += strlen( pkt ) + 1; return DONE_FORCE; } int process_haze_packet( struct qserver *server ) { unsigned char state = 0; unsigned char no_players = 0; unsigned char total_players = 0; unsigned char no_teams = 0; unsigned char total_teams = 0; int pkt_index = 0; SavedData *fragment; debug( 2, "processing packet..." ); while ( NULL != ( fragment = get_packet_fragment( pkt_index++ ) ) ) { int pktlen = fragment->datalen; char *ptr = fragment->data; char *end = ptr + pktlen; debug( 2, "processing fragment[%d]...", fragment->pkt_index ); // check we have a full header if ( pktlen < 12 ) { // invalid packet malformed_packet( server, "too short" ); return PKT_ERROR; } // skip over the header //server->protocol_version = atoi( val+1 ); ptr += 12; // 4 * null's signifies the end of a section // Basic Info while ( 0 == state && ptr < end ) { // name value pairs null seperated char *var, *val; int var_len, val_len; if ( ptr+4 <= end && 0x00 == ptr[0] && 0x00 == ptr[1] && 0x00 == ptr[2] && 0x00 == ptr[3] ) { // end of rules state++; ptr += 4; break; } var = ptr; var_len = strlen( var ); ptr += var_len + 1; if ( ptr + 1 > end ) { malformed_packet( server, "no basic value" ); return PKT_ERROR; } 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, "serverName" ) ) { server->server_name = strdup( val ); } else if( 0 == strcmp( var, "map" ) ) { // remove .res from map names if ( 0 == strncmp( val + val_len - 4, ".res", 4 ) ) { *(val + val_len - 4) = '\0'; } server->map_name = strdup( val ); } else if( 0 == strcmp( var, "maxPlayers" ) ) { server->max_players = atoi( val ); } else if( 0 == strcmp( var, "currentPlayers" ) ) { server->num_players = no_players = atoi( val ); } else { add_rule( server, var, val, NO_FLAGS ); } } // rules while ( 1 == state && ptr < end ) { // name value pairs null seperated char *var, *val; int var_len, val_len; if ( ptr+4 <= end && 0x00 == ptr[0] && 0x00 == ptr[1] && 0x00 == ptr[2] && 0x00 == ptr[3] ) { // end of basic state++; ptr += 4; break; } var = ptr; var_len = strlen( var ); ptr += var_len + 1; if ( ptr + 1 > end ) { malformed_packet( server, "no basic value" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "var:%s (%d)=%s (%d)\n", var, var_len, val, val_len ); // add the rule add_rule( server, var, val, NO_FLAGS ); } // players while ( 2 == state && ptr < end ) { // first we have the header char *header = ptr; int head_len = strlen( header ); ptr += head_len + 1; if ( ptr+2 <= end && 0x00 == ptr[0] && 0x00 == ptr[1] ) { // end of player headers state++; ptr += 2; break; } if ( 0 == head_len ) { // no more info debug( 3, "All done" ); return DONE_FORCE; } debug( 2, "player header '%s'", header ); if ( ptr > end ) { malformed_packet( server, "no details for header '%s'", header ); return PKT_ERROR; } } while ( 3 == state && ptr < end ) { char *header = ptr; int head_len = strlen( header ); int header_type; // the next byte is the starting number total_players = *ptr++; if ( 0 == strcmp( header, "player_" ) || 0 == strcmp( header, "name_" ) ) { header_type = PLAYER_NAME_HEADER; } else if ( 0 == strcmp( header, "score_" ) ) { header_type = PLAYER_SCORE_HEADER; } else if ( 0 == strcmp( header, "deaths_" ) ) { header_type = PLAYER_DEATHS_HEADER; } else if ( 0 == strcmp( header, "ping_" ) ) { header_type = PLAYER_PING_HEADER; } else if ( 0 == strcmp( header, "kills_" ) ) { header_type = PLAYER_KILLS_HEADER; } else if ( 0 == strcmp( header, "team_" ) ) { header_type = PLAYER_TEAM_HEADER; } else { header_type = PLAYER_OTHER_HEADER; } while( ptr < end ) { // now each player details // add the player struct player *player; char *val; int val_len; // check for end of this headers player info if ( 0x00 == *ptr ) { debug( 3, "end of '%s' detail", header ); ptr++; // Note: can't check ( total_players != no_players ) here as we may have more packets if ( ptr < end && 0x00 == *ptr ) { debug( 3, "end of players" ); // end of all player headers / detail state = 2; ptr++; } break; } player = get_player_by_number( server, total_players ); if ( NULL == player ) { player = add_player( server, total_players ); } if ( ptr >= end ) { malformed_packet( server, "short player detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "Player[%d][%s]=%s\n", total_players, header, val ); // lets see what we got switch( header_type ) { case PLAYER_NAME_HEADER: player->name = strdup( val ); break; case PLAYER_SCORE_HEADER: player->score = atoi( val ); break; case PLAYER_DEATHS_HEADER: player->deaths = atoi( val ); break; case PLAYER_PING_HEADER: player->ping = atoi( val ); break; case PLAYER_KILLS_HEADER: player->frags = atoi( val ); break; case PLAYER_TEAM_HEADER: player->team = atoi( val ); break; case PLAYER_OTHER_HEADER: default: if ( '_' == header[head_len-1] ) { header[head_len-1] = '\0'; player_add_info( player, header, val, NO_FLAGS ); header[head_len-1] = '_'; } else { player_add_info( player, header, val, NO_FLAGS ); } break; } total_players++; if ( total_players > no_players ) { malformed_packet( server, "to many players %d > %d", total_players, no_players ); return PKT_ERROR; } } } if ( 3 == state ) { no_teams = (unsigned char)*ptr; ptr++; debug( 2, "No teams:%d\n", no_teams ); state = 3; } while ( 4 == state && ptr < end ) { // first we have the header char *header = ptr; int head_len = strlen( header ); int header_type; ptr += head_len + 1; if ( 0 == head_len ) { // no more info debug( 3, "All done" ); return DONE_FORCE; } debug( 2, "team header '%s'", header ); if ( 0 == strcmp( header, "team_t" ) ) { header_type = TEAM_NAME_HEADER; } else { header_type = TEAM_OTHER_HEADER; } // the next byte is the starting number total_teams = *ptr++; while( ptr < end ) { // now each teams details char *val; int val_len; char rule[512]; if ( ptr >= end ) { malformed_packet( server, "short team detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "Team[%d][%s]=%s\n", total_teams, header, val ); // lets see what we got switch ( header_type ) { case TEAM_NAME_HEADER: // BF being stupid again teams 1 based instead of 0 players_set_teamname( server, total_teams + 1, val ); // N.B. yes no break case TEAM_OTHER_HEADER: default: // add as a server rule sprintf( rule, "%s%d", header, total_teams ); add_rule( server, rule, val, NO_FLAGS ); break; } total_teams++; if ( 0x00 == *ptr ) { // end of this headers teams ptr++; break; } } } } return DONE_FORCE; } query_status_t send_haze_request_packet( struct qserver *server ) { char *packet; char query_buf[128]; size_t len; unsigned char required = HAZE_BASIC_INFO; if ( get_server_rules ) { required |= HAZE_GAME_RULES; server->flags |= TF_PLAYER_QUERY; } if ( get_player_info ) { required |= HAZE_PLAYER_INFO; required |= HAZE_TEAM_INFO; server->flags |= TF_RULES_QUERY; } server->flags |= TF_STATUS_QUERY; if ( server->challenge ) { // we've recieved a challenge response, send the query + challenge id len = sprintf( query_buf, "frdquery%c%c%c%c%c", (unsigned char)(server->challenge >> 24), (unsigned char)(server->challenge >> 16), (unsigned char)(server->challenge >> 8), (unsigned char)(server->challenge >> 0), required ); packet = query_buf; } else { // Either basic v3 protocol or challenge request packet = haze_challenge; len = sizeof( haze_challenge ); } return send_packet( server, packet, len ); } qstat-2.15/utils.c0000644000175000017500000000627612420765614011044 00000000000000/* * Utility Functions * */ #include "utils.h" #if !HAVE_STRNSTR /* * strnstr - * Copyright (c) 2001 Mike Barcroft * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include char * qstat_strnstr(const char *s, const char *find, size_t slen) { char c, sc; size_t len; if ((c = *find++) != '\0') { len = strlen(find); do { do { if (slen-- < 1 || (sc = *s++) == '\0') return (NULL); } while (sc != c); if (len > slen) return (NULL); } while (strncmp(s, find, len) != 0); s--; } return ((char *)s); } #endif /* HAVE_STRNSTR */ #if !HAVE_ERR_H #include #include #include void err(int eval, const char *fmt, ...) { va_list list; va_start(list, fmt); warn(fmt, list); va_end(list); exit(eval); } void warn(const char *fmt, ...) { va_list list; va_start(list, fmt); if (fmt) fprintf(stderr, fmt, list); fprintf(stderr, "%s\n", strerror(errno)); va_end(list); } #endif /* HAVE_ERR_H */ #include // NOTE: replace must be smaller or equal in size to find char *str_replace(char *source, char *find, char *replace) { char *s = strstr(source, find); int rlen = strlen(replace); int flen = strlen(find); while(NULL != s) { strncpy(s, replace, rlen); strcpy(s + rlen, s + flen); s += rlen; s = strstr(s, find); } return source; } qstat-2.15/missing0000755000175000017500000001533012420766264011130 00000000000000#! /bin/sh # Common wrapper for a few potentially missing GNU programs. scriptversion=2013-10-28.13; # UTC # Copyright (C) 1996-2013 Free Software Foundation, Inc. # Originally written by Fran,cois Pinard , 1996. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. if test $# -eq 0; then echo 1>&2 "Try '$0 --help' for more information" exit 1 fi case $1 in --is-lightweight) # Used by our autoconf macros to check whether the available missing # script is modern enough. exit 0 ;; --run) # Back-compat with the calling convention used by older automake. shift ;; -h|--h|--he|--hel|--help) echo "\ $0 [OPTION]... PROGRAM [ARGUMENT]... Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due to PROGRAM being missing or too old. Options: -h, --help display this help and exit -v, --version output version information and exit Supported PROGRAM values: aclocal autoconf autoheader autom4te automake makeinfo bison yacc flex lex help2man Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and 'g' are ignored when checking the name. Send bug reports to ." exit $? ;; -v|--v|--ve|--ver|--vers|--versi|--versio|--version) echo "missing $scriptversion (GNU Automake)" exit $? ;; -*) echo 1>&2 "$0: unknown '$1' option" echo 1>&2 "Try '$0 --help' for more information" exit 1 ;; esac # Run the given program, remember its exit status. "$@"; st=$? # If it succeeded, we are done. test $st -eq 0 && exit 0 # Also exit now if we it failed (or wasn't found), and '--version' was # passed; such an option is passed most likely to detect whether the # program is present and works. case $2 in --version|--help) exit $st;; esac # Exit code 63 means version mismatch. This often happens when the user # tries to use an ancient version of a tool on a file that requires a # minimum version. if test $st -eq 63; then msg="probably too old" elif test $st -eq 127; then # Program was missing. msg="missing on your system" else # Program was found and executed, but failed. Give up. exit $st fi perl_URL=http://www.perl.org/ flex_URL=http://flex.sourceforge.net/ gnu_software_URL=http://www.gnu.org/software program_details () { case $1 in aclocal|automake) echo "The '$1' program is part of the GNU Automake package:" echo "<$gnu_software_URL/automake>" echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/autoconf>" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; autoconf|autom4te|autoheader) echo "The '$1' program is part of the GNU Autoconf package:" echo "<$gnu_software_URL/autoconf/>" echo "It also requires GNU m4 and Perl in order to run:" echo "<$gnu_software_URL/m4/>" echo "<$perl_URL>" ;; esac } give_advice () { # Normalize program name to check for. normalized_program=`echo "$1" | sed ' s/^gnu-//; t s/^gnu//; t s/^g//; t'` printf '%s\n' "'$1' is $msg." configure_deps="'configure.ac' or m4 files included by 'configure.ac'" case $normalized_program in autoconf*) echo "You should only need it if you modified 'configure.ac'," echo "or m4 files included by it." program_details 'autoconf' ;; autoheader*) echo "You should only need it if you modified 'acconfig.h' or" echo "$configure_deps." program_details 'autoheader' ;; automake*) echo "You should only need it if you modified 'Makefile.am' or" echo "$configure_deps." program_details 'automake' ;; aclocal*) echo "You should only need it if you modified 'acinclude.m4' or" echo "$configure_deps." program_details 'aclocal' ;; autom4te*) echo "You might have modified some maintainer files that require" echo "the 'autom4te' program to be rebuilt." program_details 'autom4te' ;; bison*|yacc*) echo "You should only need it if you modified a '.y' file." echo "You may want to install the GNU Bison package:" echo "<$gnu_software_URL/bison/>" ;; lex*|flex*) echo "You should only need it if you modified a '.l' file." echo "You may want to install the Fast Lexical Analyzer package:" echo "<$flex_URL>" ;; help2man*) echo "You should only need it if you modified a dependency" \ "of a man page." echo "You may want to install the GNU Help2man package:" echo "<$gnu_software_URL/help2man/>" ;; makeinfo*) echo "You should only need it if you modified a '.texi' file, or" echo "any other file indirectly affecting the aspect of the manual." echo "You might want to install the Texinfo package:" echo "<$gnu_software_URL/texinfo/>" echo "The spurious makeinfo call might also be the consequence of" echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might" echo "want to install GNU make:" echo "<$gnu_software_URL/make/>" ;; *) echo "You might have modified some files without having the proper" echo "tools for further handling them. Check the 'README' file, it" echo "often tells you about the needed prerequisites for installing" echo "this package. You may also peek at any GNU archive site, in" echo "case some other package contains this missing '$1' program." ;; esac } give_advice "$1" | sed -e '1s/^/WARNING: /' \ -e '2,$s/^/ /' >&2 # Propagate the correct exit status (expected to be 127 for a program # not found, 63 for a program that failed due to version mismatch). exit $st # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: qstat-2.15/doom3.h0000644000175000017500000000227612420765614010726 00000000000000/* * qstat * by Steve Jankowski * * Doom3 / Quake4 protocol * Copyright 2005 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_DOOM3_H #define QSTAT_DOOM3_H #define DOOM3_DEFAULT_PORT 27666 #define DOOM3_MASTER_DEFAULT_PORT 27650 #define QUAKE4_DEFAULT_PORT 28004 #define QUAKE4_MASTER_DEFAULT_PORT 27650 #define PREY_DEFAULT_PORT 27719 #define PREY_MASTER_DEFAULT_PORT 27655 #define ETQW_DEFAULT_PORT 27733 #define WOLF_DEFAULT_PORT 27758 query_status_t send_doom3master_request_packet( struct qserver *server); query_status_t deal_with_doom3master_packet( struct qserver *server, char *rawpkt, int pktlen); query_status_t deal_with_doom3_packet( struct qserver *server, char *rawpkt, int pktlen); query_status_t send_quake4master_request_packet( struct qserver *server); query_status_t deal_with_quake4_packet( struct qserver *server, char *rawpkt, int pktlen); query_status_t deal_with_prey_packet( struct qserver *server, char *rawpkt, int pktlen); query_status_t deal_with_etqw_packet( struct qserver *server, char *rawpkt, int pktlen); query_status_t deal_with_wolf_packet( struct qserver *server, char *rawpkt, int pktlen); #endif qstat-2.15/install-sh0000755000175000017500000003325512420766264011543 00000000000000#!/bin/sh # install - install a program, script, or datafile scriptversion=2011-11-20.07; # UTC # This originates from X11R5 (mit/util/scripts/install.sh), which was # later released in X11R6 (xc/config/util/install.sh) with the # following copyright and license. # # Copyright (C) 1994 X Consortium # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to # deal in the Software without restriction, including without limitation the # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or # sell copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the X Consortium shall not # be used in advertising or otherwise to promote the sale, use or other deal- # ings in this Software without prior written authorization from the X Consor- # tium. # # # FSF changes to this file are in the public domain. # # Calling this script install-sh is preferred over install.sh, to prevent # 'make' implicit rules from creating a file called install from it # when there is no Makefile. # # This script is compatible with the BSD install script, but was written # from scratch. nl=' ' IFS=" "" $nl" # set DOITPROG to echo to test this script # Don't use :- since 4.3BSD and earlier shells don't like it. doit=${DOITPROG-} if test -z "$doit"; then doit_exec=exec else doit_exec=$doit fi # Put in absolute file names if you don't have them in your path; # or use environment vars. chgrpprog=${CHGRPPROG-chgrp} chmodprog=${CHMODPROG-chmod} chownprog=${CHOWNPROG-chown} cmpprog=${CMPPROG-cmp} cpprog=${CPPROG-cp} mkdirprog=${MKDIRPROG-mkdir} mvprog=${MVPROG-mv} rmprog=${RMPROG-rm} stripprog=${STRIPPROG-strip} posix_glob='?' initialize_posix_glob=' test "$posix_glob" != "?" || { if (set -f) 2>/dev/null; then posix_glob= else posix_glob=: fi } ' posix_mkdir= # Desired mode of installed file. mode=0755 chgrpcmd= chmodcmd=$chmodprog chowncmd= mvcmd=$mvprog rmcmd="$rmprog -f" stripcmd= src= dst= dir_arg= dst_arg= copy_on_change=false no_target_directory= usage="\ Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE or: $0 [OPTION]... SRCFILES... DIRECTORY or: $0 [OPTION]... -t DIRECTORY SRCFILES... or: $0 [OPTION]... -d DIRECTORIES... In the 1st form, copy SRCFILE to DSTFILE. In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. In the 4th, create DIRECTORIES. Options: --help display this help and exit. --version display version info and exit. -c (ignored) -C install only if different (preserve the last data modification time) -d create directories instead of installing files. -g GROUP $chgrpprog installed files to GROUP. -m MODE $chmodprog installed files to MODE. -o USER $chownprog installed files to USER. -s $stripprog installed files. -t DIRECTORY install into DIRECTORY. -T report an error if DSTFILE is a directory. Environment variables override the default commands: CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG " while test $# -ne 0; do case $1 in -c) ;; -C) copy_on_change=true;; -d) dir_arg=true;; -g) chgrpcmd="$chgrpprog $2" shift;; --help) echo "$usage"; exit $?;; -m) mode=$2 case $mode in *' '* | *' '* | *' '* | *'*'* | *'?'* | *'['*) echo "$0: invalid mode: $mode" >&2 exit 1;; esac shift;; -o) chowncmd="$chownprog $2" shift;; -s) stripcmd=$stripprog;; -t) dst_arg=$2 # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac shift;; -T) no_target_directory=true;; --version) echo "$0 $scriptversion"; exit $?;; --) shift break;; -*) echo "$0: invalid option: $1" >&2 exit 1;; *) break;; esac shift done if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then # When -d is used, all remaining arguments are directories to create. # When -t is used, the destination is already specified. # Otherwise, the last argument is the destination. Remove it from $@. for arg do if test -n "$dst_arg"; then # $@ is not empty: it contains at least $arg. set fnord "$@" "$dst_arg" shift # fnord fi shift # arg dst_arg=$arg # Protect names problematic for 'test' and other utilities. case $dst_arg in -* | [=\(\)!]) dst_arg=./$dst_arg;; esac done fi if test $# -eq 0; then if test -z "$dir_arg"; then echo "$0: no input file specified." >&2 exit 1 fi # It's OK to call 'install-sh -d' without argument. # This can happen when creating conditional directories. exit 0 fi if test -z "$dir_arg"; then do_exit='(exit $ret); exit $ret' trap "ret=129; $do_exit" 1 trap "ret=130; $do_exit" 2 trap "ret=141; $do_exit" 13 trap "ret=143; $do_exit" 15 # Set umask so as not to create temps with too-generous modes. # However, 'strip' requires both read and write access to temps. case $mode in # Optimize common cases. *644) cp_umask=133;; *755) cp_umask=22;; *[0-7]) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw='% 200' fi cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; *) if test -z "$stripcmd"; then u_plus_rw= else u_plus_rw=,u+rw fi cp_umask=$mode$u_plus_rw;; esac fi for src do # Protect names problematic for 'test' and other utilities. case $src in -* | [=\(\)!]) src=./$src;; esac if test -n "$dir_arg"; then dst=$src dstdir=$dst test -d "$dstdir" dstdir_status=$? else # Waiting for this to be detected by the "$cpprog $src $dsttmp" command # might cause directories to be created, which would be especially bad # if $src (and thus $dsttmp) contains '*'. if test ! -f "$src" && test ! -d "$src"; then echo "$0: $src does not exist." >&2 exit 1 fi if test -z "$dst_arg"; then echo "$0: no destination specified." >&2 exit 1 fi dst=$dst_arg # If destination is a directory, append the input filename; won't work # if double slashes aren't ignored. if test -d "$dst"; then if test -n "$no_target_directory"; then echo "$0: $dst_arg: Is a directory" >&2 exit 1 fi dstdir=$dst dst=$dstdir/`basename "$src"` dstdir_status=0 else # Prefer dirname, but fall back on a substitute if dirname fails. dstdir=` (dirname "$dst") 2>/dev/null || expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$dst" : 'X\(//\)[^/]' \| \ X"$dst" : 'X\(//\)$' \| \ X"$dst" : 'X\(/\)' \| . 2>/dev/null || echo X"$dst" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q' ` test -d "$dstdir" dstdir_status=$? fi fi obsolete_mkdir_used=false if test $dstdir_status != 0; then case $posix_mkdir in '') # Create intermediate dirs using mode 755 as modified by the umask. # This is like FreeBSD 'install' as of 1997-10-28. umask=`umask` case $stripcmd.$umask in # Optimize common cases. *[2367][2367]) mkdir_umask=$umask;; .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; *[0-7]) mkdir_umask=`expr $umask + 22 \ - $umask % 100 % 40 + $umask % 20 \ - $umask % 10 % 4 + $umask % 2 `;; *) mkdir_umask=$umask,go-w;; esac # With -d, create the new directory with the user-specified mode. # Otherwise, rely on $mkdir_umask. if test -n "$dir_arg"; then mkdir_mode=-m$mode else mkdir_mode= fi posix_mkdir=false case $umask in *[123567][0-7][0-7]) # POSIX mkdir -p sets u+wx bits regardless of umask, which # is incompatible with FreeBSD 'install' when (umask & 300) != 0. ;; *) tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 if (umask $mkdir_umask && exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 then if test -z "$dir_arg" || { # Check for POSIX incompatibilities with -m. # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or # other-writable bit of parent directory when it shouldn't. # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. ls_ld_tmpdir=`ls -ld "$tmpdir"` case $ls_ld_tmpdir in d????-?r-*) different_mode=700;; d????-?--*) different_mode=755;; *) false;; esac && $mkdirprog -m$different_mode -p -- "$tmpdir" && { ls_ld_tmpdir_1=`ls -ld "$tmpdir"` test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" } } then posix_mkdir=: fi rmdir "$tmpdir/d" "$tmpdir" else # Remove any dirs left behind by ancient mkdir implementations. rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null fi trap '' 0;; esac;; esac if $posix_mkdir && ( umask $mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" ) then : else # The umask is ridiculous, or mkdir does not conform to POSIX, # or it failed possibly due to a race condition. Create the # directory the slow way, step by step, checking for races as we go. case $dstdir in /*) prefix='/';; [-=\(\)!]*) prefix='./';; *) prefix='';; esac eval "$initialize_posix_glob" oIFS=$IFS IFS=/ $posix_glob set -f set fnord $dstdir shift $posix_glob set +f IFS=$oIFS prefixes= for d do test X"$d" = X && continue prefix=$prefix$d if test -d "$prefix"; then prefixes= else if $posix_mkdir; then (umask=$mkdir_umask && $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break # Don't fail if two instances are running concurrently. test -d "$prefix" || exit 1 else case $prefix in *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; *) qprefix=$prefix;; esac prefixes="$prefixes '$qprefix'" fi fi prefix=$prefix/ done if test -n "$prefixes"; then # Don't fail if two instances are running concurrently. (umask $mkdir_umask && eval "\$doit_exec \$mkdirprog $prefixes") || test -d "$dstdir" || exit 1 obsolete_mkdir_used=true fi fi fi if test -n "$dir_arg"; then { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 else # Make a couple of temp file names in the proper directory. dsttmp=$dstdir/_inst.$$_ rmtmp=$dstdir/_rm.$$_ # Trap to clean up those temp files at exit. trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 # Copy the file name to the temp name. (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && # and set any options; do chmod last to preserve setuid bits. # # If any of these fail, we abort the whole thing. If we want to # ignore errors from any of these, just make sure not to ignore # errors from the above "$doit $cpprog $src $dsttmp" command. # { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && # If -C, don't bother to copy if it wouldn't change the file. if $copy_on_change && old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && eval "$initialize_posix_glob" && $posix_glob set -f && set X $old && old=:$2:$4:$5:$6 && set X $new && new=:$2:$4:$5:$6 && $posix_glob set +f && test "$old" = "$new" && $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 then rm -f "$dsttmp" else # Rename the file to the real destination. $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || # The rename failed, perhaps because mv can't rename something else # to itself, or perhaps because mv is so ancient that it does not # support -f. { # Now remove or move aside any old file at destination location. # We try this two ways since rm can't unlink itself on some # systems and the destination file might be busy for other # reasons. In this case, the final cleanup might fail but the new # file should still install successfully. { test ! -f "$dst" || $doit $rmcmd -f "$dst" 2>/dev/null || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } } || { echo "$0: cannot unlink or rename $dst" >&2 (exit 1); exit 1 } } && # Now rename the file to the real destination. $doit $mvcmd "$dsttmp" "$dst" } fi || exit 1 trap '' 0 fi done # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: qstat-2.15/crysis.c0000644000175000017500000001346612420765614011217 00000000000000/* * qstat * by Steve Jankowski * * Crysis query protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "utils.h" #include "qstat.h" #include "md5.h" #include "packet_manip.h" char *decode_crysis_val( char *val ) { // Very basic html conversion val = str_replace( val, """, "\"" ); return str_replace( val, "&", "&" ); } query_status_t send_crysis_request_packet( struct qserver *server ) { char cmd[256], buf[1024], *password, *md5; debug( 2, "challenge: %ld", server->challenge ); switch ( server->challenge ) { case 0: // Not seen a challenge yet, request it server->challenge++; sprintf( cmd, "challenge" ); break; case 1: server->challenge++; password = get_param_value( server, "password", "" ); sprintf( cmd, "%s:%s", server->challenge_string, password ); md5 = md5_hex( cmd, strlen( cmd ) ); sprintf( cmd, "authenticate %s", md5 ); free( md5 ); break; case 2: // NOTE: we currently don't support player info server->challenge++; server->flags |= TF_STATUS_QUERY; server->n_servers = 3; sprintf( cmd, "status" ); break; case 3: return DONE_FORCE; } server->saved_data.pkt_max = -1; sprintf(buf, "POST /RPC2 HTTP/1.1\015\012Keep-Alive: 300\015\012User-Agent: qstat %s\015\012Content-Length: %d\015\012Content-Type: text/xml\015\012\015\012%s", VERSION, (int)(98 + strlen(cmd)), cmd); return send_packet( server, buf, strlen( buf ) ); } query_status_t valid_crysis_response( struct qserver *server, char *rawpkt, int pktlen ) { char *s; int len; int cnt = packet_count( server ); if ( 0 == cnt && 0 != strncmp( "HTTP/1.1 200 OK", rawpkt, 15 ) ) { // not valid response return REQ_ERROR; } s = strnstr(rawpkt, "Content-Length: ", pktlen ); if ( NULL == s ) { // not valid response return INPROGRESS; } s += 16; if ( 1 != sscanf( s, "%d", &len ) ) { return INPROGRESS; } s = strnstr(rawpkt, "\015\012\015\012", pktlen ); if ( NULL == s ) { return INPROGRESS; } s += 4; if ( pktlen != ( s - rawpkt + len ) ) { return INPROGRESS; } return DONE_FORCE; } char* crysis_response( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *e; int len = pktlen; s = strnstr(rawpkt, "", len ); if ( NULL == s ) { // not valid response return NULL; } s += 46; len += rawpkt - s; e = strnstr(s, "", len ); if ( NULL == e ) { // not valid response return NULL; } *e = '\0'; return strdup( s ); } query_status_t deal_with_crysis_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *val, *line; query_status_t state = INPROGRESS; debug( 2, "processing..." ); if ( ! server->combined ) { state = valid_crysis_response( server, rawpkt, pktlen ); server->retry1 = n_retries; if ( 0 == server->n_requests ) { server->ping_total = time_delta( &packet_recv_time, &server->packet_time1 ); server->n_requests++; } switch ( state ) { case INPROGRESS: { // 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++; 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 ); } case DONE_FORCE: break; // single packet response fall through default: return state; } } if ( DONE_FORCE != state ) { state = valid_crysis_response( server, rawpkt, pktlen ); switch ( state ) { case DONE_FORCE: break; // actually process default: return state; } } debug( 3, "packet: challenge = %ld", server->challenge ); s = NULL; switch ( server->challenge ) { case 1: s = crysis_response( server, rawpkt, pktlen ); if ( NULL != s ) { server->challenge_string = s; return send_crysis_request_packet( server ); } return REQ_ERROR; case 2: s = crysis_response( server, rawpkt, pktlen ); if ( NULL == s ) { return REQ_ERROR; } if ( 0 != strncmp( s, "authorized", 10 ) ) { free( s ); return REQ_ERROR; } free( s ); return send_crysis_request_packet( server ); case 3: s = crysis_response( server, rawpkt, pktlen ); if ( NULL == s ) { return REQ_ERROR; } } // 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 = decode_crysis_val( s ); line = strtok( s, "\012" ); // NOTE: id=XXX and msg=XXX will be processed by the mod following the one they where the response of while ( NULL != line ) { debug( 4, "LINE: %s\n", line ); val = strstr( line, ":" ); if ( NULL != val ) { *val = '\0'; val+=2; debug( 4, "var: %s, val: %s", line, val ); if ( 0 == strcmp( "name", line ) ) { server->server_name = strdup( val ); } else if ( 0 == strcmp( "level", line ) ) { server->map_name = strdup( val ); } else if ( 0 == strcmp( "players", line ) ) { if ( 2 == sscanf( val, "%d/%d", &server->num_players, &server->max_players) ) { } } else if ( 0 == strcmp( "version", line ) || 0 == strcmp( "gamerules", line ) || 0 == strcmp( "time remaining", line ) ) { add_rule( server, line, val, NO_FLAGS ); } } line = strtok( NULL, "\012" ); } gettimeofday( &server->packet_time1, NULL ); return DONE_FORCE; } qstat-2.15/ts2.c0000644000175000017500000000666312420765614010414 00000000000000/* * qstat * by Steve Jankowski * * Teamspeak 2 query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" 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; } qstat-2.15/ut2004.h0000644000175000017500000000064412420765614010640 00000000000000/* * qstat * by Steve Jankowski * * debug helper functions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_UT2004_H #define QSTAT_UT2004_H #include "qstat.h" query_status_t send_ut2004master_request_packet(struct qserver *server); query_status_t deal_with_ut2004master_packet(struct qserver *server, char *rawpkt, int pktlen); #endif qstat-2.15/template/0000755000175000017500000000000012420766316011420 500000000000000qstat-2.15/template/unrealTh.html0000644000175000017500000000066612420765615014021 00000000000000$HTML Unreal Servers

Unreal Servers

Last update: $NOW

Example of Unreal support in QStat.

qstat-2.15/template/ghostreconTt.html0000644000175000017500000000021712420765615014712 00000000000000
Server Name Players Map Address


$TOTALPLAYERS players on $TOTALUP servers.

Created with QStat $QSTATVERSION

qstat-2.15/template/README.txt0000644000175000017500000000170012420765615013035 00000000000000This directory contains the output templates used for the old broccoli server status page. ** The broccoli servers are no longer running. You should substitute ** your own server addresses into 'broc.lst'. brocTh.html header template brocTp.html player template brocTs.html server template brocTt.html trailer template broc.lst server list To generate an HTML page for the broccoli servers: qstat -P -f broc.lst -Ts brocTs.html -Th brocTh.html -Tt brocTt.html -Tp brocTp.html -sort g -of qservers.html The HTML output will be put in "qservers.html". I've also included some templates for Unreal/UT. They can be used like this: qstat -P -R -f unreal.lst -Th unrealTh.html -Tp unrealTp.html -Ts unrealTs.html -Tt unrealTt.html -sort g -of unreal.html The HTML output will be put in "unreal.html". qstat -P -R -f tribes2.lst -Th tribes2th.html -Tp tribes2tp.html -Ts tribes2ts.html -Tt tribes2tt.html -sort g -of tribes2.html qstat-2.15/template/Makefile.am0000644000175000017500000000004612420765615013375 00000000000000EXTRA_DIST = $(wildcard *.html *.txt) qstat-2.15/template/brocTp.html0000644000175000017500000000015312420765615013457 00000000000000   $PLAYERNAME $FRAGS $PLAYERPING qstat-2.15/template/Makefile.in0000644000175000017500000002543412420766264013417 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = template DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnuconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = $(wildcard *.html *.txt) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign template/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign template/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: qstat-2.15/template/ghostreconTh.html0000644000175000017500000000045012420765615014675 00000000000000$HTML Ghost Recon Servers

Ghost Recon Servers

Last update: $NOW

Example of Ghost Recon support in QStat.

qstat-2.15/template/tribes2tt.html0000644000175000017500000000021712420765615014151 00000000000000


$TOTALPLAYERS players on $TOTALUP servers.

Created with QStat $QSTATVERSION

qstat-2.15/template/tribes2tp.html0000644000175000017500000000073512420765615014152 00000000000000   $HTMLPLAYERNAME $(IF:ISBOT)Bot$(ENDIF)$(IF:ISALIAS)Alias$(ENDIF)$(IF:ISTEAM) $ENDIF $(IF:TRIBETAG)$TRIBETAG$(ENDIF)$(IF:ISTEAM) $ENDIF $FRAGS   $TEAMNAME$(IF:ISTEAM)TEAM$ENDIF qstat-2.15/template/ghostreconTs.html0000644000175000017500000000640412420765615014715 00000000000000
Server Name Players Map Mission  
$SERVERNAME $PLAYERS/$MAXPLAYERS $MAP $(RULE:mission)  
Game Mode Mission Type Dedicated Server Ip Addr  
$(RULE:gamemode) $(RULE:missiontype) $(RULE:dedicated) $IPADDR:$PORT  
Status Time Limit Time Played Remaining Time  
$(RULE:status) $(RULE:gametime) $(RULE:timeplayed) $(RULE:remainingtime)  
Version Spawn Type Spawn Count Restrictions  
$(RULE:version) $(RULE:spawntype) $(RULE:spawncount) $(RULE:restrict)  
Password Threat Indicator Patch Level Observing  
$(RULE:password) $(RULE:ti) $(RULE:patch) $(RULE:allowobservers)  
Start Timer Start Time Value Time untill Start Debrief Time  
$(RULE:usestarttime) $(RULE:starttimeset) $(RULE:startwait) $(RULE:debrieftime)  
Respawn Minimum Respawn Maximum Respawn Safe IFF Mode  
$(RULE:respawnmin) $(RULE:respawnmax) $(RULE:respawnsafe) $(RULE:iff)  
MOTD  
$(RULE:motd)  
Mods  
$GAME  
$(IF:PLAYERS)$(IF:FLAG(-P)) $PLAYERTEMPLATE
Player Name Team Health  
$ENDIF$ENDIF

qstat-2.15/template/unrealTp.html0000644000175000017500000000017712420765615014026 00000000000000   $PLAYERNAME $FRAGS $SKIN $TEAMNUM qstat-2.15/template/tribes2ts.html0000644000175000017500000000134012420765615014146 00000000000000$(IFNOT:ISMASTER) $SERVERNAME $PLAYERS/$MAXPLAYERS $RULE:mission $MAP $HOSTNAME $(IF:RULE(info))
$(RULE:info)
$(ENDIF) $(IF:PLAYERS)$(IF:FLAG(-P)) $PLAYERTEMPLATE
  Player Name Type Tribe Score   Team  
$ENDIF$ENDIF   $ENDIF qstat-2.15/template/brocTh.html0000644000175000017500000000140412420765615013447 00000000000000$HTML broccoli Quake 2 servers

broccoli Quake 2 servers

Last update: $NOW

The Solaris version of Quake II v 3.15 (soon 3.17) is not yet available. As soon as I can get my hands on the bits, I'll be running upgrading the server.

I run $TOTALSERVERS servers on a Sun Ultra 2 running Solaris 2.5.1. The machine has two CPUs, so performance is good even when I'm using it for work. Enjoy!

qstat-2.15/template/tribes2th.html0000644000175000017500000000075312420765615014142 00000000000000$HTML Tribes 2 Servers

Tribes 2 Servers

Last update: $NOW

Example of Tribes 2 support in QStat.

Server Name Players Map Game Address
qstat-2.15/template/unrealTt.html0000644000175000017500000000021712420765615014025 00000000000000
Server Name Players Mission Map Address


$TOTALPLAYERS players on $TOTALUP servers.

Created with QStat $QSTATVERSION

qstat-2.15/template/unrealTs.html0000644000175000017500000000123212420765615014022 00000000000000 $SERVERNAME $(IFNOT:QWMASTER)$PLAYERS/$MAXPLAYERS$(ENDIF) $MAP $HOSTNAME $(IF:RULE(AdminEMail)) $(RULE:AdminEMail)$(ENDIF) $(IF:PLAYERS)$(IF:FLAG(-P)) $PLAYERTEMPLATE
  Player Name Frags Skin Team  
$ENDIF$ENDIF   qstat-2.15/template/brocTs.html0000644000175000017500000000102312420765615013457 00000000000000 $SERVERNAME $(IFNOT:QWMASTER)$PLAYERS/$MAXPLAYERS$(ENDIF) $MAP $GAME $HOSTNAME $(IF:PLAYERS)$(IF:FLAG(-P)) $PLAYERTEMPLATE
  Player Name Frags Ping  
$ENDIF$ENDIF   qstat-2.15/template/brocTt.html0000644000175000017500000000021712420765615013464 00000000000000


$TOTALPLAYERS players on $TOTALUP servers.

Created with QStat $QSTATVERSION

qstat-2.15/template/ghostreconTp.html0000644000175000017500000000026112420765615014705 00000000000000 $PLAYERNAME $TEAMNAME $(IF:DEATHS)Dead$(ENDIF)$(IFNOT:DEATHS)Alive$(ENDIF)   qstat-2.15/doom3.c0000644000175000017500000003741112420765614010720 00000000000000/* * qstat * by Steve Jankowski * * Doom3 / Quake4 protocol * Copyright 2005 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #ifndef _WIN32 #include #endif #include #include #include "qstat.h" #include "debug.h" #include "assert.h" static const char doom3_master_query[] = "\xFF\xFFgetServers\x00\x00\x00\x00\x00\x00"; // version ^^^^^^^^^^^^^^^^ // null terminated mod string ^^^^ // filterbyte ^^^^ static const char quake4_master_query[] = "\xFF\xFFgetServers\x00\x00\x00\x00\x00\x00\x00\x00"; // version ^^^^^^^^^^^^^^^^ // null terminated mod string ^^^^ // null terminated player string ^^^^ // null terminated clan string ^^^^ // filterbyte ^^^^ static unsigned put_param_string(struct qserver* server, const char* paramname, char* buf, unsigned buflen, unsigned off) { char* val = get_param_value( server, paramname, NULL); if(val && strlen(val) < buflen-off-2) { strcpy(buf+off, val); off += strlen(val) + 1; } else { buf[off++] = '\0'; } return off; } static char* build_doom3_masterfilter(struct qserver* server, char* buf, unsigned* buflen, int q4) { int flen = 0; char *pkt, *r, *sep= ""; unsigned char b = 0; char *proto = server->query_arg; unsigned ver; unsigned off = 13; if(!proto) { if(q4) { *buflen = sizeof(quake4_master_query); return (char*)quake4_master_query; } else { *buflen = sizeof(doom3_master_query); return (char*)doom3_master_query; } } ver = (atoi(proto) & 0xFFFF) << 16; proto = strchr(proto, '.'); if(proto && *++proto) { ver |= (atoi(proto) & 0xFFFF); } if(q4) { ver |= 1 << 31; // third party flag } memcpy(buf, doom3_master_query, sizeof(doom3_master_query)); put_long_little(ver, buf+off); off += 4; off = put_param_string(server, "game", buf, *buflen, off); if(q4) { off = put_param_string(server, "player", buf, *buflen, off); off = put_param_string(server, "clan", buf, *buflen, off); } pkt = get_param_value( server, "status", NULL); r = pkt ; while ( pkt && sep ) { sep= strchr( r, ':'); if ( sep ) flen= sep-r; else flen= strlen(r); if ( strncmp( r, "password", flen) == 0) b |= 0x01; else if ( strncmp( r, "nopassword", flen) == 0) b |= 0x02; else if ( strncmp( r, "notfull", flen) == 0) b |= 0x04; else if ( strncmp( r, "notfullnotempty", flen) == 0) b |= 0x08; r= sep+1; } pkt = get_param_value( server, "gametype", NULL); if(pkt) { if ( strncmp( pkt, "dm", flen) == 0) b |= 0x10; else if ( strncmp( pkt, "tourney", flen) == 0) b |= 0x20; else if ( strncmp( pkt, "tdm", flen) == 0) b |= 0x30; } buf[off++] = (char)b; *buflen = off; return buf; } query_status_t send_doom3master_request_packet( struct qserver *server) { int rc = 0; int packet_len = -1; char* packet = NULL; char query_buf[4096] = {0}; server->next_player_info = NO_PLAYER_INFO; packet_len = sizeof(query_buf); packet = build_doom3_masterfilter(server, query_buf, (unsigned*)&packet_len, 0); rc= send( server->fd, packet, packet_len, 0); if ( rc == SOCKET_ERROR) { return send_error( server, rc ); } if ( server->retry1 == n_retries) { gettimeofday( &server->packet_time1, NULL); server->n_requests++; } else { server->n_retries++; } server->retry1--; server->n_packets++; return INPROGRESS; } query_status_t send_quake4master_request_packet( struct qserver *server) { int rc = 0; int packet_len = -1; char* packet = NULL; char query_buf[4096] = {0}; server->next_player_info = NO_PLAYER_INFO; packet_len = sizeof(query_buf); packet = build_doom3_masterfilter(server, query_buf, (unsigned*)&packet_len, 1); rc= send( server->fd, packet, packet_len, 0); if ( rc == SOCKET_ERROR) { return send_error( server, rc ); } if ( server->retry1 == n_retries) { gettimeofday( &server->packet_time1, NULL); server->n_requests++; } else { server->n_retries++; } server->retry1--; server->n_packets++; return INPROGRESS; } static const char doom3_masterresponse[] = "\xFF\xFFservers"; query_status_t deal_with_doom3master_packet( struct qserver *server, char *rawpkt, int pktlen) { char* pkt, *dest; int len; server->ping_total+= time_delta( &packet_recv_time, &server->packet_time1); if ( pktlen < sizeof(doom3_masterresponse) + 6 // at least one server || (pktlen - sizeof(doom3_masterresponse)) % 6 || memcmp( doom3_masterresponse, rawpkt, sizeof(doom3_masterresponse) ) != 0 ) { server->server_name= SERVERERROR; server->master_pkt_len = 0; malformed_packet(server, "too short or invalid response"); return PKT_ERROR; } server->retry1 = 0; // received at least one packet so no need to retry pkt = rawpkt + sizeof(doom3_masterresponse); len = pktlen - sizeof(doom3_masterresponse); server->master_pkt = (char*)realloc( server->master_pkt, server->master_pkt_len + len); dest = server->master_pkt + server->master_pkt_len; server->master_pkt_len += len; while(len > 0) { memcpy(dest, pkt, 4 ); dest[4] = pkt[5]; dest[5] = pkt[4]; dest += 6; pkt += 6; len -= 6; } assert(len == 0); server->n_servers= server->master_pkt_len / 6; debug(2, "%d servers added", server->n_servers); return INPROGRESS; } static const char doom3_inforesponse[] = "\xFF\xFFinfoResponse"; static unsigned MAX_DOOM3_ASYNC_CLIENTS = 32; static unsigned MAX_WOLF_ASYNC_CLIENTS = 16; static query_status_t _deal_with_doom3_packet( struct qserver *server, char *rawpkt, int pktlen, unsigned version ) { char *ptr = rawpkt; char *end = rawpkt + pktlen; int type = 0; int size = 0; int tail_size = 4; int viewers = 0; int tv = 0; unsigned num_players = 0; unsigned challenge = 0; unsigned protocolver = 0; char tmp[32]; 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); } // Check if correct reply if ( pktlen < sizeof(doom3_inforesponse) +4 +4 +1 || memcmp( doom3_inforesponse, ptr, sizeof(doom3_inforesponse)) != 0 ) { malformed_packet(server, "too short or invalid response"); return PKT_ERROR; } ptr += sizeof(doom3_inforesponse); if ( 5 == version ) { // TaskID ptr += 4; // osmask + ranked tail_size++; } challenge = swap_long_from_little(ptr); ptr += 4; protocolver = swap_long_from_little(ptr); ptr += 4; snprintf(tmp, sizeof(tmp), "%u.%u", protocolver >> 16, protocolver & 0xFFFF); debug(2, "challenge: 0x%08X, protocol: %s (0x%X)", challenge, tmp, protocolver); server->protocol_version = protocolver; add_rule( server, "protocol", tmp, NO_FLAGS ); if ( 5 == version ) { // Size Long size = swap_long_from_little(ptr); debug( 2, "Size = %d", size ); ptr += 4; } // Commented out until we have a better way to specify the expected version // This is due to prey demo requiring version 4 yet prey retail version 3 /* if( protocolver >> 16 != version ) { malformed_packet(server, "protocol version %u, expected %u", protocolver >> 16, version ); return PKT_ERROR; } */ while ( ptr < end ) { // server info: // name value pairs null seperated // empty name && value signifies the end of section char *key, *val; unsigned keylen, vallen; key = ptr; ptr = memchr(ptr, '\0', end-ptr); if ( !ptr ) { malformed_packet( server, "no rule key" ); return PKT_ERROR; } keylen = ptr - key; val = ++ptr; ptr = memchr(ptr, '\0', end-ptr); if ( !ptr ) { malformed_packet( server, "no rule value" ); return PKT_ERROR; } vallen = ptr - val; ++ptr; if( keylen == 0 && vallen == 0 ) { type = 1; break; // end } debug( 2, "key:%s=%s:", key, val); // Lets see what we've got if ( 0 == strcasecmp( key, "si_name" ) ) { server->server_name = strdup( val ); } else if( 0 == strcasecmp( key, "fs_game" ) ) { server->game = strdup( val ); } #if 0 else if( 0 == strcasecmp( key, "si_version" ) ) { // format: x // DOOM 1.0.1262.win-x86 Jul 8 2004 16:46:37 server->protocol_version = atoi( val+1 ); } #endif else if( 0 == strcasecmp( key, "si_map" ) ) { if ( 5 == version || 6 == version ) { // ET:QW reports maps/.entities // so we strip that here if it exists char *tmpp = strstr( val, ".entities" ); if ( NULL != tmpp ) { *tmpp = '\0'; } if ( 0 == strncmp( val, "maps/", 5 ) ) { val += 5; } } server->map_name = strdup( val ); } else if ( 0 == strcasecmp( key, "si_maxplayers" ) ) { server->max_players = atoi( val ); } else if ( 0 == strcasecmp( key, "ri_maxViewers" ) ) { char max[20]; sprintf( max, "%d", server->max_players ); add_rule( server, "si_maxplayers", max, NO_FLAGS ); server->max_players = atoi( val ); } else if ( 0 == strcasecmp( key, "ri_numViewers" ) ) { viewers = atoi( val ); tv = 1; } add_rule( server, key, val, NO_FLAGS ); } if ( type != 1 ) { // no more info should be player headers here as we // requested it malformed_packet( server, "player info missing" ); return PKT_ERROR; } // now each player details while( ptr < end - tail_size ) { struct player *player; char *val; unsigned char player_id = *ptr++; short ping = 0; unsigned rate = 0; if( ( 6 == version && MAX_WOLF_ASYNC_CLIENTS == player_id ) || MAX_DOOM3_ASYNC_CLIENTS == player_id ) { break; } debug( 2, "ID = %d\n", player_id ); // Note: id's are not steady if ( ptr + 7 > end ) // 2 ping + 4 rate + empty player name ('\0') { // run off the end and shouldnt have malformed_packet( server, "player info too short" ); return PKT_ERROR; } /* if ( 6 == version ) { // Playerid is broken in wolf its always 0 player_id = num_players; } */ player = add_player( server, player_id ); if( ! player ) { malformed_packet( server, "duplicate player id" ); return PKT_ERROR; } // doesnt support score so set a sensible default player->score = 0; player->frags = 0; // Ping ping = swap_short_from_little(ptr); player->ping = ping; ptr += 2; if ( 5 != version || 0xa0013 >= protocolver ) // No Rate in ETQW since v1.4 ( protocol v10.19 ) { // Rate rate = swap_long_from_little(ptr); { char buf[16]; snprintf(buf, sizeof(buf), "%u", rate); player_add_info(player, "rate", buf, NO_FLAGS); } ptr += 4; } if ( 5 == version && ( ( 0xd0009 == protocolver || 0xd000a == protocolver ) && 0 != num_players ) ) // v13.9 or v13.10 { // Fix the packet offset due to the single bit used for bot // which realigns at the byte boundary for the player name ptr++; } // Name val = ptr; ptr = memchr(ptr, '\0', end-ptr); if ( !ptr ) { malformed_packet( server, "player name not null terminated" ); return PKT_ERROR; } player->name = strdup( val ); ptr++; switch( version ) { case 2: // Quake 4 val = ptr; ptr = memchr(ptr, '\0', end-ptr); if ( !ptr ) { malformed_packet( server, "player clan not null terminated" ); return PKT_ERROR; } player->tribe_tag = strdup( val ); ptr++; debug( 2, "Player[%d] = %s, ping %hu, rate %u, id %hhu, clan %s", num_players, player->name, ping, rate, player_id, player->tribe_tag); break; case 5: // ETQW case 6: // Wolfenstien if ( 0xa0011 <= protocolver ) // clan tag since 10.17 { // clantag position ptr++; // clantag val = ptr; ptr = memchr(ptr, '\0', end-ptr); if ( !ptr ) { malformed_packet( server, "player clan not null terminated" ); return PKT_ERROR; } player->tribe_tag = strdup( val ); ptr++; } // Bot flag if ( 0xd0009 == protocolver || 0xd000a == protocolver ) // v13.9 or v13.10 { // Bot flag is a single bit so need to realign everything from here on in :( int i; unsigned char *tp = (unsigned char*)ptr; player->type_flag = (*tp)<<7; // alignment is reset at the end for( i = 0; i < 8 && tp < (unsigned char*)end; i++ ) { *tp = (*tp)>>1 | *(tp+1)<<7; tp++; } } else { player->type_flag = *ptr++; } if ( 0xa0011 <= protocolver ) // clan tag since 10.17 { debug( 2, "Player[%d] = %s, ping %hu, rate %u, id %hhu, bot %hu, clan %s", num_players, player->name, ping, rate, player_id, player->type_flag, player->tribe_tag); } else { debug( 2, "Player[%d] = %s, ping %hu, rate %u, id %hhu, bot %hu", num_players, player->name, ping, rate, player_id, player->type_flag ); } break; default: debug( 2, "Player[%d] = %s, ping %hu, rate %u, id %hhu", num_players, player->name, ping, rate, player_id ); } ++num_players; } if( end - ptr >= 4 ) { // OS Mask snprintf(tmp, sizeof(tmp), "0x%X", swap_long_from_little(ptr)); add_rule( server, "osmask", tmp, NO_FLAGS ); debug( 2, "osmask %s", tmp); ptr += 4; if ( 5 == version && end - ptr >= 1 ) { // Ranked flag snprintf( tmp, sizeof(tmp), "%hhu", *ptr++ ); add_rule( server, "ranked", tmp, NO_FLAGS ); if ( end - ptr >= 5 ) { // Time Left snprintf( tmp, sizeof(tmp), "%d", swap_long_from_little( ptr ) ); add_rule( server, "timeleft", tmp, NO_FLAGS ); ptr += 4; // Game State snprintf( tmp, sizeof(tmp), "%hhu", *ptr++ ); add_rule( server, "gamestate", tmp, NO_FLAGS ); if ( end - ptr >= 1 ) { // Server Type unsigned char servertype = *ptr++; snprintf( tmp, sizeof(tmp), "%hhu", servertype ); add_rule( server, "servertype", tmp, NO_FLAGS ); switch ( servertype ) { case 0: // Regular Server // Interested Clients snprintf( tmp, sizeof(tmp), "%hhu", *ptr++ ); add_rule( server, "interested_clients", tmp, NO_FLAGS ); break; case 1: // TV Server // Connected Clients snprintf( tmp, sizeof(tmp), "%d", swap_long_from_little( ptr ) ); ptr+=4; add_rule( server, "interested_clients", tmp, NO_FLAGS ); // Max Clients snprintf( tmp, sizeof(tmp), "%d", swap_long_from_little( ptr ) ); ptr+=4; add_rule( server, "interested_clients", tmp, NO_FLAGS ); break; default: // Unknown if ( show_errors ) { fprintf( stderr, "Unknown server type %d\n", servertype ); } } } } } } else { malformed_packet(server, "osmask missing"); } #if 0 if(end - ptr) { malformed_packet(server, "%ld byes left", end-ptr); } #endif if ( 0 == tv ) { debug( 2, "Num players = %d", num_players ); server->num_players = num_players; } else { server->num_players = viewers; } return DONE_FORCE; } query_status_t deal_with_doom3_packet( struct qserver *server, char *rawpkt, int pktlen) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 1 ); } query_status_t deal_with_quake4_packet( struct qserver *server, char *rawpkt, int pktlen) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 2 ); } query_status_t deal_with_prey_demo_packet( struct qserver *server, char *rawpkt, int pktlen ) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 4 ); } query_status_t deal_with_prey_packet( struct qserver *server, char *rawpkt, int pktlen ) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 3 ); } query_status_t deal_with_etqw_packet( struct qserver *server, char *rawpkt, int pktlen ) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 5 ); } query_status_t deal_with_wolf_packet( struct qserver *server, char *rawpkt, int pktlen ) { return _deal_with_doom3_packet( server, rawpkt, pktlen, 6 ); } qstat-2.15/LICENSE.txt0000644000175000017500000002130612420765614011352 00000000000000 The Artistic License 2.0 Copyright (c) 2000-2006, The Perl Foundation. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble This license establishes the terms under which a given free software Package may be copied, modified, distributed, and/or redistributed. The intent is that the Copyright Holder maintains some artistic control over the development of that Package while still keeping the Package available as open source and free software. You are always permitted to make arrangements wholly outside of this license directly with the Copyright Holder of a given Package. If the terms of this license do not permit the full use that you propose to make of the Package, you should contact the Copyright Holder and seek a different licensing arrangement. Definitions "Copyright Holder" means the individual(s) or organization(s) named in the copyright notice for the entire Package. "Contributor" means any party that has contributed code or other material to the Package, in accordance with the Copyright Holder's procedures. "You" and "your" means any person who would like to copy, distribute, or modify the Package. "Package" means the collection of files distributed by the Copyright Holder, and derivatives of that collection and/or of those files. A given Package may consist of either the Standard Version, or a Modified Version. "Distribute" means providing a copy of the Package or making it accessible to anyone else, or in the case of a company or organization, to others outside of your company or organization. "Distributor Fee" means any fee that you charge for Distributing this Package or providing support for this Package to another party. It does not mean licensing fees. "Standard Version" refers to the Package if it has not been modified, or has been modified only in ways explicitly requested by the Copyright Holder. "Modified Version" means the Package, if it has been changed, and such changes were not explicitly requested by the Copyright Holder. "Original License" means this Artistic License as Distributed with the Standard Version of the Package, in its current version or as it may be modified by The Perl Foundation in the future. "Source" form means the source code, documentation source, and configuration files for the Package. "Compiled" form means the compiled bytecode, object code, binary, or any other form resulting from mechanical transformation or translation of the Source form. Permission for Use and Modification Without Distribution (1) You are permitted to use the Standard Version and create and use Modified Versions for any purpose without restriction, provided that you do not Distribute the Modified Version. Permissions for Redistribution of the Standard Version (2) You may Distribute verbatim copies of the Source form of the Standard Version of this Package in any medium without restriction, either gratis or for a Distributor Fee, provided that you duplicate all of the original copyright notices and associated disclaimers. At your discretion, such verbatim copies may or may not include a Compiled form of the Package. (3) You may apply any bug fixes, portability changes, and other modifications made available from the Copyright Holder. The resulting Package will still be considered the Standard Version, and as such will be subject to the Original License. Distribution of Modified Versions of the Package as Source (4) You may Distribute your Modified Version as Source (either gratis or for a Distributor Fee, and with or without a Compiled form of the Modified Version) provided that you clearly document how it differs from the Standard Version, including, but not limited to, documenting any non-standard features, executables, or modules, and provided that you do at least ONE of the following: (a) make the Modified Version available to the Copyright Holder of the Standard Version, under the Original License, so that the Copyright Holder may include your modifications in the Standard Version. (b) ensure that installation of your Modified Version does not prevent the user installing or running the Standard Version. In addition, the Modified Version must bear a name that is different from the name of the Standard Version. (c) allow anyone who receives a copy of the Modified Version to make the Source form of the Modified Version available to others under (i) the Original License or (ii) a license that permits the licensee to freely copy, modify and redistribute the Modified Version using the same licensing terms that apply to the copy that the licensee received, and requires that the Source form of the Modified Version, and of any works derived from it, be made freely available in that license fees are prohibited but Distributor Fees are allowed. Distribution of Compiled Forms of the Standard Version or Modified Versions without the Source (5) You may Distribute Compiled forms of the Standard Version without the Source, provided that you include complete instructions on how to get the Source of the Standard Version. Such instructions must be valid at the time of your distribution. If these instructions, at any time while you are carrying out such distribution, become invalid, you must provide new instructions on demand or cease further distribution. If you provide valid instructions or cease distribution within thirty days after you become aware that the instructions are invalid, then you do not forfeit any of your rights under this license. (6) You may Distribute a Modified Version in Compiled form without the Source, provided that you comply with Section 4 with respect to the Source of the Modified Version. Aggregating or Linking the Package (7) You may aggregate the Package (either the Standard Version or Modified Version) with other packages and Distribute the resulting aggregation provided that you do not charge a licensing fee for the Package. Distributor Fees are permitted, and licensing fees for other components in the aggregation are permitted. The terms of this license apply to the use and Distribution of the Standard or Modified Versions as included in the aggregation. (8) You are permitted to link Modified and Standard Versions with other works, to embed the Package in a larger work of your own, or to build stand-alone binary or bytecode versions of applications that include the Package, and Distribute the result without restriction, provided the result does not expose a direct interface to the Package. Items That are Not Considered Part of a Modified Version (9) Works (including, but not limited to, modules and scripts) that merely extend or make use of the Package, do not, by themselves, cause the Package to be a Modified Version. In addition, such works are not considered parts of the Package itself, and are not subject to the terms of this license. General Provisions (10) Any use, modification, and distribution of the Standard or Modified Versions is governed by this Artistic License. By using, modifying or distributing the Package, you accept this license. Do not use, modify, or distribute the Package, if you do not accept this license. (11) If your Modified Version has been derived from a Modified Version made by someone other than you, you are nevertheless required to ensure that your Modified Version complies with the requirements of this license. (12) This license does not grant you the right to use any trademark, service mark, tradename, or logo of the Copyright Holder. (13) This license includes the non-exclusive, worldwide, free-of-charge patent license to make, have made, use, offer to sell, sell, import and otherwise transfer the Package with respect to any patent claims licensable by the Copyright Holder that are necessarily infringed by the Package. If you institute patent litigation (including a cross-claim or counterclaim) against any party alleging that the Package constitutes direct or contributory patent infringement, then this Artistic License to you shall terminate on the date that such litigation is filed. (14) Disclaimer of Warranty: THE PACKAGE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT ARE DISCLAIMED TO THE EXTENT PERMITTED BY YOUR LOCAL LAW. UNLESS REQUIRED BY LAW, NO COPYRIGHT HOLDER OR CONTRIBUTOR WILL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THE PACKAGE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. qstat-2.15/hcache.c0000644000175000017500000002367312420765614011117 00000000000000/* * qstat * by Steve Jankowski * steve@activesw.com * http://www.activesw.com/people/steve/qstat.html * * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk) * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net) * Thanks to Scott MacFiggen for the quicksort code (smf@activesw.com) * * Inspired by QuakePing by Len Norton * * Copyright 1996,1997,1998,1999 by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #include #include #include #include #include "qstat.h" #include "debug.h" #ifndef _WIN32 #include #include #include #include #include #endif #ifdef _WIN32 #include #endif #ifdef __hpux #define STATIC static #else #define STATIC #endif #ifndef INADDR_NONE #define INADDR_NONE ~0 #endif typedef struct _cache_entry { unsigned long ipaddr; char *hostname[5]; } cache_entry; static cache_entry *hcache; static int n_entry; static int max_entry; static char *last_filename; static int n_changes; static void write_file(FILE *file); static cache_entry * init_entry( unsigned long ipaddr, char *hostname, cache_entry *known); static cache_entry * find_entry( unsigned long ipaddr); static void free_entry( cache_entry *entry); static cache_entry * validate_entry( cache_entry *entry); static cache_entry * find_host_entry( char *hostname); static void add_hostname( cache_entry *entry, const char *hostname); int hcache_open( char *filename, int update) { FILE *file; char line[500], ipstr[500], hostname[500]; char *l; int line_no, end; unsigned long ip1, ip2, ip3, ip4, ipaddr; cache_entry *entry; file= fopen( filename, update?"r+":"r"); if ( file == NULL) { if ( errno == ENOENT) { debug(2, "Creating new host cache \"%s\"\n", filename); last_filename= filename; return 0; } perror( filename); return -1; } last_filename= filename; for ( line_no= 1; fgets( line, sizeof(line), file) != NULL; line_no++) { if ( strlen(line) < 2) continue; if ( line[strlen(line)-1] != '\n') { printf( "%d: line too long\n", line_no); continue; } l= line; while ( isspace( (unsigned char)*l)) l++; if ( *l == '#' || *l == '\0') continue; if ( sscanf( l, "%s%n", ipstr, &end) != 1) { printf( "%d: parse error\n", line_no); continue; } if ( sscanf( ipstr, "%lu.%lu.%lu.%lu", &ip1, &ip2, &ip3, &ip4) != 4) { init_entry( 0, ipstr, NULL); continue; } if ( (ip1&0xffffff00) || (ip2&0xffffff00) || (ip3&0xffffff00) || (ip4&0xffffff00)) { printf( "%d: invalid IP address \"%s\"\n", line_no, ipstr); continue; } ipaddr= (ip1<<24) | (ip2<<16) | (ip3<<8) | ip4; entry= init_entry( ipaddr, NULL, NULL); while ( 1) { l+= end; while ( isspace( (unsigned char)*l)) l++; if ( *l == '#' || *l == '\0') break; hostname[0]= '\0'; if ( sscanf( l, "%s%n", hostname, &end) != 1) { printf( "%d: parse error\n", line_no); continue; } init_entry( ipaddr, hostname, entry); } } fclose(file); return 0; } STATIC cache_entry * init_entry( unsigned long ipaddr, char *hostname, cache_entry *known) { cache_entry *entry; int e= 0, h; if ( n_entry == max_entry) { if ( max_entry == 0) { max_entry= 50; hcache= (cache_entry*) malloc(sizeof(cache_entry) * max_entry * 2); } else { hcache= (cache_entry*) realloc( hcache, sizeof(cache_entry) * max_entry * 2); } memset( hcache+n_entry, 0, sizeof(cache_entry) * max_entry * (n_entry==0?2:1)); max_entry*= 2; } if ( ipaddr == 0) { entry= find_host_entry( hostname); if ( entry == NULL) { hcache[n_entry].hostname[0]= strdup( hostname); return &hcache[n_entry++]; } return entry; } if ( known != NULL) entry= known; else { for ( e= 0; e < n_entry; e++) if ( hcache[e].ipaddr == ipaddr) break; entry= &hcache[e]; entry->ipaddr= ipaddr; } if ( hostname && hostname[0] != '\0') { for ( h= 0; h < 5; h++) if ( entry->hostname[h] == NULL) { entry->hostname[h]= strdup( hostname); break; } } if ( e == n_entry) n_entry++; return entry; } STATIC cache_entry * find_host_entry( char *hostname) { cache_entry *entry= &hcache[0]; char **ehost; int e, h; char first= *hostname; for ( e= 0; e < n_entry; e++, entry++) { ehost= &entry->hostname[0]; for ( h= 0; h < 5; h++, ehost++) if ( *ehost && first == **ehost && strcmp( hostname, *ehost) == 0) return entry; } return NULL; } void hcache_write_file( char *filename) { FILE *file; if ( filename != NULL) file= fopen( filename, "w"); else file= stdout; if ( file == NULL) { perror( filename); return; } write_file( file); } void hcache_update_file() { FILE *file; if ( last_filename == NULL || n_changes == 0) return; file= fopen( last_filename, "w"); if ( file == NULL) { perror( last_filename); return; } write_file( file); } STATIC void write_file( FILE *file) { int e, h; for ( e= 0; e < n_entry; e++) { unsigned long ipaddr= hcache[e].ipaddr; if ( ipaddr == 0) continue; fprintf( file, "%lu.%lu.%lu.%lu", (ipaddr&0xff000000)>>24, (ipaddr&0xff0000)>>16, (ipaddr&0xff00)>>8, ipaddr&0xff); if ( hcache[e].hostname[0]) { for ( h= 0; h < 5; h++) if ( hcache[e].hostname[h] != NULL) fprintf( file, "%c%s", h?' ':'\t', hcache[e].hostname[h]); } fprintf( file, "\n"); } fclose( file); } void hcache_invalidate() { int e; for ( e= 0; e < n_entry; e++) if ( hcache[e].ipaddr != 0) memset( & hcache[e].hostname[0], 0, sizeof( hcache[e].hostname)); } void hcache_validate() { int e; char **alias; struct hostent *ent; unsigned long ipaddr; cache_entry *entry; for ( e= 0; e < n_entry; e++) { fprintf( stderr, "\r%d / %d validating ", e, n_entry); if ( hcache[e].ipaddr != 0) { ipaddr= hcache[e].ipaddr; fprintf( stderr, "%lu.%lu.%lu.%lu", (ipaddr&0xff000000)>>24, (ipaddr&0xff0000)>>16, (ipaddr&0xff00)>>8, ipaddr&0xff); ipaddr= htonl( ipaddr); ent= gethostbyaddr( (char*)&ipaddr, sizeof(unsigned long), AF_INET); } else if ( hcache[e].hostname[0] != NULL) { fprintf( stderr, "%s", hcache[e].hostname[0]); ent= gethostbyname( hcache[e].hostname[0]); if ( ent != NULL) { memcpy( &ipaddr, ent->h_addr_list[0], sizeof(ipaddr)); ipaddr= ntohl( ipaddr); if ( (entry= find_entry( ipaddr)) != NULL) { add_hostname( entry, hcache[e].hostname[0]); free_entry( &hcache[e]); } else hcache[e].ipaddr= ipaddr; } } else continue; if ( ent == NULL) continue; if ( ent->h_name && ent->h_name[0] != '\0') add_hostname( &hcache[e], ent->h_name); printf( "h_name %s\n", ent->h_name?ent->h_name:"NULL"); alias= ent->h_aliases; while ( *alias) { add_hostname( &hcache[e], *alias); printf( "h_aliases %s\n", *alias); alias++; } } } STATIC cache_entry * validate_entry( cache_entry *entry) { struct hostent *ent; char **alias; cache_entry *tmp; unsigned long ipaddr; if ( entry->ipaddr != 0) { ipaddr= htonl( entry->ipaddr); /* fprintf( stderr, "%u.%u.%u.%u", (ipaddr&0xff000000)>>24, (ipaddr&0xff0000)>>16, (ipaddr&0xff00)>>8, ipaddr&0xff); */ ent= gethostbyaddr( (char*)&ipaddr, sizeof(unsigned long), AF_INET); } else if ( entry->hostname[0] != NULL) { /* fprintf( stderr, "%s", entry->hostname[0]); */ ent= gethostbyname( entry->hostname[0]); if ( ent != NULL) { memcpy( &ipaddr, ent->h_addr_list[0], sizeof(ipaddr)); ipaddr= ntohl( ipaddr); if ( (tmp= find_entry( ipaddr)) != NULL) { add_hostname( tmp, entry->hostname[0]); free_entry( entry); entry= tmp; } else entry->ipaddr= ipaddr; } } else return NULL; if ( ent == NULL) return NULL; if ( ent->h_name && ent->h_name[0] != '\0') add_hostname( entry, ent->h_name); alias= ent->h_aliases; while ( *alias) { add_hostname( entry, *alias); alias++; } return entry; } unsigned long hcache_lookup_hostname( char *hostname) { cache_entry *entry; int e, h; debug(1, "looking up %s\n", hostname); for ( e= 0; e < n_entry; e++) { for ( h= 0; h < 5; h++) { if ( hcache[e].hostname[h] && strcmp( hostname, hcache[e].hostname[h]) == 0) return hcache[e].ipaddr; } } entry= init_entry( 0, hostname, NULL); if ( entry->ipaddr == 0) { debug(2, "validating %s\n", hostname); entry= validate_entry( entry); n_changes++; } if ( entry != NULL && entry->ipaddr) { debug(2, "returning %lx\n", entry->ipaddr); return entry->ipaddr; } return INADDR_NONE; } char * hcache_lookup_ipaddr( unsigned long ipaddr) { cache_entry *entry; int e; for ( e= 0; e < n_entry; e++) if ( hcache[e].ipaddr == ipaddr) return hcache[e].hostname[0]; entry= init_entry( ipaddr, 0, NULL); debug(1, "validating %lx\n", ipaddr); validate_entry( entry); n_changes++; return entry ? entry->hostname[0] : NULL; } STATIC cache_entry * find_entry( unsigned long ipaddr) { int e; for ( e= 0; e < n_entry; e++) if ( hcache[e].ipaddr == ipaddr) return &hcache[e]; return NULL; } STATIC void free_entry( cache_entry *entry) { int h; for ( h= 0; h < 5; h++) if ( entry->hostname[h] != NULL) free( entry->hostname[h]); memset( entry, 0, sizeof(*entry)); } STATIC void add_hostname( cache_entry *entry, const char *hostname) { int h; for ( h= 0; h < 5; h++) { if ( entry->hostname[h] == NULL) break; if ( strcmp( entry->hostname[h], hostname) == 0) return; } if ( h < 5) entry->hostname[h]= strdup( hostname); } /* main(int argc, char *argv[]) { hcache_open( argv[1], 0); hcache_write(NULL); hcache_invalidate(); printf( "invalidate\n"); hcache_write(NULL); hcache_validate(); printf( "validate\n"); hcache_write( "/tmp/qhcache.out"); } */ qstat-2.15/tee.c0000644000175000017500000000454612420765614010457 00000000000000/* * qstat * by Steve Jankowski * * Teeworlds protocol * Copyright 2008 ? Emiliano Leporati * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" char tee_serverinfo[8] = { '\xFF', '\xFF', '\xFF', '\xFF', 'i', 'n', 'f', 'o' }; query_status_t send_tee_request_packet( struct qserver *server ) { return send_packet( server, server->type->status_packet, server->type->status_len ); } query_status_t deal_with_tee_packet( struct qserver *server, char *rawpkt, int pktlen ) { // skip unimplemented ack, crc, etc char *pkt = rawpkt + 6; char *tok = NULL, *version = NULL; int i; struct player* player; server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); if (0 == memcmp( pkt, tee_serverinfo, 8)) { pkt += 8; // version version = strdup(pkt); pkt += strlen(pkt) + 1; // server name server->server_name = strdup(pkt); pkt += strlen(pkt) + 1; // map name server->map_name = strdup(pkt); pkt += strlen(pkt) + 1; // game type switch(atoi(pkt)) { case 0: add_rule( server, server->type->game_rule, "dm", NO_FLAGS); break; case 1: add_rule( server, server->type->game_rule, "tdm", NO_FLAGS); break; case 2: add_rule( server, server->type->game_rule, "ctf", NO_FLAGS); break; default: add_rule( server, server->type->game_rule, "unknown", NO_FLAGS); break; } pkt += strlen(pkt) + 1; pkt += strlen(pkt) + 1; pkt += strlen(pkt) + 1; // num players server->num_players = atoi(pkt); pkt += strlen(pkt) + 1; // max players server->max_players = atoi(pkt); pkt += strlen(pkt) + 1; // players for(i = 0; i < server->num_players; i++) { player = add_player( server, i ); player->name = strdup(pkt); pkt += strlen(pkt) + 1; player->score = atoi(pkt); pkt += strlen(pkt) + 1; } // version reprise server->protocol_version = 0; if (NULL == (tok = strtok(version, "."))) return -1; server->protocol_version |= (atoi(tok) & 0x000F) << 12; if (NULL == (tok = strtok(NULL, "."))) return -1; server->protocol_version |= (atoi(tok) & 0x000F) << 8; if (NULL == (tok = strtok(NULL, "."))) return -1; server->protocol_version |= (atoi(tok) & 0x00FF); free(version); return DONE_FORCE; } // unknown packet type return PKT_ERROR; } qstat-2.15/wic.c0000644000175000017500000001077212420765614010462 00000000000000/* * qstat * by Steve Jankowski * * World in Conflict Protocol * Copyright 2007 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" query_status_t send_wic_request_packet( struct qserver *server ) { char buf[256]; int serverport = get_param_i_value( server, "port", 0 ); char *password = get_param_value( server, "password", "N/A" ); change_server_port( server, serverport, 1 ); if ( get_player_info ) { server->flags |= TF_PLAYER_QUERY|TF_RULES_QUERY; sprintf( buf, "%s\x0d\x0a/listsettings\x0d\x0a/listplayers\x0d\x0a/exit\x0d\x0a", password ); server->saved_data.pkt_index = 2; } else { server->flags |= TF_STATUS_QUERY; sprintf( buf, "%s\x0d\x0a/listsettings\x0d\x0a/exit\x0d\x0a", password ); server->saved_data.pkt_index = 1; } return send_packet( server, buf, strlen( buf ) ); } query_status_t deal_with_wic_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *end, *team = NULL; int mode = server->n_servers, slot, score; char name[256], role[256]; debug( 2, "processing n_requests %d, retry1 %d, n_retries %d, delta %d", server->n_requests, server->retry1, n_retries, time_delta( &packet_recv_time, &server->packet_time1 ) ); server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); server->n_requests++; if ( 0 == pktlen ) { // Invalid password return REQ_ERROR; } gettimeofday( &server->packet_time1, NULL); rawpkt[pktlen]= '\0'; end = &rawpkt[pktlen]; s = rawpkt; while ( NULL != s ) { int len = strlen( s ); *(s + len - 2) = '\0'; // strip off \x0D\x0A debug( 2, "Line[%d]: %s", mode, s ); if ( 0 == mode ) { // Settings // TODO: make parse safe if ( 0 == strncmp( s, "Settings: ", 9 ) ) { // Server Rule char *key = s + 10; char *value = strchr( key, ' ' ); *value = '\0'; value++; debug( 2, "key: '%s' = '%s'", key, value ); if ( 0 == strcmp( "myGameName", key ) ) { server->server_name = strdup( value ); } else if ( 0 == strcmp( "myMapFilename", key ) ) { server->map_name = strdup( value ); } else if ( 0 == strcmp( "myMaxPlayers", key ) ) { server->max_players = atoi( value ); } else if ( 0 == strcmp( "myCurrentNumberOfPlayers", key ) ) { server->num_players = atoi( value); } else { add_rule( server, key, value, NO_FLAGS ); } } else if ( 0 == strcmp( "Listing players", s ) ) { // end of rules request server->saved_data.pkt_index--; mode++; } else if ( 0 == strcmp( "Exit confirmed.", s ) ) { server->n_servers = mode; return DONE_FORCE; } } else if ( 1 == mode ) { // Player info if ( 0 == strncmp( s, "Team: ", 6 ) ) { team = s + 6; debug( 2, "Team: %s", team ); } else if ( 4 == sscanf( s, "Slot: %d Role: %s Score: %d Name: %255[^\x0d\x0a]", &slot, role, &score, name ) ) { // Player info struct player *player = add_player( server, server->n_player_info ); if ( NULL != player ) { player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->name = strdup( name ); player->score = score; player->team_name = team; player->tribe_tag = strdup( role ); // Indicate if its a bot player->type_flag = ( 0 == strcmp( name, "Computer: Balanced" ) ) ? 1 : 0; } debug( 2, "player %d, role %s, score %d, name %s", slot, role, score, name ); } else if ( 3 == sscanf( s, "Slot: %d Role: Score: %d Name: %255[^\x0d\x0a]", &slot, &score, name ) ) { // Player info struct player *player = add_player( server, server->n_player_info ); if ( NULL != player ) { player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->name = strdup( name ); player->score = score; player->team_name = team; // Indicate if its a bot player->type_flag = ( 0 == strcmp( name, "Computer: Balanced" ) ) ? 1 : 0; } debug( 2, "player %d, score %d, name %s", slot, score, name ); } else if ( 0 == strcmp( "Exit confirmed.", s ) ) { server->n_servers = mode; return DONE_FORCE; } } s += len; if ( s + 1 < end ) { s++; // next line } else { s = NULL; } } server->n_servers = mode; if ( 0 == server->saved_data.pkt_index ) { server->map_name = strdup( "N/A" ); return DONE_FORCE; } return INPROGRESS; } qstat-2.15/fl.c0000644000175000017500000002536112420765615010302 00000000000000/* * qstat * by Steve Jankowski * * Frontlines-Fuel of War protocol * Copyright 2008 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" #define FL_GETCHALLENGE "\xFF\xFF\xFF\xFF\x57" #define FL_CHALLENGERESPONSE 0x41 #define FL_INFO "\xFF\xFF\xFF\xFF\x46LSQ" #define FL_INFORESPONSE 0x49 #define FL_PLAYER "\xFF\xFF\xFF\xFF\x55" #define FL_PLAYERRESPONSE 0x44 #define FL_RULES "\xFF\xFF\xFF\xFF\x56" #define FL_RULESRESPONSE 0x45 struct fl_status { unsigned sent_challenge : 1; unsigned have_challenge : 1; unsigned sent_info : 1; unsigned have_info : 1; unsigned sent_player : 1; unsigned have_player : 1; unsigned sent_rules : 1; unsigned have_rules : 1; unsigned challenge; unsigned char type; }; query_status_t send_fl_request_packet(struct qserver *server) { struct fl_status* status = (struct fl_status*)server->master_query_tag; if( SOCKET_ERROR == qserver_send_initial(server, FL_INFO, sizeof(FL_INFO) - 1) ) { return SOCKET_ERROR; } status->sent_info = 1; status->type = 0; return INPROGRESS; } query_status_t send_fl_rule_request_packet(struct qserver *server) { struct fl_status* status = (struct fl_status*)server->master_query_tag; if ( 1 >= status->type ) { // Not supported return PKT_ERROR; } if(!get_server_rules && !get_player_info) { return DONE_FORCE; } do { if(!status->have_challenge) { debug(3, "sending challenge"); if( SOCKET_ERROR == qserver_send_initial(server, FL_GETCHALLENGE, sizeof(FL_GETCHALLENGE)-1) ) { return SOCKET_ERROR; } status->sent_challenge = 1; break; } else if(get_server_rules && !status->have_rules) { char buf[sizeof(FL_RULES)-1+4] = FL_RULES; memcpy(buf+sizeof(FL_RULES)-1, &status->challenge, 4); debug(3, "sending rule query"); if( SOCKET_ERROR == qserver_send_initial(server, buf, sizeof(buf)) ) { return SOCKET_ERROR; } status->sent_rules = 1; break; } else if(get_player_info && !status->have_player) { char buf[sizeof(FL_PLAYER)-1+4] = FL_PLAYER; memcpy(buf+sizeof(FL_PLAYER)-1, &status->challenge, 4); debug(3, "sending player query"); if( SOCKET_ERROR == qserver_send_initial(server, buf, sizeof(buf)) ) { return SOCKET_ERROR; } status->sent_player = 1; break; } else { debug(3, "timeout"); // we are probably called due to timeout, restart. status->have_challenge = 0; status->have_rules = 0; } } while(1); return INPROGRESS; } 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; } // vim: sw=4 ts=4 noet qstat-2.15/a2s.h0000644000175000017500000000073212420765615010366 00000000000000/* * qstat * by Steve Jankowski * * New Half-Life2 query protocol * Copyright 2005 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_A2S_H #define QSTAT_A2S_H #include "qserver.h" query_status_t send_a2s_request_packet(struct qserver *server); query_status_t send_a2s_rule_request_packet(struct qserver *server); query_status_t deal_with_a2s_packet(struct qserver *server, char *rawpkt, int pktlen); #endif qstat-2.15/config.h0000644000175000017500000000047212420765614011146 00000000000000/* * config.h * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Copyright 1996,1997,1998,1999 by Steve Jankowski */ #include "qstat.h" int qsc_load_default_config_files(); int qsc_load_config_file(char const* filename); server_type ** qsc_get_config_server_types( int *n_config_types); qstat-2.15/config.sub0000755000175000017500000010577512420766264011531 00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-09-11' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # Please send patches with a ChangeLog entry to config-patches@gnu.org. # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. # If it is invalid, we print an error message on stderr and exit with code 1. # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases # that are meaningful with *any* GNU software. # Each package is responsible for reporting which valid configurations # it does not support. The user should be able to distinguish # a failure to support a valid configuration from a meaningless # configuration. # The goal of this file is to map all the various variations of a given # machine specification into a single specification in the form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ knetbsd*-gnu* | netbsd*-gnu* | \ kopensolaris*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; android-linux) os=-linux-android basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### Let's recognize common machines as not being operating systems so ### that things like config.sub decstation-3100 work. We also ### recognize some manufacturers as not being operating systems, so we ### can provide default operating systems below. case $os in -sun*os*) # Prevent following clause from handling this invalid input. ;; -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ -apple | -axis | -knuth | -cray | -microblaze*) os= basic_machine=$1 ;; -bluegene*) os=-cnk ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*178) os=-lynxos178 ;; -lynx*5) os=-lynxos5 ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; esac # Decode aliases for certain CPU-COMPANY combinations. case $basic_machine in # Recognize the basic CPU types without company name. # Some are omitted here because they have special meanings below. 1750a | 580 \ | a29k \ | aarch64 | aarch64_be \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ | epiphany \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | k1om \ | le32 | le64 \ | lm32 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64octeon | mips64octeonel \ | mips64orion | mips64orionel \ | mips64r5900 | mips64r5900el \ | mips64vr | mips64vrel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | moxie \ | mt \ | msp430 \ | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ | riscv32 | riscv64 \ | rl78 | rx \ | score \ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu \ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) basic_machine=$basic_machine-unknown ;; c54x) basic_machine=tic54x-unknown ;; c55x) basic_machine=tic55x-unknown ;; c6x) basic_machine=tic6x-unknown ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; strongarm | thumb | xscale) basic_machine=arm-unknown ;; xgate) basic_machine=$basic_machine-unknown os=-none ;; xscaleeb) basic_machine=armeb-unknown ;; xscaleel) basic_machine=armel-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # Object if more than one company name word. *-*-*) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; # Recognize the basic CPU types with company name. 580-* \ | a29k-* \ | aarch64-* | aarch64_be-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | hexagon-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | k1om-* \ | le32-* | le64-* \ | lm32-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ | microblaze-* | microblazeel-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64octeon-* | mips64octeonel-* \ | mips64orion-* | mips64orionel-* \ | mips64r5900-* | mips64r5900el-* \ | mips64vr-* | mips64vrel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nds32-* | nds32le-* | nds32be-* \ | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ | tron-* \ | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ | ymp-* \ | z8k-* | z80-*) ;; # Recognize the basic CPU types without company name, with glob match. xtensa*) basic_machine=$basic_machine-unknown ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aros) basic_machine=i386-pc os=-aros ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; blackfin) basic_machine=bfin-unknown os=-linux ;; blackfin-*) basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; bluegene*) basic_machine=powerpc-ibm os=-cnk ;; c54x-*) basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c55x-*) basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c6x-*) basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` ;; c90) basic_machine=c90-cray os=-unicos ;; cegcc) basic_machine=arm-unknown os=-cegcc ;; convex-c1) basic_machine=c1-convex os=-bsd ;; convex-c2) basic_machine=c2-convex os=-bsd ;; convex-c32) basic_machine=c32-convex os=-bsd ;; convex-c34) basic_machine=c34-convex os=-bsd ;; convex-c38) basic_machine=c38-convex os=-bsd ;; cray | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16 | cr16-*) basic_machine=cr16-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; dicos) basic_machine=i686-pc os=-dicos ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; dpx20 | dpx20-*) basic_machine=rs6000-bull os=-bosx ;; dpx2* | dpx2*-bull) basic_machine=m68k-bull os=-sysv3 ;; ebmon29k) basic_machine=a29k-amd os=-ebmon ;; elxsi) basic_machine=elxsi-elxsi os=-bsd ;; encore | umax | mmax) basic_machine=ns32k-encore ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-hitachi os=-hms ;; harris) basic_machine=m88k-harris os=-sysv3 ;; hp300-*) basic_machine=m68k-hp ;; hp300bsd) basic_machine=m68k-hp os=-bsd ;; hp300hpux) basic_machine=m68k-hp os=-hpux ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; iris | iris4d) basic_machine=mips-sgi case $os in -irix*) ;; *) os=-irix4 ;; esac ;; isi68 | isi) basic_machine=m68k-isi os=-sysv ;; m68knommu) basic_machine=m68k-unknown os=-linux ;; m68knommu-*) basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; m88k-omron*) basic_machine=m88k-omron ;; magnum | m3230) basic_machine=mips-mips os=-sysv ;; merlin) basic_machine=ns32k-utek os=-sysv ;; microblaze*) basic_machine=microblaze-xilinx ;; mingw64) basic_machine=x86_64-pc os=-mingw64 ;; mingw32) basic_machine=i686-pc os=-mingw32 ;; mingw32ce) basic_machine=arm-unknown os=-mingw32ce ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; moxiebox) basic_machine=moxie-unknown os=-moxiebox ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; msys) basic_machine=i686-pc os=-msys ;; mvs) basic_machine=i370-ibm os=-mvs ;; nacl) basic_machine=le32-unknown os=-nacl ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; news | news700 | news800 | news900) basic_machine=m68k-sony os=-newsos ;; news1000) basic_machine=m68030-sony os=-newsos ;; news-3600 | risc-news) basic_machine=mips-sony os=-newsos ;; necv70) basic_machine=v70-nec os=-sysv ;; next | m*-next ) basic_machine=m68k-next case $os in -nextstep* ) ;; -ns2*) os=-nextstep2 ;; *) os=-nextstep3 ;; esac ;; nh3000) basic_machine=m68k-harris os=-cxux ;; nh[45]000) basic_machine=m88k-harris os=-cxux ;; nindy960) basic_machine=i960-intel os=-nindy ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; neo-tandem) basic_machine=neo-tandem ;; nse-tandem) basic_machine=nse-tandem ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; pa-hitachi) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; paragon) basic_machine=i860-intel os=-osf ;; parisc) basic_machine=hppa-unknown os=-linux ;; parisc-*) basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` os=-linux ;; pbd) basic_machine=sparc-tti ;; pbb) basic_machine=m68k-tti ;; pc532 | pc532-*) basic_machine=ns32k-pc532 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-ibm ;; ppc | ppcbe) basic_machine=powerpc-unknown ;; ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppcle | powerpclittle | ppc-le | powerpc-little) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos | rdos64) basic_machine=x86_64-pc os=-rdos ;; rdos32) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; strongarm-* | thumb-*) basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'` ;; sun2) basic_machine=m68000-sun ;; sun2os3) basic_machine=m68000-sun os=-sunos3 ;; sun2os4) basic_machine=m68000-sun os=-sunos4 ;; sun3os3) basic_machine=m68k-sun os=-sunos3 ;; sun3os4) basic_machine=m68k-sun os=-sunos4 ;; sun4os3) basic_machine=sparc-sun os=-sunos3 ;; sun4os4) basic_machine=sparc-sun os=-sunos4 ;; sun4sol2) basic_machine=sparc-sun os=-solaris2 ;; sun3 | sun3-*) basic_machine=m68k-sun ;; sun4) basic_machine=sparc-sun ;; sun386 | sun386i | roadrunner) basic_machine=i386-sun ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tile*) basic_machine=$basic_machine-unknown os=-linux-gnu ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; xscale-* | xscalee[bl]-*) basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'` ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; z80-*-coff) basic_machine=z80-unknown os=-sim ;; none) basic_machine=none-none os=-none ;; # Here we handle the default manufacturer of certain CPU types. It is in # some cases the only manufacturer, in others, it is the most popular. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 exit 1 ;; esac # Here we canonicalize certain aliases for manufacturers. case $basic_machine in *-digital*) basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` ;; *-commodore*) basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` ;; *) ;; esac # Decode manufacturer-specific aliases for certain operating systems. if [ x"$os" != x"" ] then case $os in # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -auroraux) os=-auroraux ;; -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # First accept the basic system types. # The portable systems comes first. # Each alternative MUST END IN A *, to match a version number. # -sysv* is not here because it comes later, after sysvr4. -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* | -aros* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -bitrig* | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -zvmoe) os=-zvmoe ;; -dicos*) os=-dicos ;; -nacl*) ;; -none) ;; *) # Get rid of the `-' at the beginning of $os. os=`echo $os | sed 's/[^-]*-//'` echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 exit 1 ;; esac else # Here we handle the default operating systems that come with various machines. # The value should be what the vendor currently ships out the door with their # machine or put another way, the most popular os provided with the machine. # Note that if you're going to try to match "-MANUFACTURER" here (say, # "-sun"), then you have to tell the case statement up towards the top # that MANUFACTURER isn't an operating system. Otherwise, code above # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. case $basic_machine in score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; c8051-*) os=-elf ;; hexagon-*) os=-elf ;; tic54x-*) os=-coff ;; tic55x-*) os=-coff ;; tic6x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; pdp11-*) os=-none ;; *-dec | vax-*) os=-ultrix4.2 ;; m68*-apollo) os=-domain ;; i386-sun) os=-sunos4.0.2 ;; m68000-sun) os=-sunos3 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-sequent) os=-ptx ;; *-crds) os=-unos ;; *-ns) os=-genix ;; i370-*) os=-mvs ;; *-next) os=-nextstep3 ;; *-gould) os=-sysv ;; *-highlevel) os=-bsd ;; *-encore) os=-bsd ;; *-sgi) os=-irix ;; *-siemens) os=-sysv4 ;; *-masscomp) os=-rtu ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) os=-none ;; esac fi # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. vendor=unknown case $basic_machine in *-unknown) case $os in -riscix*) vendor=acorn ;; -sunos*) vendor=sun ;; -cnk*|-aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qstat-2.15/ts3.c0000644000175000017500000002556612420765614010420 00000000000000/* * qstat * by Steve Jankowski * * Teamspeak 3 query protocol * Copyright 2009 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "utils.h" #include "packet_manip.h" char *decode_ts3_val( char *val ) { val = str_replace( val, "\\\\", "\\" ); val = str_replace( val, "\\/", "/" ); val = str_replace( val, "\\s", " " ); val = str_replace( val, "\\p", "|" ); val = str_replace( val, "\\a", "\007" ); val = str_replace( val, "\\b", "\010" ); val = str_replace( val, "\\f", "\014" ); val = str_replace( val, "\\n", "\012" ); val = str_replace( val, "\\r", "\015" ); val = str_replace( val, "\\t", "\011" ); return str_replace( val, "\\v", "\013" ); } int all_ts3_servers( struct qserver *server ) { return ( 1 == get_param_i_value( server, "allservers", 0 ) ) ? 1 : 0; } query_status_t send_ts3_all_servers_packet( struct qserver *server ) { char buf[256], *password, *username; switch ( server->challenge ) { case 0: // Not seen a challenge yet, wait for it server->n_servers = 999; return INPROGRESS; case 1: 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: // NOTE: we currently don't support player info server->flags |= TF_STATUS_QUERY; server->n_servers = 3; sprintf( buf, "serverlist\015\012" ); break; case 3: sprintf( buf, "quit\015\012" ); break; case 4: return DONE_FORCE; } server->saved_data.pkt_max = -1; return send_packet( server, buf, strlen( buf ) ); } 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", password, username ); 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 send_ts3_request_packet( struct qserver *server ) { debug( 3, "send_ts3_request_packet: state = %ld", server->challenge ); return ( all_ts3_servers( server ) ) ? send_ts3_all_servers_packet( server ) : send_ts3_single_server_packet( server ); } int valid_ts3_response( struct qserver *server, char *rawpkt, int pktlen ) { char *end = &rawpkt[pktlen-1]; char *s = rawpkt; if ( 0 == strncmp( "TS3", s, 3 ) ) { // Challenge server->master_pkt_len = 3; return 1; } while ( NULL != s ) { // use response if ( 0 == strncmp( "error", s, 5 ) ) { // end cmd response if ( 0 == strncmp( "error id=0", s, 9 ) ) { server->master_pkt_len = s - rawpkt + 9; return 1; } else { // bad server server->server_name = DOWN; server->saved_data.pkt_index = 0; return DONE_FORCE; } } s = strstr( s, "\012\015" ); if ( NULL != s ) { s = ( s + 2 < end ) ? s + 2 : NULL; } } return 0; } query_status_t deal_with_ts3_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *end, *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'; end = &rawpkt[pktlen-1]; 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; } qstat-2.15/ottd.h0000644000175000017500000000103312420765615010646 00000000000000/* * qstat * * opentTTD protocol * Copyright 2007 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_OTTD_H #define QSTAT_OTTD_H #include "qstat.h" query_status_t send_ottdmaster_request_packet(struct qserver *server); query_status_t deal_with_ottdmaster_packet(struct qserver *server, char *rawpkt, int pktlen); query_status_t send_ottd_request_packet(struct qserver *server); query_status_t deal_with_ottd_packet(struct qserver *server, char *rawpkt, int pktlen); #endif qstat-2.15/configure.ac0000644000175000017500000000460612420765614012021 00000000000000AC_INIT([qstat],[2.15],[qstat-users@yahoogroups.com]) AC_CONFIG_SRCDIR([qstat.c]) AM_CONFIG_HEADER([gnuconfig.h]) AC_PREREQ(2.53) AC_CANONICAL_HOST AM_INIT_AUTOMAKE([1.6 foreign]) dnl Checks for programs. AC_PROG_CC dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADER(sys/mman.h, [have_mman_h=yes]) case $host in *mingw32*) AC_MSG_NOTICE([compiling for $host, adding -lwsock32]) LIBS="$LIBS -lwsock32" ;; esac dnl Check for strnstr including broken one on MacOSX 10.4 which crashes dnl AC_CACHE_CHECK(for strnstr, ac_cv_func_strnstr, AC_TRY_RUN([ #include #include #include // we expect this to succeed, or crash on over-run. // if it passes otherwise we may need a better check. int main(int argc, char **argv) { int size = 20; char *str = malloc(size); memset(str, 'x', size); strnstr(str, "fubar", size); return 0; } ],ac_cv_func_strnstr="yes",ac_cv_func_strnstr="no") ) if test "$ac_cv_func_strnstr" = "yes" ; then AC_DEFINE(HAVE_STRNSTR,1,[Working strnstr]) else AC_DEFINE(HAVE_STRNSTR,0,[No or broken strnstr]) fi dnl check if user wants debug AC_MSG_CHECKING([whether to enable optimization]) AC_ARG_ENABLE(optimize,[ --disable-optimize turn off optimization]) if test x$enable_optimize != xno; then AC_MSG_RESULT([yes]) else CPPFLAGS="" CFLAGS="-ggdb" AC_MSG_RESULT([no]) fi dnl check if user wants debug AC_MSG_CHECKING([whether to enable debug output]) AC_ARG_ENABLE(debug,[ --disable-debug turn off debugging code]) if test x$enable_debug != xno; then CPPFLAGS="$CPPFLAGS -DDEBUG" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) fi AC_MSG_CHECKING([whether to enable packet dumps]) AC_ARG_ENABLE(dump,[ --enable-dump enable packet dumps]) if test x$enable_dump != xno; then if test x$have_mman_h = xyes; then CPPFLAGS="$CPPFLAGS -DENABLE_DUMP" AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no, sys/mman.h missing]) fi else AC_MSG_RESULT([no]) fi AC_ARG_WITH(efence, [ --with-efence= Use electric fence for malloc debugging.], if test x$withval != xyes ; then LDFLAGS="${LDFLAGS} -L$withval" fi AC_CHECK_LIB(efence,malloc) ) dnl Use -Wall if we have gcc. changequote(,)dnl if test "x$GCC" = "xyes"; then case " $CFLAGS " in *[\ \ ]-Wall[\ \ ]*) ;; *) CFLAGS="$CFLAGS -Wall" ;; esac fi changequote([,])dnl AC_CONFIG_FILES([ Makefile template/Makefile info/Makefile ]) AC_OUTPUT qstat-2.15/starmade.h0000644000175000017500000000067612420765614011507 00000000000000/* * qstat * by Steve Jankowski * * StarMade protocol * Copyright 2013 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_STARMADE_H #define QSTAT_STARMADE_H #include "qserver.h" // Packet processing methods query_status_t deal_with_starmade_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_starmade_request_packet( struct qserver *server ); #endif qstat-2.15/aclocal.m40000644000175000017500000012367112420766263011400 00000000000000# generated automatically by aclocal 1.14.1 -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])]) m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],, [m4_warning([this file was generated for autoconf 2.69. You have another version of autoconf. It may work, but is not guaranteed to. If you have problems, you may need to regenerate the build system entirely. To do so, use the procedure documented by the package, typically 'autoreconf'.])]) # Copyright (C) 2002-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_AUTOMAKE_VERSION(VERSION) # ---------------------------- # Automake X.Y traces this macro to ensure aclocal.m4 has been # generated from the m4 files accompanying Automake X.Y. # (This private macro should not be called outside this file.) AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version='1.14' dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to dnl require some minimum version. Point them to the right macro. m4_if([$1], [1.14.1], [], [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl ]) # _AM_AUTOCONF_VERSION(VERSION) # ----------------------------- # aclocal traces this macro to find the Autoconf version. # This is a private macro too. Using m4_define simplifies # the logic in aclocal, which can simply ignore this definition. m4_define([_AM_AUTOCONF_VERSION], []) # AM_SET_CURRENT_AUTOMAKE_VERSION # ------------------------------- # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. # This function is AC_REQUIREd by AM_INIT_AUTOMAKE. AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], [AM_AUTOMAKE_VERSION([1.14.1])dnl m4_ifndef([AC_AUTOCONF_VERSION], [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) # AM_AUX_DIR_EXPAND -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets # $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to # '$srcdir', '$srcdir/..', or '$srcdir/../..'. # # Of course, Automake must honor this variable whenever it calls a # tool from the auxiliary directory. The problem is that $srcdir (and # therefore $ac_aux_dir as well) can be either absolute or relative, # depending on how configure is run. This is pretty annoying, since # it makes $ac_aux_dir quite unusable in subdirectories: in the top # source directory, any form will work fine, but in subdirectories a # relative path needs to be adjusted first. # # $ac_aux_dir/missing # fails when called from a subdirectory if $ac_aux_dir is relative # $top_srcdir/$ac_aux_dir/missing # fails if $ac_aux_dir is absolute, # fails when called from a subdirectory in a VPATH build with # a relative $ac_aux_dir # # The reason of the latter failure is that $top_srcdir and $ac_aux_dir # are both prefixed by $srcdir. In an in-source build this is usually # harmless because $srcdir is '.', but things will broke when you # start a VPATH build or use an absolute $srcdir. # # So we could use something similar to $top_srcdir/$ac_aux_dir/missing, # iff we strip the leading $srcdir from $ac_aux_dir. That would be: # am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` # and then we would define $MISSING as # MISSING="\${SHELL} $am_aux_dir/missing" # This will work as long as MISSING is not called from configure, because # unfortunately $(top_srcdir) has no meaning in configure. # However there are other variables, like CC, which are often used in # configure, and could therefore not use this "fixed" $ac_aux_dir. # # Another solution, used here, is to always expand $ac_aux_dir to an # absolute PATH. The drawback is that using absolute paths prevent a # configured tree to be moved without reconfiguration. AC_DEFUN([AM_AUX_DIR_EXPAND], [dnl Rely on autoconf to set up CDPATH properly. AC_PREREQ([2.50])dnl # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` ]) # AM_CONDITIONAL -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_CONDITIONAL(NAME, SHELL-CONDITION) # ------------------------------------- # Define a conditional. AC_DEFUN([AM_CONDITIONAL], [AC_PREREQ([2.52])dnl m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl AC_SUBST([$1_TRUE])dnl AC_SUBST([$1_FALSE])dnl _AM_SUBST_NOTMAKE([$1_TRUE])dnl _AM_SUBST_NOTMAKE([$1_FALSE])dnl m4_define([_AM_COND_VALUE_$1], [$2])dnl if $2; then $1_TRUE= $1_FALSE='#' else $1_TRUE='#' $1_FALSE= fi AC_CONFIG_COMMANDS_PRE( [if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then AC_MSG_ERROR([[conditional "$1" was never defined. Usually this means the macro was only invoked conditionally.]]) fi])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be # written in clear, in which case automake, when reading aclocal.m4, # will think it sees a *use*, and therefore will trigger all it's # C support machinery. Also note that it means that autoscan, seeing # CC etc. in the Makefile, will ask for an AC_PROG_CC use... # _AM_DEPENDENCIES(NAME) # ---------------------- # See how the compiler implements dependency checking. # NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC". # We try a few techniques and use that to set a single cache variable. # # We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was # modified to invoke _AM_DEPENDENCIES(CC); we would have a circular # dependency, and given that the user is not expected to run this macro, # just rely on AC_PROG_CC. AC_DEFUN([_AM_DEPENDENCIES], [AC_REQUIRE([AM_SET_DEPDIR])dnl AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl AC_REQUIRE([AM_MAKE_INCLUDE])dnl AC_REQUIRE([AM_DEP_TRACK])dnl m4_if([$1], [CC], [depcc="$CC" am_compiler_list=], [$1], [CXX], [depcc="$CXX" am_compiler_list=], [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'], [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'], [$1], [UPC], [depcc="$UPC" am_compiler_list=], [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'], [depcc="$$1" am_compiler_list=]) AC_CACHE_CHECK([dependency style of $depcc], [am_cv_$1_dependencies_compiler_type], [if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_$1_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` fi am__universal=false m4_case([$1], [CC], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac], [CXX], [case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac]) for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_$1_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_$1_dependencies_compiler_type=none fi ]) AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) AM_CONDITIONAL([am__fastdep$1], [ test "x$enable_dependency_tracking" != xno \ && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) ]) # AM_SET_DEPDIR # ------------- # Choose a directory name for dependency files. # This macro is AC_REQUIREd in _AM_DEPENDENCIES. AC_DEFUN([AM_SET_DEPDIR], [AC_REQUIRE([AM_SET_LEADING_DOT])dnl AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl ]) # AM_DEP_TRACK # ------------ AC_DEFUN([AM_DEP_TRACK], [AC_ARG_ENABLE([dependency-tracking], [dnl AS_HELP_STRING( [--enable-dependency-tracking], [do not reject slow dependency extractors]) AS_HELP_STRING( [--disable-dependency-tracking], [speeds up one-time build])]) if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) AC_SUBST([AMDEPBACKSLASH])dnl _AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl AC_SUBST([am__nodep])dnl _AM_SUBST_NOTMAKE([am__nodep])dnl ]) # Generate code to set up dependency tracking. -*- Autoconf -*- # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_OUTPUT_DEPENDENCY_COMMANDS # ------------------------------ AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], [{ # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`AS_DIRNAME("$mf")` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`AS_DIRNAME(["$file"])` AS_MKDIR_P([$dirpart/$fdir]) # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ])# _AM_OUTPUT_DEPENDENCY_COMMANDS # AM_OUTPUT_DEPENDENCY_COMMANDS # ----------------------------- # This macro should only be invoked once -- use via AC_REQUIRE. # # This code is only required when automatic dependency tracking # is enabled. FIXME. This creates each '.P' file that we will # need in order to bootstrap the dependency handling code. AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], [AC_CONFIG_COMMANDS([depfiles], [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) ]) # Do all the work for Automake. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This macro actually does too much. Some checks are only needed if # your package does certain things. But this isn't really a big deal. dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O. m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC]) [_AM_PROG_CC_C_O ]) # AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) # AM_INIT_AUTOMAKE([OPTIONS]) # ----------------------------------------------- # The call with PACKAGE and VERSION arguments is the old style # call (pre autoconf-2.50), which is being phased out. PACKAGE # and VERSION should now be passed to AC_INIT and removed from # the call to AM_INIT_AUTOMAKE. # We support both call styles for the transition. After # the next Automake release, Autoconf can make the AC_INIT # arguments mandatory, and then we can depend on a new Autoconf # release and drop the old call support. AC_DEFUN([AM_INIT_AUTOMAKE], [AC_PREREQ([2.65])dnl dnl Autoconf wants to disallow AM_ names. We explicitly allow dnl the ones we care about. m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl AC_REQUIRE([AC_PROG_INSTALL])dnl if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl # test to see if srcdir already configured if test -f $srcdir/config.status; then AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi AC_SUBST([CYGPATH_W]) # Define the identity of the package. dnl Distinguish between old-style and new-style calls. m4_ifval([$2], [AC_DIAGNOSE([obsolete], [$0: two- and three-arguments forms are deprecated.]) m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl AC_SUBST([PACKAGE], [$1])dnl AC_SUBST([VERSION], [$2])], [_AM_SET_OPTIONS([$1])dnl dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. m4_if( m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]), [ok:ok],, [m4_fatal([AC_INIT should be called with package and version arguments])])dnl AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl _AM_IF_OPTION([no-define],, [AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package]) AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl # Some tools Automake needs. AC_REQUIRE([AM_SANITY_CHECK])dnl AC_REQUIRE([AC_ARG_PROGRAM])dnl AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}]) AM_MISSING_PROG([AUTOCONF], [autoconf]) AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}]) AM_MISSING_PROG([AUTOHEADER], [autoheader]) AM_MISSING_PROG([MAKEINFO], [makeinfo]) AC_REQUIRE([AM_PROG_INSTALL_SH])dnl AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl AC_REQUIRE([AC_PROG_MKDIR_P])dnl # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # AC_SUBST([mkdir_p], ['$(MKDIR_P)']) # We need awk for the "check" target. The system "awk" is bad on # some platforms. AC_REQUIRE([AC_PROG_AWK])dnl AC_REQUIRE([AC_PROG_MAKE_SET])dnl AC_REQUIRE([AM_SET_LEADING_DOT])dnl _AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], [_AM_PROG_TAR([v7])])]) _AM_IF_OPTION([no-dependencies],, [AC_PROVIDE_IFELSE([AC_PROG_CC], [_AM_DEPENDENCIES([CC])], [m4_define([AC_PROG_CC], m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_CXX], [_AM_DEPENDENCIES([CXX])], [m4_define([AC_PROG_CXX], m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJC], [_AM_DEPENDENCIES([OBJC])], [m4_define([AC_PROG_OBJC], m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl AC_PROVIDE_IFELSE([AC_PROG_OBJCXX], [_AM_DEPENDENCIES([OBJCXX])], [m4_define([AC_PROG_OBJCXX], m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl ]) AC_REQUIRE([AM_SILENT_RULES])dnl dnl The testsuite driver may need to know about EXEEXT, so add the dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below. AC_CONFIG_COMMANDS_PRE(dnl [m4_provide_if([_AM_COMPILER_EXEEXT], [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END AC_MSG_ERROR([Your 'rm' program is bad, sorry.]) fi fi ]) dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further dnl mangled by Autoconf and run in a shell conditional statement. m4_define([_AC_COMPILER_EXEEXT], m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) # When config.status generates a header, we must update the stamp-h file. # This file resides in the same directory as the config header # that is generated. The stamp files are numbered to have different names. # Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the # loop where config.status creates the headers, so we can generate # our stamp files there. AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], [# Compute $1's index in $config_headers. _am_arg=$1 _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_SH # ------------------ # Define $install_sh. AC_DEFUN([AM_PROG_INSTALL_SH], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi AC_SUBST([install_sh])]) # Copyright (C) 2003-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # Check whether the underlying file-system supports filenames # with a leading dot. For instance MS-DOS doesn't. AC_DEFUN([AM_SET_LEADING_DOT], [rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null AC_SUBST([am__leading_dot])]) # Check to see how 'make' treats includes. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MAKE_INCLUDE() # ----------------- # Check to see how make treats includes. AC_DEFUN([AM_MAKE_INCLUDE], [am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. AC_MSG_CHECKING([for style of include used by $am_make]) am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi AC_SUBST([am__include]) AC_SUBST([am__quote]) AC_MSG_RESULT([$_am_result]) rm -f confinc confmf ]) # Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- # Copyright (C) 1997-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_MISSING_PROG(NAME, PROGRAM) # ------------------------------ AC_DEFUN([AM_MISSING_PROG], [AC_REQUIRE([AM_MISSING_HAS_RUN]) $1=${$1-"${am_missing_run}$2"} AC_SUBST($1)]) # AM_MISSING_HAS_RUN # ------------------ # Define MISSING if not defined so far and test if it is modern enough. # If it is, set am_missing_run to use it, otherwise, to nothing. AC_DEFUN([AM_MISSING_HAS_RUN], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([missing])dnl if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= AC_MSG_WARN(['missing' script is too old or missing]) fi ]) # -*- Autoconf -*- # Obsolete and "removed" macros, that must however still report explicit # error messages when used, to smooth transition. # # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. AC_DEFUN([AM_CONFIG_HEADER], [AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should use the 'AC][_CONFIG_HEADERS' macro instead.])dnl AC_CONFIG_HEADERS($@)]) AC_DEFUN([AM_PROG_CC_STDC], [AC_PROG_CC am_cv_prog_cc_stdc=$ac_cv_prog_cc_stdc AC_DIAGNOSE([obsolete], ['$0': this macro is obsolete. You should simply use the 'AC][_PROG_CC' macro instead. Also, your code should no longer depend upon 'am_cv_prog_cc_stdc', but upon 'ac_cv_prog_cc_stdc'.])]) AC_DEFUN([AM_C_PROTOTYPES], [AC_FATAL([automatic de-ANSI-fication support has been removed])]) AU_DEFUN([fp_C_PROTOTYPES], [AM_C_PROTOTYPES]) # Helper functions for option handling. -*- Autoconf -*- # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_MANGLE_OPTION(NAME) # ----------------------- AC_DEFUN([_AM_MANGLE_OPTION], [[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) # _AM_SET_OPTION(NAME) # -------------------- # Set option NAME. Presently that only means defining a flag for this option. AC_DEFUN([_AM_SET_OPTION], [m4_define(_AM_MANGLE_OPTION([$1]), [1])]) # _AM_SET_OPTIONS(OPTIONS) # ------------------------ # OPTIONS is a space-separated list of Automake options. AC_DEFUN([_AM_SET_OPTIONS], [m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) # _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) # ------------------------------------------- # Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. AC_DEFUN([_AM_IF_OPTION], [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) # Copyright (C) 1999-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_CC_C_O # --------------- # Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC # to automatically call this. AC_DEFUN([_AM_PROG_CC_C_O], [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl AC_REQUIRE_AUX_FILE([compile])dnl AC_LANG_PUSH([C])dnl AC_CACHE_CHECK( [whether $CC understands -c and -o together], [am_cv_prog_cc_c_o], [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])]) # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i]) if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi AC_LANG_POP([C])]) # For backward compatibility. AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_RUN_LOG(COMMAND) # ------------------- # Run COMMAND, save the exit status in ac_status, and log it. # (This has been adapted from Autoconf's _AC_RUN_LOG macro.) AC_DEFUN([AM_RUN_LOG], [{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD (exit $ac_status); }]) # Check to make sure that the build environment is sane. -*- Autoconf -*- # Copyright (C) 1996-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SANITY_CHECK # --------------- AC_DEFUN([AM_SANITY_CHECK], [AC_MSG_CHECKING([whether build environment is sane]) # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[[\\\"\#\$\&\'\`$am_lf]]*) AC_MSG_ERROR([unsafe absolute working directory name]);; esac case $srcdir in *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$[*]" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$[*]" != "X $srcdir/configure conftest.file" \ && test "$[*]" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken alias in your environment]) fi if test "$[2]" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$[2]" = conftest.file ) then # Ok. : else AC_MSG_ERROR([newly created file is older than distributed files! Check your system clock]) fi AC_MSG_RESULT([yes]) # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi AC_CONFIG_COMMANDS_PRE( [AC_MSG_CHECKING([that generated files are newer than configure]) if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi AC_MSG_RESULT([done])]) rm -f conftest.file ]) # Copyright (C) 2009-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_SILENT_RULES([DEFAULT]) # -------------------------- # Enable less verbose build rules; with the default set to DEFAULT # ("yes" being less verbose, "no" or empty being verbose). AC_DEFUN([AM_SILENT_RULES], [AC_ARG_ENABLE([silent-rules], [dnl AS_HELP_STRING( [--enable-silent-rules], [less verbose build output (undo: "make V=1")]) AS_HELP_STRING( [--disable-silent-rules], [verbose build output (undo: "make V=0")])dnl ]) case $enable_silent_rules in @%:@ ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);; esac dnl dnl A few 'make' implementations (e.g., NonStop OS and NextStep) dnl do not support nested variable expansions. dnl See automake bug#9928 and bug#10237. am_make=${MAKE-make} AC_CACHE_CHECK([whether $am_make supports nested variables], [am_cv_make_support_nested_variables], [if AS_ECHO([['TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi]) if test $am_cv_make_support_nested_variables = yes; then dnl Using '$V' instead of '$(V)' breaks IRIX make. AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AC_SUBST([AM_V])dnl AM_SUBST_NOTMAKE([AM_V])dnl AC_SUBST([AM_DEFAULT_V])dnl AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl AC_SUBST([AM_DEFAULT_VERBOSITY])dnl AM_BACKSLASH='\' AC_SUBST([AM_BACKSLASH])dnl _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl ]) # Copyright (C) 2001-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # AM_PROG_INSTALL_STRIP # --------------------- # One issue with vendor 'install' (even GNU) is that you can't # specify the program used to strip binaries. This is especially # annoying in cross-compiling environments, where the build's strip # is unlikely to handle the host's binaries. # Fortunately install-sh will honor a STRIPPROG variable, so we # always use install-sh in "make install-strip", and initialize # STRIPPROG with the value of the STRIP variable (set by the user). AC_DEFUN([AM_PROG_INSTALL_STRIP], [AC_REQUIRE([AM_PROG_INSTALL_SH])dnl # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. dnl Don't test for $cross_compiling = yes, because it might be 'maybe'. if test "$cross_compiling" != no; then AC_CHECK_TOOL([STRIP], [strip], :) fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" AC_SUBST([INSTALL_STRIP_PROGRAM])]) # Copyright (C) 2006-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_SUBST_NOTMAKE(VARIABLE) # --------------------------- # Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. # This macro is traced by Automake. AC_DEFUN([_AM_SUBST_NOTMAKE]) # AM_SUBST_NOTMAKE(VARIABLE) # -------------------------- # Public sister of _AM_SUBST_NOTMAKE. AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) # Check how to create a tarball. -*- Autoconf -*- # Copyright (C) 2004-2013 Free Software Foundation, Inc. # # This file is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # _AM_PROG_TAR(FORMAT) # -------------------- # Check how to create a tarball in format FORMAT. # FORMAT should be one of 'v7', 'ustar', or 'pax'. # # Substitute a variable $(am__tar) that is a command # writing to stdout a FORMAT-tarball containing the directory # $tardir. # tardir=directory && $(am__tar) > result.tar # # Substitute a variable $(am__untar) that extract such # a tarball read from stdin. # $(am__untar) < result.tar # AC_DEFUN([_AM_PROG_TAR], [# Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AC_SUBST([AMTAR], ['$${TAR-tar}']) # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' m4_if([$1], [v7], [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'], [m4_case([$1], [ustar], [# The POSIX 1988 'ustar' format is defined with fixed-size fields. # There is notably a 21 bits limit for the UID and the GID. In fact, # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343 # and bug#13588). am_max_uid=2097151 # 2^21 - 1 am_max_gid=$am_max_uid # The $UID and $GID variables are not portable, so we need to resort # to the POSIX-mandated id(1) utility. Errors in the 'id' calls # below are definitely unexpected, so allow the users to see them # (that is, avoid stderr redirection). am_uid=`id -u || echo unknown` am_gid=`id -g || echo unknown` AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format]) if test $am_uid -le $am_max_uid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format]) if test $am_gid -le $am_max_gid; then AC_MSG_RESULT([yes]) else AC_MSG_RESULT([no]) _am_tools=none fi], [pax], [], [m4_fatal([Unknown tar format])]) AC_MSG_CHECKING([how to create a $1 tar archive]) # Go ahead even if we have the value already cached. We do so because we # need to set the values for the 'am__tar' and 'am__untar' variables. _am_tools=${am_cv_prog_tar_$1-$_am_tools} for _am_tool in $_am_tools; do case $_am_tool in gnutar) for _am_tar in tar gnutar gtar; do AM_RUN_LOG([$_am_tar --version]) && break done am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' am__untar="$_am_tar -xf -" ;; plaintar) # Must skip GNU tar: if it does not support --format= it doesn't create # ustar tarball either. (tar --version) >/dev/null 2>&1 && continue am__tar='tar chf - "$$tardir"' am__tar_='tar chf - "$tardir"' am__untar='tar xf -' ;; pax) am__tar='pax -L -x $1 -w "$$tardir"' am__tar_='pax -L -x $1 -w "$tardir"' am__untar='pax -r' ;; cpio) am__tar='find "$$tardir" -print | cpio -o -H $1 -L' am__tar_='find "$tardir" -print | cpio -o -H $1 -L' am__untar='cpio -i -H $1 -d' ;; none) am__tar=false am__tar_=false am__untar=false ;; esac # If the value was cached, stop now. We just wanted to have am__tar # and am__untar set. test -n "${am_cv_prog_tar_$1}" && break # tar/untar a dummy directory, and stop if the command works. rm -rf conftest.dir mkdir conftest.dir echo GrepMe > conftest.dir/file AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) rm -rf conftest.dir if test -s conftest.tar; then AM_RUN_LOG([$am__untar /dev/null 2>&1 && break fi done rm -rf conftest.dir AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) AC_MSG_RESULT([$am_cv_prog_tar_$1])]) AC_SUBST([am__tar]) AC_SUBST([am__untar]) ]) # _AM_PROG_TAR qstat-2.15/dirtybomb.h0000644000175000017500000000070312420765614011671 00000000000000/* * qstat * by Steve Jankowski * * DirtyBomb protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_DIRTYBOMB_H #define QSTAT_DIRTYBOMB_H #include "qserver.h" // Packet processing methods query_status_t deal_with_dirtybomb_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_dirtybomb_request_packet( struct qserver *server ); #endif qstat-2.15/COMPILE.txt0000644000175000017500000000077512420765614011367 00000000000000Compilation instructions for QStat ---------------------------------- Linux and other GNU systems --------------------------- ./configure && make to install qstat run "make install" to see which configuration parameters can be tweaked, run "./configure --help" If you want to compile from CVS you need to first install autoconf and automake, then run ./autogen.sh. WINDOWS ------- nmake /f Makefile.noauto windows SOLARIS ------- make -f Makefile.noauto solaris HPUX ---- make -f Makefile.noauto hpux qstat-2.15/xform.c0000644000175000017500000003514712420765614011036 00000000000000/* * xform functions * * The methods / structures provide a fully dynamic method for * manipulating server & player names for servers before output * * The original string passed in is never altered. * * We use a dynamically allocated set of buffers to ensure we have * no memory collision. These buffers are persistent for the life * of the qstat process to avoid constant malloc, realloc and free * calls. */ #include #include #include #include #ifndef _WIN32 #include #include #endif #include "xform.h" #ifndef EX_OSERR #define EX_OSERR 71 #endif /* * Flag controlling if xform methods do any processing except transforming * NULL to blank string */ int xform_names = 1; /* Flag to determine if we strip all unprintable characters */ int xform_strip_unprintable = 0; /* Flag to determine if we should print hex based player names */ int xform_hex_player_names = 0; /* Flag to determine if we should print hex based server names */ int xform_hex_server_names = 0; /* Flag to determine if we should script carets */ int xform_strip_carets = 1; /* Flag to detemine if we should generate html names */ int xform_html_names = -1; extern int html_mode; /* xform buffer structure */ typedef struct xform { char *buf; size_t size; struct xform *next; } xform; /* First xform buffer */ static struct xform *xform_bufs = NULL; /* Current xform buffer */ static struct xform *xform_buf = NULL; /* Size of the used amount of the current xform buffer */ static size_t xform_used; /* Is there a currently open font tag in the xform buffer */ static int xform_font_tag; /* Min size of an xform buffer */ static const int xform_buf_min = 256; /*** Private Methods ***/ static int xform_html_entity(const char c, char *dest) { if (html_mode) { switch (c) { case '<': strcpy(dest, "<"); return 4; case '>': strcpy(dest, ">"); return 4; case '&': strcpy(dest, "&"); return 5; default: break; } } return 0; } /* * return the current xform buffer string buffer */ static char * xform_strbuf() { return xform_buf->buf; } /* * Ensure a the current xform buffer is at least size */ static void xform_buf_resize(size_t size, char **bufp) { char *oldbuf; if (size <= xform_buf->size) { // already big enough xform_used = size; return; } oldbuf = xform_buf->buf; if ((xform_buf->buf = realloc(xform_buf->buf, size)) == NULL) err(EX_OSERR, NULL); if (xform_buf->buf != oldbuf && bufp != NULL) { // memory block moved update bufp *bufp = xform_buf->buf + ((*bufp) - oldbuf); } xform_buf->size = size; xform_used = size; } /* * snprintf a string into an xform buffer expanding the buffer * by the size of new string if needed */ static int xform_snprintf(char **buf, size_t size, const char* format, ... ) { int ret; va_list args; // ensure buf is large enough xform_buf_resize(xform_used + size, buf); va_start(args, format); ret = vsnprintf(*buf, size, format, args); va_end(args); return ret; } /* * Copy a string into an xform buffer expanding the buffer * by the size of new string if needed */ static int xform_strcpy(char **buf, const char *str) { size_t size; size = strlen(str); // ensure buf is large enough xform_buf_resize(xform_used + size, buf); (void)strcpy(*buf, str); return size; } /* * Close previous html color and start a new one * Returns the size of the string added to the buffer */ static int xform_html_color(char **buf, const char *font_color) { size_t size; int inc; if (xform_html_names != 1) return 0; size = 15 + strlen(font_color); if (xform_font_tag) size += 7; inc = xform_snprintf(buf, size, "%s", xform_font_tag ? "" : "", font_color); xform_font_tag = 1; return inc; } /* * Reset the xform buffers for re-use */ static void xform_buf_reset() { xform_buf = xform_bufs; xform_font_tag = 0; xform_used = 0; } /* * Allocate and init a new xform buffer ensuring min size is used */ static char * xform_buf_create(size_t size) { struct xform *next; char *buf; /* * We use a min size which should be reasonable for * 99.9% of server and player names */ size = (size >= xform_buf_min) ? size + 1 : xform_buf_min; if((next = malloc(sizeof(xform))) == NULL) { err(EX_OSERR, NULL); } if((buf = malloc(sizeof(char) * size)) == NULL) { err(EX_OSERR, NULL); } next->buf = buf; next->next = NULL; next->size = size; xform_used = size; xform_font_tag = 0; buf[0] = '\0'; if (xform_buf == NULL) { xform_bufs = next; } else { xform_buf->next = next; } xform_buf = next; return next->buf; } /* * Get a xform buffer allocating a new one or expanding an * old one as required */ static char * xform_buf_get(size_t size) { if (xform_buf == NULL || xform_buf->next == NULL) { return xform_buf_create(size); } xform_buf = xform_buf->next; if (size > xform_buf->size) { xform_buf_resize(size, NULL); } else { xform_used = size; xform_font_tag = 0; } xform_buf->buf[0] = '\0'; return xform_buf->buf; } static char *quake3_escape_colors[8] = { "black", "red", "green", "yellow", "blue", "cyan", "magenta", "white" }; /* * Transform a quake 3 string */ static char * xform_name_q3(char *string, struct qserver *server) { unsigned char *s; char *q; q = xform_strbuf(); s = (unsigned char*)string; for (; *s; s++) { if (*s == '^' && *(s + 1) != '^') { if (*(s + 1) == '\0') { break; } if (xform_html_names == 1) { q += xform_html_color(&q, quake3_escape_colors[*(s + 1) &0x7]); s++; } else if (xform_strip_carets) { s++; } else { *q++ = *s; } } else { int inc = xform_html_entity((char)*s, q); if (0 != inc) { q += inc; } else if (isprint(*s)) { *q++ = *s; } else if (*s == '\033') { /* skip */ } else if (*s == 0x80) { *q++ = '('; } else if (*s == 0x81) { *q++ = '='; } else if (*s == 0x82) { *q++ = ')'; } else if (*s == 0x10 || *s == 0x90) { *q++ = '['; } else if (*s == 0x11 || *s == 0x91) { *q++ = ']'; } else if (*s >= 0x92 && *s <= 0x9a) { *q++ = *s - 98; } else if (*s >= 0xa0 && *s <= 0xe0) { *q++ = *s - 128; } else if (*s >= 0xe1 && *s <= 0xfa) { *q++ = *s - 160; } else if (*s >= 0xfb && *s <= 0xfe) { *q++ = *s - 128; } } } *q = '\0'; return xform_strbuf(); } /* * Transform a tribes 2 string */ static char * xform_name_t2(char *string, struct qserver *server) { char *s, *q; q = xform_strbuf(); s = string; for (; *s; s++) { int inc = xform_html_entity(*s, q); if (0 != inc) { q += inc; continue; } else if (isprint(*s)) { *q++ = *s; continue; } if (xform_html_names == 1 && s[1] != '\0') { char *font_color; switch (*s) { case 0x8: font_color = "white"; break; /* normal */ case 0xb: font_color = "yellow"; break; /* tribe tag */ case 0xc: font_color = "blue"; break; /* alias */ case 0xe: font_color = "green"; break; /* bot */ default: font_color = NULL; } if (font_color) { q += xform_html_color(&q, font_color); } } } *q = '\0'; return xform_strbuf(); } static const char *unreal_rgb_colors[] = { "#F0F8FF", "#FAEBD7", "#00FFFF", "#7FFFD4", "#F0FFFF", "#F5F5DC", "#FFE4C4", "#000000", "#FFEBCD", "#0000FF", "#8A2BE2", "#A52A2A", "#DEB887", "#5F9EA0", "#7FFF00", "#D2691E", "#FF7F50", "#6495ED", "#FFF8DC", "#DC143C", "#00FFFF", "#00008B", "#008B8B", "#B8860B", "#A9A9A9", "#006400", "#BDB76B", "#8B008B", "#556B2F", "#FF8C00", "#9932CC", "#8B0000", "#E9967A", "#8FBC8F", "#483D8B", "#2F4F4F", "#00CED1", "#9400D3", "#FF1493", "#00BFFF", "#696969", "#1E90FF", "#B22222", "#FFFAF0", "#228B22", "#FF00FF", "#DCDCDC", "#F8F8FF", "#FFD700", "#DAA520", "#808080", "#008000", "#ADFF2F", "#F0FFF0", "#FF69B4", "#CD5C5C", "#4B0082", "#FFFFF0", "#F0E68C", "#E6E6FA", "#FFF0F5", "#7CFC00", "#FFFACD", "#ADD8E6", "#F08080", "#E0FFFF", "#FAFAD2", "#90EE90", "#D3D3D3", "#FFB6C1", "#FFA07A", "#20B2AA", "#87CEFA", "#778899", "#B0C4DE", "#FFFFE0", "#00FF00", "#32CD32", "#FAF0E6", "#FF00FF", "#800000", "#66CDAA", "#0000CD", "#BA55D3", "#9370DB", "#3CB371", "#7B68EE", "#00FA9A", "#48D1CC", "#C71585", "#191970", "#F5FFFA", "#FFE4E1", "#FFE4B5", "#FFDEAD", "#000080", "#FDF5E6", "#808000", "#6B8E23", "#FFA500", "#FF4500", "#DA70D6", "#EEE8AA", "#98FB98", "#AFEEEE", "#DB7093", "#FFEFD5", "#FFDAB9", "#CD853F", "#FFC0CB", "#DDA0DD", "#B0E0E6", "#800080", "#FF0000", "#BC8F8F", "#4169E1", "#8B4513", "#FA8072", "#F4A460", "#2E8B57", "#FFF5EE", "#A0522D", "#C0C0C0", "#87CEEB", "#6A5ACD", "#708090", "#FFFAFA", "#00FF7F", "#4682B4", "#D2B48C", "#008080", "#D8BFD8", "#FF6347", "#40E0D0", "#EE82EE", "#F5DEB3", "#FFFFFF", "#F5F5F5", "#FFFF00", "#9ACD32", }; /* * Transform a unreal 2 string */ static char * xform_name_u2(char *string, struct qserver *server) { unsigned char *s; char *q; q = xform_strbuf(); s = (unsigned char *)string; for (; *s; s++) { if (memcmp(s, "^\1", 2) == 0) { // xmp color s += 2; q += xform_html_color((char **)&s, unreal_rgb_colors[*s - 1]); } else if (memcmp(s, "\x1b", 1) == 0) { // ut2k4 color char color[5]; s += 1; sprintf(color, "#%02hhx%02hhx%02hhx", s[0], s[1], s[2]); q += xform_html_color(&q, color); s += 3; } else { int inc = xform_html_entity(*s, q); if (0 != inc) { q += inc; } else if (isprint(*s)) { *q++ = *s; } else if (0xa0 == *s) { *q++ = ' '; } } } *q = '\0'; return xform_strbuf(); } /* * Transform a trackmania string */ static char * xform_name_tm(char *string, struct qserver *server) { char *s, *q; int open = 0; char c1, c2, c3; q = xform_strbuf(); s = string; for (; *s; s++) { if (*s == '$') { s++; switch (*s) { case 'i': case 'I': // italic if (xform_html_names == 1) { q += xform_strcpy(&q, ""); open++; } break; case 's': case 'S': // shadowed break; case 'w': case 'W': // wide break; case 'n': case 'N': // narrow break; case 'm': case 'M': // normal if (xform_html_names == 1) { q += xform_strcpy(&q, ""); open++; } break; case 'o': case 'O': // bold if (xform_html_names == 1) { q += xform_strcpy(&q, ""); open++; } break; case 'g': case 'G': // default color if (xform_html_names == 1) { q += xform_strcpy(&q, ""); open++; } break; case 'z': case 'Z': // reset all while (open) { q += xform_strcpy(&q, ""); open--; } break; case 't': case 'T': // capitalise if (xform_html_names == 1) { q += xform_strcpy(&q, ""); open++; } break; case '$': // literal $ *q++ = '$'; break; case '\0': // Unexpected end break; default: // color c3 = '\0'; c1 = *s; s++; c2 = *s; if (c2) { s++; c3 = *s; if (c3 && xform_html_names == 1) { q += xform_snprintf(&q, 34, "", c1, c1, c2, c2, c3, c3); open++; } } break; } } else { *q++ = *s; } } while (open) { q += xform_strcpy(&q, ""); open--; } *q = '\0'; return xform_strbuf(); } static char *sof_colors[32] = { "FFFFFF", "FFFFFF", "FF0000", "00FF00", "FFFF00", "0000FF", "FF00FF", "00FFFF", "000000", "7F7F7F", "702D07", "7F0000", "007F00", "FFFFFF", "007F7F", "00007F", "564D28", "4C5E36", "370B65", "005572", "54647E", "1E2A63", "66097B", "705E61", "980053", "960018", "702D07", "54492A", "61A997", "CB8F39", "CF8316", "FF8020" }; /* * Transform a soldier of fortune player name */ static char * xform_name_sof(char *string, struct qserver *server) { unsigned char *s; char *q; q = xform_strbuf(); s = (unsigned char*)string; // The may not be the intention but is needed for q1 at least for (; *s; s++) { int inc = xform_html_entity(*s, q); if (0 != inc) { q += inc; continue; } if (*s < ' ') { q += xform_html_color(&q, sof_colors[*(s)]); } else if (isprint(*s)) { *q++ = *s; // ## more fixes below; double check against real sof servers } else if (*s >= 0xa0) { *q++ = *s &0x7f; } else if (*s >= 0x92 && *s < 0x9c) { *q++ = '0' + (*s - 0x92); } else if (*s >= 0x12 && *s < 0x1c) { *q++ = '0' + (*s - 0x12); } else if (*s == 0x90 || *s == 0x10) { *q++ = '['; } else if (*s == 0x91 || *s == 0x11) { *q++ = ']'; } else if (*s == 0xa || *s == 0xc || *s == 0xd) { *q++ = ']'; } } *q = '\0'; return xform_strbuf(); } /*** Public Methods ***/ /* * perform a printf containing xform_name based arguments */ int xform_printf(FILE *file, const char *format, ...) { int ret; va_list args; xform_buf_reset(); va_start(args, format); ret = vfprintf(file, format, args); va_end(args); return ret; } /* * Clear out and free all memory used by xform buffers */ void xform_buf_free() { struct xform *cur; struct xform *next; for (cur = xform_bufs; cur != NULL; cur = next) { next = cur->next; if (cur->buf != NULL) { free(cur->buf); cur->buf = NULL; } free(cur); } xform_bufs = NULL; xform_buf = NULL; } /* * Transforms a string based on the details stored on the server */ char * xform_name(char *string, struct qserver *server) { char *buf, *bufp, *s; int is_server_name; if (string == NULL) { buf = xform_buf_get(1); strcpy(buf, "?"); return buf; } if (!xform_names) { return string; } s = string; if (xform_strip_unprintable) { buf = xform_buf_get(strlen(string)); bufp = buf; for (; *s; s++) { if (isprint(*s)) { *bufp = *s; bufp++; } } *bufp = '\0'; if (*buf == '\0') { strcpy(buf, "?"); return buf; } s = buf; } is_server_name = (string == server->server_name); if ((xform_hex_player_names && !is_server_name) || (xform_hex_server_names && is_server_name)) { buf = xform_buf_get(strlen(s) * 2); bufp = buf; for (; *s; s++, bufp += 2) { sprintf(bufp, "%02hhx", *s); } *bufp = '\0'; return buf; } buf = xform_buf_get(strlen(s)); if (server->type->flags &TF_QUAKE3_NAMES) { s = xform_name_q3(s, server); } else if (!is_server_name && (server->type->flags &TF_TRIBES2_NAMES)) { s = xform_name_t2(s, server); } else if (server->type->flags &TF_U2_NAMES) { s = xform_name_u2(s, server); } else if (server->type->flags &TF_TM_NAMES) { s = xform_name_tm(s, server); } else if (!is_server_name || server->type->flags &TF_SOF_NAMES) { // Catch all for NOT is_server_name OR TF_SOF_NAMES s = xform_name_sof(s, server); } if (xform_font_tag) { xform_strcpy(&s, ""); } return s; } qstat-2.15/Makefile.am0000644000175000017500000000202512420765615011561 00000000000000SUBDIRS = template info CPPFLAGS = -Dsysconfdir=\"$(sysconfdir)\" @CPPFLAGS@ bin_PROGRAMS = qstat qstat_SOURCES = \ xform.c xform.h \ config.c config.h \ debug.c debug.h \ utils.c utils.h \ hcache.c \ md5.c md5.h \ qserver.c qserver.h \ qstat.c qstat.h \ template.c \ a2s.c a2s.h \ packet_manip.c packet_manip.h \ ut2004.c ut2004.h \ doom3.c doom3.h \ gps.c gps.h \ gs2.c gs2.h \ gs3.c gs3.h \ ts2.c ts2.h \ tm.c tm.h \ haze.c haze.h \ ottd.c ottd.h \ wic.c wic.h \ fl.c fl.h \ tee.c tee.h \ cube2.c cube2.h \ ts3.c ts3.h \ bfbc2.c bfbc2.h \ ventrilo.c ventrilo.h \ mumble.c mumble.h \ terraria.c terraria.h \ crysis.c crysis.h \ dirtybomb.c dirtybomb.h \ starmade.c starmade.h \ farmsim.c farmsim.h \ ksp.c ksp.h dist_configfiles_DATA = qstat.cfg configfilesdir = $(sysconfdir) EXTRA_DIST = CHANGES.txt COMPILE.txt LICENSE.txt \ Makefile.noauto \ ChangeLog \ qstatdoc.html \ contrib.cfg cl: cvs2cl.pl --utc --no-wrap --separate-header --no-times -f ChangeLog.cvs rm -f ChangeLog.cvs.bak qstat.core qstat-2.15/CHANGES.txt0000644000175000017500000014435612420765614011353 00000000000000Qstat version 2.15 Summary of New Features ----------------------- New protocols: KSP [-ksp] Qstat version 2.14 Summary of New Features ----------------------- New protocols: DirtyBomb aka Extraction [-dirtybomb] Starmade [-starmade] Farmsim [-farmsim] Refactored output splitting out xform processing into its own files improving various portions of it. Fixes ----- hcache segv fixes packetmanip fixes for packet combining -- Steven Harltand QStat version 2.11 ** UPDATED for 2.11 ** November 04, 2006 Summary of New Features ----------------------- new protocols: Warsow [-warsows, -warsowm] Prey [-preys, -preym] TrackMania [-tm] Tremulous [-tremulous, -tremulousm] add -nx and -nnx options that enable resp. disable name transformation calculate player score for AMS servers Fixes ----- fix segfault when a "tribes2 master" returns garbage -- Steve Jankowski Steven Hartland Ludwig Nussel QStat version 2.10 ** UPDATED for 2.10 ** October 22, 2005 Fixes ----- fix Quake4 master only returning 231 servers fix busy loop when waiting for Quake3 and Quake4/Doom3 master packets fix win32 build -- Steve Jankowski Steven Hartland Ludwig Nussel QStat version 2.9 ** UPDATED for 2.9 ** October 20, 2005 Summary of New Features ----------------------- new protocols: Pariah [-prs] Steam Master for A2S [-stma2s] Nexuiz [-nexuizm, -nexuizs] Gamespy V3 [-gs3] Quake 4 [-q4m, -q4s] add option -allowserverdups to be able to query ts2 servers support for LAN broadcasts with A2S add option -sendinterval for tuning send throttling add support for port ranges support HL1 protocol variant in A2S add 'S' player sort option to sort by score Fixes ----- fix eye protocol not showing the last player always use an offset of 123 with eye protocol fix infinite loop and memory expansion when port is 65535 -- Steve Jankowski Steven Hartland Ludwig Nussel ** UPDATED for 2.8 ** April 03, 2005 Summary of New Features ----------------------- add support for new steam protocol (-a2s) add derived type STMHL2 for steam master returning a2s instead of hls change timing for sending packets to improve ping times of low-ping servers Fixes ----- fix ut2004 master server support -- Steve Jankowski Steven Hartland Ludwig Nussel QStat version 2.7 ** UPDATED for 2.7 ** Dec 22, 2004 Summary of New Features ----------------------- new protocols: UT2004 master [-ut2004m] update steam master protocol to new version add additional output to the player xml of -gps add option -progress,n to print out progress every n packets add doom3 protocol and osmask as server rule use autoconf+automake, a simple Makefile is provided as fallback add "flags" to qstat.cfg Fixes ----- fix hanging qstat when receiving UDP packets with incorrect checksum fix colored names in America's Army (use -ams instead of -gps) -- Steve Jankowski Steven Hartland Ludwig Nussel QStat version 2.6 ** UPDATED for 2.6 ** Aug 15, 2004 Summary of New Features ----------------------- new protocols: All Seeing Eye [-eye] Ravenshield [-rvs] Savage [-sas] FarCry [-fcs] Jedi Knight: Jedi Academy [-jk3m, -jk3s] Gamespy2 [-gs2] Steam master [-stm] Doom3 [-dm3s, -dm3s] Half-Life 2 [-hl2s] (experimental) add option -hsn to display server names in hex [no docs] add "servers/sec" to -progress output add -mdelim parameter to specify the multi value delimiter ( default '|' ) add \final\\ to end of gamespy master request add UT2K4 colored name parsing add UT2 XMP colored name parsing add SOF coloring of server names Fixes ----- fix custom q3 master query for masters created via qstat.cfg fix gamespy protocol to better handle Halo and BF1942 fix for multi value fields in UT2003 e.g. Mutators. fix XML escaping bugs New template variables ---------------------- $SCORE player score Thanks ------ Timothee Besset from id Software for providing Doom3 protocol information Alexander Schfer for fixing version and password field for Ravenshield and of course everyone else who provided feedback and bug reports -- Steve Jankowski Steven Hartland Ludwig Nussel ** UPDATED for 2.5c ** Nov 11, 2002 Summary of New Features ----------------------- Unreal Tournament 2003 support [-ut2s] Including support for the current UT2003 patch Ghost Recon support [-grs] Bob Marriott provided the patch for this. I integrated with very few changes. See info/GhostRecon.txt for more detail. Thanks Bob! Supports versions 1.2, 1.3, 1.4 and expansions -noportoffset to disable adding the port offset to query packets There's a "noportoffset" query argument to set this per-server. -showgameport to output the game port instead of the query port With -showgameport, qstat will report the game port instead of the query port in $ARG, $PORT, and $HOSTNAME. If the query port is different from game port, the query port will be set in the "_queryport" server rule. There's a "showgameport" query argument to set this per-server. New template variables ---------------------- $TOTALMAXPLAYERS Sum of max players from all servers $PLAYERSTATID UT2003 global player stat id (not yet supported by Epic). $UNREALTOURNAMENT2003 $GHOSTRECON $PLAYERLEVEL Character level for NWN $IF:DEATHS True if $DEATHS > 0 $TOTALUTILIZATION How full the servers are (0 to 100 percent) Fixes ----- Fixed packet parsing for Battlefield 1942. Use -gps to query BF1942 servers. The query port is usually 23000. Fix broadcast queries for Tribes 2, Quake 3, UT2003 (hopefully) Fix all output modes to support team-numbers, team-names, and no-team styles Fix xml output; accidentally disabled and Fix player info for NWN and other GPS games Fix sv_password rule on Half-Life servers Removed some debug output Thanks ------ A big round of applause for Bob Marriott, author of the Ghost Recon support. He reverse engineered the GR status protocol and maintained the patch through several protocol revisions. And he wrote documentation! Thanks to Ludwig Nussel and Alex Burger of XQF for testing, suggestions, and some timely stubborness :-) Thanks for testing and suggestions: Kingsley Foreman, Pierre Smolarek, Simon Garner and Paul Witt. Steve, steve@qstat.org ** UPDATED for 2.5b ** August 8, 2002 Whoops, I broke XQF. When using QStat raw mode, XQF and other programs rely on the number of fields returned staying fixed. I added a game/mod field to most raw output which breaks these programs. Summary of New Features ----------------------- Extended -raw with a -raw,game variation that adds the game/mod name to the end of the raw server output. Otherwise, the game/mod info is not output in raw mode. Thanks to Ludwig Nussel for not biting my head off (too much). Steve, steve@qstat.org ** UPDATED for 2.5a ** August 6, 2002 Final version of QStat 2.5a. Please send feedback and bug reports to qstat-users@yahoogroups.com or to steve@qstat.org This version of QStat is being distributed under the Artistic License. The terms of the license can be found in LICENSE.txt in the QStat package. Summary of New Features ----------------------- Config file support to define new game types This is a major new feature. This will allow users to define new game types and master servers, including setting custom request packets. I expect that support for most new game types will be accomplished via config files. The default config file is "qstat.cfg". More game types from QStat users can be found in "contrib.cfg". Added support for "status port offset" to config file; UNS (unreal) has this set to 1. If you extend UNS, the new server type will have the same status port offset. Added a GNUmakefile to support gmake Updated COMPILE.txt with new instructions Improve Half-Life server status; extracts mod information and secure status Add support for server rules template (-Tr file) See qstatdoc.html for instructions. Support broadcast queries for Tribes and Tribes 2 Star Trek: Elite Force server and master (-efs and -efm) Return to Castle Wolfenstein server and master (-rws and -rwm) Debug flag (-d) (uses an improved packet output format) Support color player names in Soldier of Fortune Default Config File (qstat.cfg) ------------------------------- Command and Conquer: Renegade server (-crs) Soldier of Fortune 2 (-sof2s) Soldier of Fortune 2 Master (-sof2m) Medal of Honor: Allied Assault server (-mas) Medal of Honor: Allied Assault server, Quake 3 protocol (-maqs) Half-Life "infostring" protocol (-hlqs) This is a Quake 2 style protocol Fixes ----- Fixed raw output to include the game or mod name as the last item Fix template to allow numbers, '.' and ' ' in rule names Refers to $(RULE:someserverrule) Allowing space ' ' may break existing templates if they use syntax like $RULE:maxbullets Max Bullets This can be fixed by change it to $(RULE:maxbullets) This change was made because SOF2 allows spaces in server rule names. Fix Unreal and Gamespy based servers to support backslashes '\' in player names (only partially worked before) Support Half-Life split packets; this happens to the rules info from some Half-Life servers (usually AdminMod and DOD). XML output; added element, UTF-8 output option (-utf8) XML; added Fix crash on broadcast queries Avoid duplicates in the rule list Fixed -srcip to put address in the right byte-order Work-around for crash on Windows when bind() returns temporary error Finish output when -timeout expires Changed Q3 based servers to use a two-packet status query; I think this gets more accurate mod information. More accurate player count on Quake based servers Compiles on OSX/Darwin Fix one byte overrun on QuakeWorld packet New template variables ---------------------- $TYPEPREFIX The server's game type prefix $RULENAMESPACES Allow spaces in rule names $RULETEMPLATE Invoke the server rule template $RULENAME The rule name $RULEVALUE The rule value $(IF:RULENAME(name)) True if rule name equals "name" $(IF:RULEVALUE(value)) True if rule value equals "value" (see qstat.cfg for gametype variables) Thanks ------ Many thanks to all the beta testers for bug reports and feature suggestions. There are many to list, but the following provided significant help: Kingsley Foreman, Mike Davis, Ludwig Nussel, Pierre Smolarek, aphax, and Simon Garner. and I'm sure I forgot someone Steve, steve@qstat.org ** UPDATED for 2.4e ** Oct 1, 2001 This release is basically to fix Tribes 2 support. That was all my fault, Dynamix/Sierra did nothing wrong. Since I was going through the trouble of a full release, I decided to toss in Descent 3 support. Don't be impressed, a patch for D3 was sitting in my inbox. :-) Summary of New Features ----------------------- Descent 3 support -htmlmode (same as $HTML, but for -raw mode) Fixes ----- Fixed Tribes 2 queries Fixed $SHIRTCOLOR when no color names are used Thanks ------ Many thanks to Matthew Mueller for a patch to support Descent 3. Matthew thanks Brian Hayes, Kevin Bentley, and tcpdump. Thanks to Thomas Hager for putting me on the right track for the Tribe 2 bug. Sorry, the real -noconsole support did not make it into this release. Steve, steve@qstat.org ** UPDATED for 2.4d ** August 8, 2001 Summary of New Features ----------------------- Half-Life master filters Names for Quake 3 game types XML output mode Broadcast support for Gamespy style protocols Append output file option [-af] Option to print carets in Q3 player names [-carets] OS/2 Warp EMX compiler port OpenBSD support Options to specify source ports [-srcport] and source IP address [-srcip] for packets sent by qstat. Handy for getting through firewalls. See docs for details. Fixes ----- Tribes 2 teamdamage flag Fixed writing beyond array bounds when reading templates on Windows. (maybe this will fix the garbage characters some people see) Fixed player sorting for games with teams (tribes 1 and 2). Removed win32/qstat.exe from the tar.gz Trying the MS C 6.0 compiler again (win32/qstat.exe) Fixed running QStat from PHP; would crash or give no data New template variables ---------------------- $CLEARNEWLINES Convert newlines to spaces in all variable output. Handy for Tribes 2 servers with long descriptions. $GAMETYPE Quake 3 only - the name of the game type Thanks ------ Most of this release was contributed by QStat users: XML output Simon Garner Half-Life master filters Ludwig Nussel OS/2 Warp EMX Mikulas Patocka OpenBSD subset A three rail gun salut to ya! And thanks to Tahi 'Linus' Walcher for helping find the PHP bug. strace is a thing of the gods. I was hoping to fix one other problem for Windows users. QStat is a command-line style program, so Windows always gives it a console window. This is annoying if you're running QStat from a web-page or a GUI server browser. I can fix this, but it's not that easy. In the mean time, I've added a -noconsole option that will delete the console as soon as qstat starts. The effect is that a console window will flash on the screen briefly. QStat still runs, you just won't see any output on screen. Anyway, I'll craft a real implementation of -noconsole in the next release. Steve, steve@qstat.org ** UPDATED for 2.4c ** Apr 19, 2001 Summary of New Features ----------------------- Tribes 2 player type and tribe tag information Changed Quake 3 default version to "48" (1.27g) New Tribes 2 master filters. (see documentation) Bug Fixes --------- Fixed win32/qstat.exe binary; re-compiled using old compiler Convert newlines into spaces when printing Tribes 2 server info in raw mode. Fixed problems with the 22337 build of Tribes 2. Tribes 2 raw output is now the same format as most other servers. Note that this reverses the order of current and max players from what they were in 2.4b. And adds ping and # retries values. New template variables ---------------------- $IF:ISBOT $IF:ISALIAS $IF:TRIBETAG $TRIBETAG Notes ----- [ Blarg, I hate it when I blow a release. Many people had problems with the win32/qstat.exe in 2.4b release. I had compiled this with a new compiler version on a new Win2k install. It worked fine for me, but apparently the new compiler has compatibility problems. So, I've gone back to the old compiler and old NT 4.0 install. Several people also reported problems using 2.4b with the new 22337 build of Tribes 2. Sorry about the problems. This release should fix things up. ] The new Tribes 2 player info is available in raw mode (see docs) and templates. But it is not displayed in the interactive output. I've updated the sample Tribes 2 templates to display the new player info. Finally, there seem to be a number of bugs with the Tribes 2 master servers. One of the bugs is noted in the documentation. Dynamix is aware of the problems and working to fix them. Steve, steve@qstat.org ** UPDATED for 2.4b ** Apr 13, 2001 Summary of New Features ----------------------- Support for Tribes 2 [-t2s] (builds numbered 22075 or higher) Support for Tribes 2 master [-t2m] Support for Quake 3 and Tribes 2 colorized player names [-htmlnames] Sample HTML templates for Tribes 2 [template/tribes2*] New QStat web site! http://www.qstat.org New mailing lists for QStat users and announcements! (see web site) New template variables ---------------------- $ISMASTER $TRIBES2 $TRIBES2MASTER $HTMLPLAYERNAME Bug Fixes --------- Fix 'game' value for some Quake 2 based servers Fixed some cases where QStat will hang Fixed some picky compiler warnings Notes ----- The Tribes 2 master server has a number of fancy filtering options. Check the "Tribes 2 Master" section in the documentation for details. Many thanks to Brad Heinz and Dynamix for their help with Tribes 2. Thanks to the QStat beta testers: Dr. Chmod, Marauder, Leif Sawyer, Luca Spada, Simon Garner, and Jose Ivey Steve, steve@qstat.org ** UPDATED for 2.4a ** Oct 5, 2000 Summary of New Features ----------------------- Support for Gamespy master [-gsm] Support for "Gamespy style" protocol queries (adds 12+ games) [-gsm and -gps] More server sort options [-sort] Player sort options [-sort] Option to set the output file [-of] Quake 3 master query argument; can query by protocol version Other Improvements ------------------ Way way way faster Fixed Q3 master server queries Fixed queries of SoF 1.05 servers Servers now queried in the order provided to QStat (was reverse order) Fixed ^ display in Q3 player names Partial fix for '\' in player names Players now displayed in the order the server reports them (was reverse order) Rules now displayed in the order the server reports them (was reverse order) Server variables can be referenced inside player templates Fixed raw display of SoF servers Improved HalfLife queries; fetches sv_type and sv_os server rules Much much much faster New template variables ---------------------- $IF:GAMESPYMASTER $IF:GAMESPYPROTOCOL Notes ----- I'm probably treading on some toes with the Gamespy master support. Someone figured out that the Gamespy server lists are not protected, and sent me the protocol. Once I had that, supporting the master was trivial. See the documentation for details on using a gamespy master. Many games are using the Unreal style server status protocol. Maybe because there are lots of Unreal engine games. Or maybe because developers want Gamespy support, so they use a protocol that Gamespy already supports. There are too many of these games to add individual game types and command-line options. So I've lumped them together as "Gamespy Protocol" servers using the game type "GPS". They all seem to have a server rule called "gamename" set to the name of the game (eg. "roguespear", "turok2"). I made a pile of performance improvements to QStat. Start-up time for large server lists is very fast. Queries on large servers lists is also much faster. And queries require much less CPU time. If you have -maxsim set high to reduce query times, you might see more server timeouts now. QStat can spew out packets so fast, you'll see more packet loss and hence more timeouts. Thanks ------ Many thanks to the beta testers and contributors. They provided bug fixes, bug reports, suggestions, ideas, protocol traces, and kind words. I'll spare them the spam by just mentioning real names: Alex Burger, Conan Ford, Vitaliy Fuks, Mike Dowell, Nico de Vries, and Jose Ivey Steve ** UPDATED for 2.3g ** Feb 3, 2000 BETA is done! The 2.3 release is stable enough now to drop the beta qualifier. Summary of New Features ----------------------- Added options to support Soldier of Fortune [-sfs] New template variables ---------------------- $IF:SOLDIEROFFORTUNE There are command-line options to control the following, but it's handy to have control within the templates as well. $COLORNUMBERS Set the format of $SHIRTCOLOR and $PANTSCOLOR $COLORNAMES $COLORRGB $TIMESECONDS Set the format of $CONNECTTIME $TIMECLOCK $TIMESTOPWATCH Summary of Fixes ---------------- Fix crashes in Unreal -raw player output (duh). Fix hangs doing Unreal server queries. Fix $GAME for Quake 3 servers Fix Kingpin servers reported as Q2 servers Notes ----- The SOF server does not return map information, so you'll just get a '?' or blank for an SOF map. The map info is returned by the master server. But QStat does not yet support the SOF master server. I traced the SOF master protocol, but it's totally different from any other master server. Before I invest the time into writing a parser for the SOF master packets, I'm going to wait to see if it changes before the final retail release. Notes on Future Releases ------------------------ Now that the 2.3 release train is winding down, what's up for QStat 2.4? I don't know, but there's a few frequently requested features: - More sort options; server and player - More games; Delta Force, Descent III - Fetch server lists from web pages - Better templates; variables and full expression evaluation - Better performance on large server lists - Examples and samples I don't know which features will be available when, so don't ask. There may be one or two more 2.3 releases to fix critical bugs or add a new game. Getrnk und ist frhlich, Steve ** UPDATED for 2.3f BETA ** Jan 11, 2000 Summary of Fixes ---------------- Added player ping and face to Unreal -raw output Fix queries for version 405 Unreal servers New template variable --------------------- For the player template: $FACE The texture used on a player's face. This was added to Unreal a while back, but I didn't notice. Notes ----- The fine blokes at Unreal decided to fiddle with the Unreal query protocol. When asked why PingTool and QStat did not work with the new servers, they responded that we must not be following the new GameSpy spec. Ha! As if they publish this information or care to keep other server browser authors informed. Sheesh. Steve ** UPDATED for 2.3e BETA ** Jan 7, 2000 Summary of Fixes ---------------- Quake III Arena master queries Half-Life master queries $(IF:GAME) was true when $GAME was blank (Tribes) Improved Q3A player name translation Fixed raw mode output for Unreal (minor incompatible change) Updated docs for raw mode output Add one to Unreal/UT port to get query port (incompatible change) $GAME and "-sort g" now work for Unreal/UT Summary of New Features ----------------------- Options added for Kingpin and Heretic II game servers. These two games were previously supported with the -q2s option. New options: -kps and -hrs New template conditions: $(IF:KINGPIN) and $(IF:HERETIC2) Notes ----- Numerous people sent me the fix for the Q3A master query problem. I think the first was Ted Milker, but thanks to all for your suggestions and patience. The Half-Life master support wasn't using the latest protocol, so needed an upgrade. Now you can get the full 2100+ server list from the master. BTW, there are more HL servers than Q3A servers. Unreal support was changed to automatically add one to the port number to find the query port. This is probably why people thought QStat didn't support UT. For those that figure it out already, you'll have to remove your own +1 hacks to use this release. I apologize for the long delay between releases. Work, holidays, and health problems cut my free time to less than zero. Best wishes for the new millennium, Steve ** UPDATED for 2.3d BETA ** May 12, 1999 More bug reports and suggestions prompted this release. Quake 3 master -------------- The id Q3 master server isn't working very well. The protocol is lame and its network is way over subscribed. I've enhanced QStat to deal with the changes, but I actually think they (id) have made matters worse rather than better. QStat can now, sometimes, get all the servers from the master, but it often can't get 30-60% of the servers. This is not QStat problem, but id's. I've sent them a detailed analysis of the problems and made some suggestions. Summary of Fixes ---------------- Improve reliability of Q3 master server queries Support Tribes servers with 3+ teams Strip escape sequences from Q3 player names; use -hpn if you want the complete content of player names. Accurately calculate number of servers on a master (ignore duplicates). Fixed $(ISFULL) to be false if the server is empty [duh] New Features ------------ New option to control master server retry interval ("-mi") independent of server retry interval. Increase maximum -maxsim to 256 for Win32. Added $(TYPESTRING) template var; shows server's type string (eg. q2s, hls) Added $(NOWINT) template var; shows the current time in seconds since 00:00:00 UTC, January 1, 1970. Notes ----- Many many thanks to Nico de Vries (Nico.de.Vries@ucc.nl) of CLQ for the many bugs reports, suggestions, etc. Thanks to stincey@nireland.com for figuring out the Tribes 3+ teams bug. Steve, steve@activesw.com ** UPDATED for 2.3c BETA ** May 3, 1999 A slew of bug reports arrived over the weekend. I guess QStat users are weekend warriors. Thanks to the four people that sent patches for the Q3 master breakage. I won't say who's patch I used, but I selected the most elegant. id has said that the Q3 master protocol will be changing alot over the next weeks. I'll try to track their progress, but no promises. They also asked for suggestions on reducing packet size, so I sent them my ideas (all quite clever ). Summary of Fixes ---------------- Q3 master server Q3 server name Tribes -raw mode [forgot to write it] Removed leftover debug print Switched snprintf() to sprintf() [much more portable] Half-Life game rules [useful for TFC] Fixed -progress output Added player ping to Unreal player output Fixed minor mistakes in docs Notes ----- Many thanks to: "Dark Grue" of QStatList Nico de Vries of CLQ "Joe S." of ... I forget what Joe does Sven Grundmann for their bug reports, patches, and suggestions. Steve, steve@activesw.com ** UPDATED for 2.3b BETA ** April 29, 1999 New: Quake III and BFRIS support Not many complaints about problems with 2.3a, looks like the new code is working fine. Summary of New Features ----------------------- Quake III: Arena (Q3Test) Quake III master BFRIS (www.aegistech.com) Minor Changes ------------- A couple people pointed out that the docs and the code did not exactly agree on the server type strings. So, I've fixed the code to match the docs. The following type strings were changed: 2.3a 2.3b ---- ---- QW --> QWS Q2 --> Q2S Notes ----- Voluminous thanks to Dave "Zoid" Kirsch of id Software for supplying diffs to support Quake III. Zoid says has used QStat "from time to time" over the years. Makes me smile. And a sweeping bow to Pete Ratzlaff of Harvard for the diff to support Linux game BFRIS. See www.aegistech.com for info. I gave the diffs the wary eye for fuggly programming, but both were written nicely and applied without a hitch. I performed minimal testing of the new code, please let me know if there are problems. Steve, steve@activesw.com ** UPDATED for 2.3a BETA ** April 19, 1999 Lots of changes and additions in this release, far more than I have patience to test. Please try this release with your web page, stats program, server browser, and what not. If you encounter any problems _please_ send me email! Flames on my sloppy coding are acceptable. Summary of New Features ----------------------- Complete Half-Life support (players and server rules) Half-Life master server (option -hlm) Tribes servers (option -tbs) Tribes master server (option -tbm) Shogo (option -sgs) Hex player colors (option -hc) Several new template variables Created server types table to simplify code Bug Fixes --------- Servers without "hostname" rule appeared to TIMEOUT One or two other boo-boos Incompatible ------------ The option "-qw" has been removed. Please use "-qwm" instead. New variables for output templates ---------------------------------- Generic variables $(DEFAULTTYPE) Full name of the default server type (-default) Server variables $(ISEMPTY) True if the server has no players $(ISFULL) True if the server is full of players Player variables $(PACKETLOSS) Players packets loss (Tribes only) $(ISTEAM) True if this player represents a team (Tribes only) $(TEAMNAME) Name of this player's team (Tribes only) Notes ----- Many thanks to the following for their assistance: zarjazz@barrysworld.com Tribes seb@club-internet.fr, carl@d-n-a.net Shogo sean@msiconsulting.com Half-Life Thanks to the many people who have sent suggestions for improvements. I've incorporated some of them in this release, more will follow in later releases. This release was focused on supporting popular new games and making it easier to add new games to the code. The backlog of new games support is now empty. If there's a game you would like to see supported, please send email. The Linux game BFRIS (http://www.aegistech.com) is the only planned new game support. Steve, steve@activesw.com ** UPDATED for 2.2b ** Jan 15, 1999 D'oh! I need to do more testing. The -raw mode did not work at all for Half-Life. Thanks to Dark Grue for bring that to my attention. Bug Fixes --------- Fix Half-Life support with -raw mode Shush compiler warning on Linux Steve, steve@activesw.com ** UPDATED for 2.2a ** Jan 14, 1999 Not too much in this release, but I've been getting an email a day asking about Half-Life support. The Half-Life status packets are totally different from Quake II, so I've only completed the general info so far. Players and rules from Half-Life will be available in the next release. I also threw in flags to support Sin. Sin was supported in previous releases by pretending it was a Q2 server, but now it has its own flags. Future releases of QStat will support even more games (Shogo, Blood 2, Heretic 2, etc). Summary of New Features ----------------------- Sin support (option -sns) Half-Life (partial) support (option -hls) Bug Fixes --------- Divide-by-zero bug with sorting Memory allocation bug using -H (hostname lookup) New variables for output templates ---------------------------------- Server template variables $SIN True if the server is running Sin $HALFLIFE True if the server is running Half-Life Steve, steve@activesw.com ** UPDATED for 2.1a ** Oct 4, 1998 This release supercedes previous 2.1 releases (2.1z BETA and 2.1y BETA) Summary of New Features ----------------------- Unreal 2.15+ support (option -uns) Broadcast queries (prefix address with '+') Save lists from master servers (option -qw,outfile and -q2m,outfile) Bug Fixes --------- Fixed host cache on Intel platforms Report Host Not Found as a server error (so it appears in templates and raw output) New variables for output templates ---------------------------------- Server template variables $HOSTNOTFOUND True if the host name lookup failed Player template variables $MESH Player mesh (model) name (Unreal only) Notes ----- QStat will support the public Unreal master server once it's done. The current Unreal master server is private to GameSpy (snarl). The broadcast queries is an experimental feature. I've only tested it with Quake II. Other games will be tested and supported in later releases. For example, querying the local net for Q2 servers on the default port: qstat -q2s +255.255.255.255 The '+' makes QStat broadcast to the given address. The default broadcast address for all nets is 255.255.255.255. You can also use a network specific broadcast (eg. 199.2.18.255). On Unixes, 'ifconfig -a' will display the broadcast address for all attached networks. The ",outfile" option for master servers is handy for dealing with unreliable master server (such as the id Q2 master). Run qstat once to save the servers lists to files, and a second time to query the servers: qstat -q2m,outfile satan.idsoftware.com,idq2.lst qstat -f idq2.lst The first command saves the server list from the id Q2 master into "idq2.lst". If the master isn't working, then the file retains its previous contents. The second command queries the servers in that file. I've also included the templates for an example Unreal server list web page. Thanks to my wonderful users for reporting bugs and making suggestions. And a special thanks to the Unreal development team for actually documenting their query protocol (unlike some other well known first person shooter developers). Steve, steve@activesw.com ** UPDATED for 2.1y BETA ** Aug 22, 1998 Summary of New Features ----------------------- HexenWorld support Revived support for id's Q2 master New variables for output templates Faster host cache initialization More efficient server query (Unix only) Support for AIX 4.2 and HPUX 11.0 Bug Fixes --------- Fixed bogus query failure on second server on same IP address. Fixed to ignore QW and Q2 server packets that contain lots of error messages. Also disabled printing of the "Odd packet" messages. They can be enabled with the -errors option. Fixed output templates on Windows Non-feature ----------- Unreal support. Unreal needs to get fixed before QStat can support it. HexenWorld support ------------------ Use the -hws command line option, or the HWS server type key. Revived support for id's Q2 master ---------------------------------- id's Quake II master server was broken for a long time. QStat supported id's Q2 master, but the master only rarely returned anything (and you had to wait up to 30 seconds for a response). When QuakeSpy announced that id had fixed their Q2 master, I was surprised that QStat did not work on the fixed master. Turns out the "fix" also changed the query protocol slightly. New variables for output templates ---------------------------------- General variables $\ Inhibit output of the next newline. Server template variables $HEXENWORLD True if the server is HexenWorld (use with $IF) $UNREAL True if the server is Unreal (use with $IF) Player template variables $DEATHS Number of deaths (Unreal only) $TEAMNUM Team number (Unreal only) un-Unreal support ----------------- I implemented support for the original Unreal server status protocol. However, the Unreal server worked so poorly as to be unusable. Unreal is getting improved Internet support, but it's not ready yet. When Unreal gets fixed, QStat will support the new protocol. I've also included the templates I use for the status page of my own Quake II servers. Steve, steve@activesw.com ** UPDATED for 2.1z BETA ** Feb 28, 1998 Summary of New Features ----------------------- Output templates (HTML generation) Server sorting Host name and IP address cache Support for Quake II master New Flags --------- See the documentation (qstatdoc.html) for complete details. -default server-type Set the default server type which should be one of: QS, QW, QWM, H2S, Q2, or Q2M. -Hcache file Host name cache file -sort sort-key Sort the servers by the sort-key p sort by ping g sort by game -Tserver file Server output template. Displayed once per server. -Tplayer file Player output template. Displayed once per player (if -P is used) -Theader file Header output template. Displayed once before any servers are output -Ttrailer file Trailer output template. Displayed once after all servers and players are output. -q2m Get servers from Quake II master server Summary of Enhancements ----------------------- Remove duplicate server addresses before query Reduce memory usage when -R and/or -P are not specified Work-around a memory leak in Solaris 2.5 Wait for results from all master servers before starting to query servers VMS support Release Notes ------------- This is a major new release of QStat. There is over 1400 lines of new code with all the benefits and drawbacks therein. I hope you like the features, but I really hope it's not riddled with bugs. There might be some portability issues since I only have access to Solaris, HP-UX, Irix, and Windows NT. If you have a problem compiling, please send me a note. No major new features are planned for 2.1 beyond what you see here. However, I plan to make enhancements to the sorting and template code before final release. Please tell me what is missing. Obvious deficiencies include: - No per-server output files (can't have a server list with a link to a page with details about each server). - Missing $ELSE ($IFNOT is a cheap replacement) - Flexible $IF expressions would be nice - The output template variable syntax is kinda lame: you use $(IF:RULE(email)) to test for a rule and $(RULE:email) to output the value - Can only sort on ping and game. Would like to add map, players, etc - Can't sort the player lists - Host cache administration might be nice (re-verify command) - Host cache sharing. Use file locking to allow multiple qstats to share the same host cache. Presence on the list above does not guarantee implementation! Please tell me what you want, even if it's listed above. A host name cache can take a _long_ time to build the first time (30 minutes, minimum). I will try to keep starter cache files on the QStat web site. The current cache file for servers in the QW masters contains over 1000 entries. I've included sample output templates for HTML. They are not the best HTML, but they demonstrate some of the neat tricks you can do. If you use the templates with '-R', then server rules like email and web will be output as links next to the server. If you get player status (-P), then a subtable is output with player info formatted with the correct columns for the server type. A sample command line to use the templates: qstat -f myservers.txt -Ts template/server1.html -Th template/header1.html -Tp template/player1.html -Tt template/trailer1.html > myservers.html (The template files in qstat21z.zip have a ".htm" extension) Finally, the id Quake II master has a bug (gasp!) that makes it _very_ slow to respond some times. QStat tries to work-around the bug by increasing the retry interval by 20 times while waiting for a response from a Quake II master. The retry interval is restored once all the masters have been queried. Thank you for your support. ** UPDATED for 2.0b ** Dec 29, 1997 - Fix map name for Quake II 3.07-09 The rule key changed from "map" to "mapname". If both are present, then "mapname" takes precedence. - Q2: Noticed some servers are running custom games. The rule keys for games are confusing: "gamename" Always seems to be set to "baseq2", unless a custom game is being run, in which case "gamename" is not set at all. "gamedir" Probably the same as "*gamedir" in QW. "game" Always the same as "gamedir" in the servers I stat'd. Maybe this can be used to indicate the name as well as the version of the game being run. For now, QStat displays the value of the "game" key in the non-raw output of Q2 servers. - Print file name and line number information with errors when reading files. - new option: -progress display progress meter Thanks maynard@ultra.net Leave for the Holidays and the id boys change the protocol. A minor change, but a few QStat users noticed right away. The change does not affect people using -raw. ** UPDATED for 2.0a ** Dec 9, 1997 - Support for Quake II servers, see documentation for usage. - Minor fix to connect time formatting. I don't have Quake II, but the status protocol is very similar to QuakeWorld, so I was able to figure it out by poking existing Quake II servers on the net. Id has stated that the network protocol will get an upgrade soon after the in-store release. As always, QStat will track these changes as they become available. ** UPDATED for 1.6 ** Nov 30, 1997 Changes since beta5. Minor enhancements and a few fixes. - Removed all the annoying copyright restrictions. - Added option -ne : no empty servers Thanks secabeen@fnord.rh.uchicago.edu - Added option -raw-arg : special for QStatList (see qstat docs) Thanks darkgrue@iname.com - Added option -timeout : total time in seconds before giving up Can prevent overlapping runs when cron runs qstat every five minutes. - Added gamedir to QW server output (not -raw) - Fixed bug getting long server lists from QuakeWorld masters. Can now get lists in excess of 16,000 servers. How long til that limit is exceeded? - Fixed bug using -H with -qw - Fixed use of select() so systems with large file descriptor limits can query more than 64 servers at a time. - Overhauled the web page, but it is still gif-less. QStat 1.6 has been in alpha / beta just short of a year (1.6 alpha was released Dec 20, 1996). It has been a good year. Many thanks to those who sent suggestions, kind words, and bug reports. And appologies to those who have not seen their request implemented, or who did not even receive a reply. "Mmmgufm gumerfm rerfgmmf." "That's right, Kenny, Steve is a busy guy and doesn't care about your stupid problems." "Merfgl! gumerfm rerfgmmf!" "Dammit, Kenny, turn down the computer, I can't hear you over the splattering bodies." "Gumerfm rerfgmmf." "Oh. Kenny says, Steve does care about your problems, but not the stupid ones." [ A large core dump falls on Kenny, killing him. ] "Steve killed Kenny! You bastard!" Quake II gives me an excuse to crank up the major version dial. QStat 2.0 will feature support for Quake II servers. ** UPDATED for 1.6 beta5 ** Oct 5, 1997 Kitchen sink release to add some of the most requested features. - Extended file format. The file used with the -f option can include server type information to distinguish between Hexen II, Quake, and QuakeWorld servers. You can put all your servers into one file and query them all with one qstat invocation. - Fix bug that caused a QuakeWorld master server query to never timeout. - New option -h2s for specifying a single Hexen II server to query. - New option -maxsimultaneous limits the number of simultaneous server queries. Previously configurable by modifying the MAXFD #define in qstat.h. - Updated docs [FINALLY!] - Compiles on HP-UX 10.20 - Changed packaging: files are in a directory named for the version of qstat, and use gzip instead of compress on unix - Removed pre-QuakeWorld 1.5 support. The -qw1.5 option is obsolete and no longer needed. As are the -qwuserinfo and -qwseeninfo options. - Smarter about when to include server type prefix in formatted output Unless I hear cries for more features, this will be the last beta before the final release of qstat 1.6. Now that the docs are up to date, I've run out of excuses for doing the release. ** UPDATED for 1.6 beta4 ** Sept 2, 1997 Qstat has gone through some minor revs of beta3 and the arrival of Hexen II sparked the need for another release. Summary of fixes and changes: - Support for Hexen II servers. Use the -hexen2 mode to query Hexen II servers: qstat -hexen2 -R -P 165.166.143.15 208.131.24.189 You cannot mix queries of Quake and Hexen II servers. This limitation will be fixed in the final 1.6 release. However you can mix QW and Hexen II queries in one qstat command. [Thanks to Michael Long, mlong@infoave.net, for getting me the protocol magic for Hexen II.] - In the formatted display output (as opposed to -raw), a Hexen II server is indicated with a H2S prefix. This will only be seen if qstat is using different quake protocols at the same time (eg. query a Hexen II and QW server in the same command). - Various fixes to deal with bogus packets from QW servers. The lastest one is caused when the QW server info packet is truncated. It appears that there is a fixed buffer of 1600 bytes in the QW server for building server info responses. The QW server programmers may want to consider increasing this value. On Ethernet, two packets must be used to send 1600 bytes (Ethernet frame size 1518, subtract ~50 for header, leaving ~1468 for data). Might as well set the buffer size to ~3000 bytes so two full packets can be used. - There's some wierd problem on Linux which causes bind() to occasionally fail with EADDRINUSE. Fixed the code to consider this a transient error and retry the address at a later time. If you saw messages like: bind: Address already in use send: Invalid argument from qstat, then this fixes that. No time table for the final 1.6 release. Other than updating the docs, I don't plan any significant new features. ** The docs have not yet been updated. This is all you get for now. ** ** UPDATED for 1.6 beta3 ** April 3, 1997 D'oh! Should never do releases just after midnight. Beta2 had an old win32 executable. Also forgot to check for NULL map name in the -raw display code. Sorry! ** UPDATED for 1.6 beta2 ** April 2, 1997 Features in 1.6 beta2 beyond beta1 Fix crash on negative player colors New option -qw1.5 Use the QuakeWorld 1.5 protocol. Affects the interaction with a QW master (-qw). Fortunately, the rest of the protocol hasn't changed. I imagine the user and seen info won't be available from a QW 1.5 master. The user and seen flags will remain until I have a better understanding of where QW is going. Had to fix a bunch of crashes related to QW 1.5 servers. Some of them don't have common keys like "map". ** UPDATED for 1.6 beta1 ** Feb 7, 1997 Features in 1.6 beta1 over the 1.6 alpha releases: Changes to -qw option Support for user names and user ids Defaults values ("qstat") for user id and password. Most of the QW masters have a qstat user with "qstat" as the password. New option -qws Fetch and display stats for a single QW server. New option -qwuserinfo Fetch and display user information from a QW master. New option -qwseeninfo Fetch and display user information from a QW master. bug fix Better handling of error packets from QW servers and masters. No more "huh?" Thanks to Kris Nosack (kn@byu.edu) for comments and bug reports. ** The following has been updated to reflect the changes and ** additions in 1.6 beta1. The main feature of this release is support for QuakeWorld. A couple minor bug fixes have also been made. QuakeWorld support has been integrated into qstat. You can query normal Quake servers and QuakeWorld servers at the same time. A new prefix is used to distinguish between the different server types. New options ----------- All of these options can be used together in a single run of qstat. To query QuakeWorld servers, use the -qw or -qws options. The first will get the list of QW servers from a QW master and query all of them for status information. The latter, -qws, will just query the given QW server for status information. These options are the only way to get QuakeWorld server stats. Hosts added with -f or on the command-line are treated like normal Quake servers. -qw host:port:uid:password host host name or IP address of QW Master Server port port number (defaults to 27000 if blank) uid valid QW user id or name on host password password for user To get the server list from a master server, qstat needs a valid login on the master. A default login and password can be used if the uid and password are not given. The default is "qstat" for both values. All the known masters should have a "qstat" user with the same password. -qws host:port host host name or IP address of QW server port post number (defaults to 27500 if blank) If you don't use -qw or -qws, qstat will behave identically to qstat 1.5. I use the following command to query QW servers: qstat -qw 204.50.178.66 To get QuakeWorld user information, use the -qwuserinfo and -qwseeninfo options. A QW login is not required to get user information. -qwuserinfo host:port user-list host host name or IP address of QW Master Server port port number (defaults to 27000 if blank) user-list list of QW users (ids or names) The display for a user will include everything in their record. The color name option (-ncn) is applied to 'topcolor' and 'bottomcolor'. The user-list must be _one_ command line argument; use double-quotes to enclose multiple users if they're separated with spaces. You can also use back-slashes to separate users. -qwseeninfo host:port user-list host host name or IP address of QW Master Server port port number (defaults to 27000 if blank) user-list list of QW users (ids or names) The last seen information comes directly from the master, qstat does not perform any additional formatting. The user-list should be _one_ command line argument; use double-quotes to enclose multiple users if they're separated with spaces. You can also use back-slashes to separate users. To get user information for me and qstat and find out who was last slagging me: qstat -qwuserinfo 204.50.178.66 "Act-Steve qstat" -qwseeninfo 204.50.178.66 Act-Steve Display format -------------- The QW servers return different information than the normal servers, so I had to extend the output style. The first field of a server status line is the server type: QS normal Quake server QW QW server QWM QW master server QWU QW user information QWE QW last seen information The for-human-comsumption output is pretty self-evident, but the raw output needs some explanation. The output for normal Quake servers has not changed. QWM server status fields server address, number of QW servers [the uid and password are removed before display, no rules or player info is output] QW server status server address, server name, map name, max players, current players, avg response time, number of retries [If -R is specified, a line of server rules is output. The format is the same as for normal servers: key1=value1,key2=value2] [If -P is specified, one line is output for each player.] player uid, player name, frags, connect time, shirt color, pants color, ping, skin QWU key1, value1, key2, value2, ... [The first seven keys will always be the same; name, userid, skill, efficiency, rank, frags, deaths. But I would not count on that as I'm a fickle programmer and may change my mind.] QWE seen-info [qstat just displays the string returned by the master. The user name is embedded in there, but you'll have to parse it out.] All the existing display options apply to QW servers. Run qstat by hand to better understand the new output before trying to incorporate it into your web page. Errors ------ QStat has a variety of ways of reporting errors such as time outs and server errors. If you see something between angle brackets, , that's an error message directly from a server or master. Some day I'll document how errors are displayed in the raw format. But for now I trust you web masters can figure it out Final words ----------- This version is very beta. If you would like qstat to work differently let me know. And of course, if you have problems or questions, please let me know. Known bugs ---------- qstat often fails to get all the QW server lists if multiple QW masters are specified. You'll see a TIMEOUT or "no response" from the QWM when this happens. I have a fix in mind, but I'm tired and there's beer waiting for me at home. An error is not displayed if qstat times out getting user or last seen information. Steve Jankowski steve@activesw.com --- Version 1.5 adds player info, server rules, response times, and performance improvements. A large number of flags were added to support different output formatting options. Web masters should check out the -raw option which displays all server info with your choice of delimiter. Updated copyright to be more specific about allowable use. Updated the web page with links to Quake protocol pages. Version 1.4 includes a number of new features and bug fixes. There is now support for Linux, flags to set retry timeout and interval, flags to limit output to running or not full servers. A bug was fixed which caused qstat to have a long delay the first time it was run on Windows 95/NT. Version 1.3 fixes a bug introduced in 1.2 and adds a Windows 95/NT executable. The bug caused DOWN servers to be reported multiple times. Version 1.2 fixes the bug with running out of file descriptors. qstat-2.15/gnuconfig.h.in0000644000175000017500000000304612420766316012265 00000000000000/* gnuconfig.h.in. Generated from configure.ac by autoheader. */ /* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H /* Define to 1 if you have the `efence' library (-lefence). */ #undef HAVE_LIBEFENCE /* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H /* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H /* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H /* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H /* Define to 1 if you have the header file. */ #undef HAVE_STRING_H /* No or broken strnstr */ #undef HAVE_STRNSTR /* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H /* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H /* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the home page for this package. */ #undef PACKAGE_URL /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION qstat-2.15/tm.h0000644000175000017500000000065012420765615010320 00000000000000/* * qstat * by Steve Jankowski * * TrackMania protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_TM_H #define QSTAT_TM_H #include "qserver.h" // Packet processing methods query_status_t deal_with_tm_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_tm_request_packet( struct qserver *server ); #endif qstat-2.15/config.guess0000755000175000017500000012355012420766264012055 00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright 1992-2014 Free Software Foundation, Inc. timestamp='2014-03-23' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # # Originally written by Per Bothner. # # You can get the latest version of this script from: # http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD # # Please send patches with a ChangeLog entry to config-patches@gnu.org. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright 1992-2014 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) if (test -f /.attbin/uname) >/dev/null 2>&1 ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown case "${UNAME_SYSTEM}" in Linux|GNU|GNU/*) # If the system lacks a compiler, then just pick glibc. # We could probably try harder. LIBC=gnu eval $set_cc_for_build cat <<-EOF > $dummy.c #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc #else LIBC=gnu #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 exit $exitcode ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm*:riscos:*:*|arm*:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; s390x:SunOS:*:*) echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) echo i386-pc-auroraux${UNAME_RELEASE} exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build SUN_ARCH="i386" # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH="x86_64" fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:*:*) case "`/usr/bin/arch -k`" in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` exit ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then echo rs6000-ibm-aix3.2.4 else echo rs6000-ibm-aix3.2 fi exit ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include int main () { long cpu = sysconf (_SC_CPU_VERSION); /* The order matters, because CPU_IS_HP_MC68K erroneously returns true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct results, however. */ if (CPU_IS_PA_RISC (cpu)) { switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; default: puts ("hppa-hitachi-hiuxwe2"); break; } } else if (CPU_IS_HP_MC68K (cpu)) puts ("m68k-hitachi-hiuxwe2"); else puts ("unknown-hitachi-hiuxwe2"); exit (0); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` case ${UNAME_PROCESSOR} in amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW64*:*) echo ${UNAME_MACHINE}-pc-mingw64 exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; authenticamd | genuineintel | EM64T) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; IA64) echo ia64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; 8664:Windows_NT:*) echo x86_64-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; aarch64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC="gnulibc1" ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arm*:Linux:*:*) eval $set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then echo ${UNAME_MACHINE}-unknown-linux-${LIBC} else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi else echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf fi fi exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; cris:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; hexagon:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:Linux:*:*) echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; mips:Linux:*:* | mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef ${UNAME_MACHINE} #undef ${UNAME_MACHINE}el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=${UNAME_MACHINE}el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=${UNAME_MACHINE} #else CPU= #endif #endif EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; openrisc*:Linux:*:*) echo or1k-unknown-linux-${LIBC} exit ;; or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) echo sparc-unknown-linux-${LIBC} exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; *) echo hppa-unknown-linux-${LIBC} ;; esac exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-${LIBC} exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-${LIBC} exit ;; ppc64le:Linux:*:*) echo powerpc64le-unknown-linux-${LIBC} exit ;; ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; tile*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configury will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 fi exit ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; NCR*:*:4.2:* | MPRAS*:*:4.2:*) OS_REL='.3' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` echo ${UNAME_MACHINE}-sni-sysv4 else echo ns32k-sni-sysv fi exit ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. echo i586-pc-haiku exit ;; x86_64:Haiku:*:*) echo x86_64-unknown-haiku exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown eval $set_cc_for_build if test "$UNAME_PROCESSOR" = unknown ; then UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in i386) UNAME_PROCESSOR=x86_64 ;; powerpc) UNAME_PROCESSOR=powerpc64 ;; esac fi fi elif test "$UNAME_PROCESSOR" = i386 ; then # Avoid executing cc on OS X 10.9, as it ships with a stub # that puts up a graphical alert prompting to install # developer tools. Any system running Mac OS X 10.7 or # later (Darwin 11 and later) is required to have a 64-bit # processor. This is not true of the ARM version of Darwin # that Apple uses in portable devices. UNAME_PROCESSOR=x86_64 fi echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NEO-?:NONSTOP_KERNEL:*:*) echo neo-tandem-nsk${UNAME_RELEASE} exit ;; NSE-*:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; i*86:AROS:*:*) echo ${UNAME_MACHINE}-pc-aros exit ;; x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; esac cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: qstat-2.15/Makefile.noauto0000644000175000017500000000270112420765614012471 00000000000000## Uncomment if you have gcc #CC = gcc #CFLAGS = -Wall -g -O2 #LDFLAGS = #LDLIBS = #CFLAGS += -Dsysconfdir=\"/etc\" CFLAGS = -DDEBUG=1 -DENABLE_DUMP=1 ## NOTE: if you get errors when linking qstat (missing symbols or ## libraries), then modify LDFLAGS or LDLIBS SRC = utils.c xform.c config.c debug.c hcache.c md5.c qserver.c qstat.c template.c ut2004.c a2s.c packet_manip.c gs3.c gs2.c gps.c ts2.c doom3.c tm.c haze.c wic.c ottd.c fl.c tee.c ts3.c bfbc2.c ventrilo.c cube2.c mumble.c terraria.c crysis.c dirtybomb.c starmade.c farmsim.c ksp.c OBJ = $(SRC:.c=.obj) O = $(SRC:.c=.o) SOLARIS_LIBS = -lsocket -lnsl WINDOWS_LIBS = wsock32.lib OS2_LIBS = so32dll.lib tcp32dll.lib EMX_LIBS = -lsocket all: qstat qstat: $(O) $(CC) $(CFLAGS) -o qstat $(O) $(LDFLAGS) $(LDLIBS) solaris: $(SRC) $(CC) $(CFLAGS) -o qstat $(SRC) $(LDFLAGS) $(LDLIBS) $(SOLARIS_LIBS) aix sgi freebsd macosx osx openbsd irix linux: qstat hp hpux: $(SRC) $(CC) $(CFLAGS) -Ae -o qstat $(SRC) $(LDFLAGS) $(LDLIBS) win32: windows windows: $(OBJ) $(CC) /Feqstat.exe $(OBJ) $(LDFLAGS) $(LDLIBS) $(WINDOWS_LIBS) windows_debug: $(SRC) rm -f *.pdb $(CC) $(CFLAGS) /Zi $(SRC) /Feqstat.exe $(WINDOWS_LIBS) /link /fixed:no /incremental:no os2: $(SRC) $(CC) /Q /W0 /C+ $(SRC) ilink /PM:VIO $(OBJ) /out:qstat.exe $(LDFLAGS) $(LDLIBS) $(OS2_LIBS) os2emx: $(SRC) $(CC) $(CFLAGS) -o qstat.exe $(SRC) $(LDFLAGS) $(LDLIBS) $(EMX_LIBS) clean: rm -f qstat core qstat.exe $(O) $(OBJ) qstat-2.15/Makefile.in0000644000175000017500000010306312420766264011577 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ bin_PROGRAMS = qstat$(EXEEXT) subdir = . DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/configure $(am__configure_deps) \ $(srcdir)/gnuconfig.h.in depcomp $(dist_configfiles_DATA) \ ChangeLog compile config.guess config.sub install-sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ configure.lineno config.status.lineno mkinstalldirs = $(install_sh) -d CONFIG_HEADER = gnuconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(configfilesdir)" PROGRAMS = $(bin_PROGRAMS) am_qstat_OBJECTS = xform.$(OBJEXT) config.$(OBJEXT) debug.$(OBJEXT) \ utils.$(OBJEXT) hcache.$(OBJEXT) md5.$(OBJEXT) \ qserver.$(OBJEXT) qstat.$(OBJEXT) template.$(OBJEXT) \ a2s.$(OBJEXT) packet_manip.$(OBJEXT) ut2004.$(OBJEXT) \ doom3.$(OBJEXT) gps.$(OBJEXT) gs2.$(OBJEXT) gs3.$(OBJEXT) \ ts2.$(OBJEXT) tm.$(OBJEXT) haze.$(OBJEXT) ottd.$(OBJEXT) \ wic.$(OBJEXT) fl.$(OBJEXT) tee.$(OBJEXT) cube2.$(OBJEXT) \ ts3.$(OBJEXT) bfbc2.$(OBJEXT) ventrilo.$(OBJEXT) \ mumble.$(OBJEXT) terraria.$(OBJEXT) crysis.$(OBJEXT) \ dirtybomb.$(OBJEXT) starmade.$(OBJEXT) farmsim.$(OBJEXT) \ ksp.$(OBJEXT) qstat_OBJECTS = $(am_qstat_OBJECTS) qstat_LDADD = $(LDADD) AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = DEFAULT_INCLUDES = -I.@am__isrc@ depcomp = $(SHELL) $(top_srcdir)/depcomp am__depfiles_maybe = depfiles am__mv = mv -f COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) AM_V_CC = $(am__v_CC_@AM_V@) am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) am__v_CC_0 = @echo " CC " $@; am__v_CC_1 = CCLD = $(CC) LINK = $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ AM_V_CCLD = $(am__v_CCLD_@AM_V@) am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) am__v_CCLD_0 = @echo " CCLD " $@; am__v_CCLD_1 = SOURCES = $(qstat_SOURCES) DIST_SOURCES = $(qstat_SOURCES) RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ ctags-recursive dvi-recursive html-recursive info-recursive \ install-data-recursive install-dvi-recursive \ install-exec-recursive install-html-recursive \ install-info-recursive install-pdf-recursive \ install-ps-recursive install-recursive installcheck-recursive \ installdirs-recursive pdf-recursive ps-recursive \ tags-recursive uninstall-recursive am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; am__vpath_adj = case $$p in \ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ *) f=$$p;; \ esac; am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; am__install_max = 40 am__nobase_strip_setup = \ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` am__nobase_strip = \ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" am__nobase_list = $(am__nobase_strip_setup); \ for p in $$list; do echo "$$p $$p"; done | \ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ if (++n[$$2] == $(am__install_max)) \ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ END { for (dir in files) print dir, files[dir] }' am__base_list = \ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' am__uninstall_files_from_dir = { \ test -z "$$files" \ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ $(am__cd) "$$dir" && rm -f $$files; }; \ } DATA = $(dist_configfiles_DATA) RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ distclean-recursive maintainer-clean-recursive am__recursive_targets = \ $(RECURSIVE_TARGETS) \ $(RECURSIVE_CLEAN_TARGETS) \ $(am__extra_recursive_targets) AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ cscope distdir dist dist-all distcheck am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \ $(LISP)gnuconfig.h.in # Read a list of newline-separated strings from the standard input, # and print each of them once, without duplicates. Input order is # *not* preserved. am__uniquify_input = $(AWK) '\ BEGIN { nonempty = 0; } \ { items[$$0] = 1; nonempty = 1; } \ END { if (nonempty) { for (i in items) print i; }; } \ ' # Make sure the list of sources is unique. This is necessary because, # e.g., the same source file might be shared among _SOURCES variables # for different programs/libraries. am__define_uniq_tagged_files = \ list='$(am__tagged_files)'; \ unique=`for i in $$list; do \ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ done | $(am__uniquify_input)` ETAGS = etags CTAGS = ctags CSCOPE = cscope DIST_SUBDIRS = $(SUBDIRS) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) distdir = $(PACKAGE)-$(VERSION) top_distdir = $(distdir) am__remove_distdir = \ if test -d "$(distdir)"; then \ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ && rm -rf "$(distdir)" \ || { sleep 5 && rm -rf "$(distdir)"; }; \ else :; fi am__post_remove_distdir = $(am__remove_distdir) am__relativize = \ dir0=`pwd`; \ sed_first='s,^\([^/]*\)/.*$$,\1,'; \ sed_rest='s,^[^/]*/*,,'; \ sed_last='s,^.*/\([^/]*\)$$,\1,'; \ sed_butlast='s,/*[^/]*$$,,'; \ while test -n "$$dir1"; do \ first=`echo "$$dir1" | sed -e "$$sed_first"`; \ if test "$$first" != "."; then \ if test "$$first" = ".."; then \ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ else \ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ if test "$$first2" = "$$first"; then \ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ else \ dir2="../$$dir2"; \ fi; \ dir0="$$dir0"/"$$first"; \ fi; \ fi; \ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ done; \ reldir="$$dir2" DIST_ARCHIVES = $(distdir).tar.gz GZIP_ENV = --best DIST_TARGETS = dist-gzip distuninstallcheck_listfiles = find . -type f -print am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$' distcleancheck_listfiles = find . -type f -print ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = -Dsysconfdir=\"$(sysconfdir)\" @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ SUBDIRS = template info qstat_SOURCES = \ xform.c xform.h \ config.c config.h \ debug.c debug.h \ utils.c utils.h \ hcache.c \ md5.c md5.h \ qserver.c qserver.h \ qstat.c qstat.h \ template.c \ a2s.c a2s.h \ packet_manip.c packet_manip.h \ ut2004.c ut2004.h \ doom3.c doom3.h \ gps.c gps.h \ gs2.c gs2.h \ gs3.c gs3.h \ ts2.c ts2.h \ tm.c tm.h \ haze.c haze.h \ ottd.c ottd.h \ wic.c wic.h \ fl.c fl.h \ tee.c tee.h \ cube2.c cube2.h \ ts3.c ts3.h \ bfbc2.c bfbc2.h \ ventrilo.c ventrilo.h \ mumble.c mumble.h \ terraria.c terraria.h \ crysis.c crysis.h \ dirtybomb.c dirtybomb.h \ starmade.c starmade.h \ farmsim.c farmsim.h \ ksp.c ksp.h dist_configfiles_DATA = qstat.cfg configfilesdir = $(sysconfdir) EXTRA_DIST = CHANGES.txt COMPILE.txt LICENSE.txt \ Makefile.noauto \ ChangeLog \ qstatdoc.html \ contrib.cfg all: gnuconfig.h $(MAKE) $(AM_MAKEFLAGS) all-recursive .SUFFIXES: .SUFFIXES: .c .o .obj am--refresh: Makefile @: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \ && exit 0; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ echo ' $(SHELL) ./config.status'; \ $(SHELL) ./config.status;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) $(SHELL) ./config.status --recheck $(top_srcdir)/configure: $(am__configure_deps) $(am__cd) $(srcdir) && $(AUTOCONF) $(ACLOCAL_M4): $(am__aclocal_m4_deps) $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) $(am__aclocal_m4_deps): gnuconfig.h: stamp-h1 @test -f $@ || rm -f stamp-h1 @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 stamp-h1: $(srcdir)/gnuconfig.h.in $(top_builddir)/config.status @rm -f stamp-h1 cd $(top_builddir) && $(SHELL) ./config.status gnuconfig.h $(srcdir)/gnuconfig.h.in: $(am__configure_deps) ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) rm -f stamp-h1 touch $@ distclean-hdr: -rm -f gnuconfig.h stamp-h1 install-binPROGRAMS: $(bin_PROGRAMS) @$(NORMAL_INSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ fi; \ for p in $$list; do echo "$$p $$p"; done | \ sed 's/$(EXEEXT)$$//' | \ while read p p1; do if test -f $$p \ ; then echo "$$p"; echo "$$p"; else :; fi; \ done | \ sed -e 'p;s,.*/,,;n;h' \ -e 's|.*|.|' \ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ sed 'N;N;N;s,\n, ,g' | \ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ if ($$2 == $$4) files[d] = files[d] " " $$1; \ else { print "f", $$3 "/" $$4, $$1; } } \ END { for (d in files) print "f", d, files[d] }' | \ while read type dir files; do \ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ test -z "$$files" || { \ echo " $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ $(INSTALL_PROGRAM_ENV) $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ } \ ; done uninstall-binPROGRAMS: @$(NORMAL_UNINSTALL) @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ files=`for p in $$list; do echo "$$p"; done | \ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ -e 's/$$/$(EXEEXT)/' \ `; \ test -n "$$list" || exit 0; \ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ cd "$(DESTDIR)$(bindir)" && rm -f $$files clean-binPROGRAMS: -test -z "$(bin_PROGRAMS)" || rm -f $(bin_PROGRAMS) qstat$(EXEEXT): $(qstat_OBJECTS) $(qstat_DEPENDENCIES) $(EXTRA_qstat_DEPENDENCIES) @rm -f qstat$(EXEEXT) $(AM_V_CCLD)$(LINK) $(qstat_OBJECTS) $(qstat_LDADD) $(LIBS) mostlyclean-compile: -rm -f *.$(OBJEXT) distclean-compile: -rm -f *.tab.c @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/a2s.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bfbc2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/config.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/crysis.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cube2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/debug.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dirtybomb.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/doom3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/farmsim.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fl.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gps.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gs2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gs3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/haze.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hcache.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ksp.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/md5.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mumble.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ottd.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packet_manip.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qserver.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qstat.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/starmade.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tee.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/template.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/terraria.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tm.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ts2.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ts3.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ut2004.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ventrilo.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wic.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xform.Po@am__quote@ .c.o: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: @am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` install-dist_configfilesDATA: $(dist_configfiles_DATA) @$(NORMAL_INSTALL) @list='$(dist_configfiles_DATA)'; test -n "$(configfilesdir)" || list=; \ if test -n "$$list"; then \ echo " $(MKDIR_P) '$(DESTDIR)$(configfilesdir)'"; \ $(MKDIR_P) "$(DESTDIR)$(configfilesdir)" || exit 1; \ fi; \ for p in $$list; do \ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ echo "$$d$$p"; \ done | $(am__base_list) | \ while read files; do \ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(configfilesdir)'"; \ $(INSTALL_DATA) $$files "$(DESTDIR)$(configfilesdir)" || exit $$?; \ done uninstall-dist_configfilesDATA: @$(NORMAL_UNINSTALL) @list='$(dist_configfiles_DATA)'; test -n "$(configfilesdir)" || list=; \ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ dir='$(DESTDIR)$(configfilesdir)'; $(am__uninstall_files_from_dir) # This directory's subdirectories are mostly independent; you can cd # into them and run 'make' without going through this Makefile. # To change the values of 'make' variables: instead of editing Makefiles, # (1) if the variable is set in 'config.status', edit 'config.status' # (which will cause the Makefiles to be regenerated when you run 'make'); # (2) otherwise, pass the desired values on the 'make' command line. $(am__recursive_targets): @fail=; \ if $(am__make_keepgoing); then \ failcom='fail=yes'; \ else \ failcom='exit 1'; \ fi; \ dot_seen=no; \ target=`echo $@ | sed s/-recursive//`; \ case "$@" in \ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ *) list='$(SUBDIRS)' ;; \ esac; \ for subdir in $$list; do \ echo "Making $$target in $$subdir"; \ if test "$$subdir" = "."; then \ dot_seen=yes; \ local_target="$$target-am"; \ else \ local_target="$$target"; \ fi; \ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ || eval $$failcom; \ done; \ if test "$$dot_seen" = "no"; then \ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ fi; test -z "$$fail" ID: $(am__tagged_files) $(am__define_uniq_tagged_files); mkid -fID $$unique tags: tags-recursive TAGS: tags tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) set x; \ here=`pwd`; \ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ include_option=--etags-include; \ empty_fix=.; \ else \ include_option=--include; \ empty_fix=; \ fi; \ list='$(SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ test ! -f $$subdir/TAGS || \ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ fi; \ done; \ $(am__define_uniq_tagged_files); \ shift; \ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ test -n "$$unique" || unique=$$empty_fix; \ if test $$# -gt 0; then \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ "$$@" $$unique; \ else \ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ $$unique; \ fi; \ fi ctags: ctags-recursive CTAGS: ctags ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) $(am__define_uniq_tagged_files); \ test -z "$(CTAGS_ARGS)$$unique" \ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ $$unique GTAGS: here=`$(am__cd) $(top_builddir) && pwd` \ && $(am__cd) $(top_srcdir) \ && gtags -i $(GTAGS_ARGS) "$$here" cscope: cscope.files test ! -s cscope.files \ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS) clean-cscope: -rm -f cscope.files cscope.files: clean-cscope cscopelist cscopelist: cscopelist-recursive cscopelist-am: $(am__tagged_files) list='$(am__tagged_files)'; \ case "$(srcdir)" in \ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ *) sdir=$(subdir)/$(srcdir) ;; \ esac; \ for i in $$list; do \ if test -f "$$i"; then \ echo "$(subdir)/$$i"; \ else \ echo "$$sdir/$$i"; \ fi; \ done >> $(top_builddir)/cscope.files distclean-tags: -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags -rm -f cscope.out cscope.in.out cscope.po.out cscope.files distdir: $(DISTFILES) $(am__remove_distdir) test -d "$(distdir)" || mkdir "$(distdir)" @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ if test "$$subdir" = .; then :; else \ $(am__make_dryrun) \ || test -d "$(distdir)/$$subdir" \ || $(MKDIR_P) "$(distdir)/$$subdir" \ || exit 1; \ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ $(am__relativize); \ new_distdir=$$reldir; \ dir1=$$subdir; dir2="$(top_distdir)"; \ $(am__relativize); \ new_top_distdir=$$reldir; \ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ ($(am__cd) $$subdir && \ $(MAKE) $(AM_MAKEFLAGS) \ top_distdir="$$new_top_distdir" \ distdir="$$new_distdir" \ am__remove_distdir=: \ am__skip_length_check=: \ am__skip_mode_fix=: \ distdir) \ || exit 1; \ fi; \ done -test -n "$(am__skip_mode_fix)" \ || find "$(distdir)" -type d ! -perm -755 \ -exec chmod u+rwx,go+rx {} \; -o \ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ || chmod -R a+r "$(distdir)" dist-gzip: distdir tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz $(am__post_remove_distdir) dist-bzip2: distdir tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2 $(am__post_remove_distdir) dist-lzip: distdir tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz $(am__post_remove_distdir) dist-xz: distdir tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz $(am__post_remove_distdir) dist-tarZ: distdir @echo WARNING: "Support for shar distribution archives is" \ "deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z $(am__post_remove_distdir) dist-shar: distdir @echo WARNING: "Support for distribution archives compressed with" \ "legacy program 'compress' is deprecated." >&2 @echo WARNING: "It will be removed altogether in Automake 2.0" >&2 shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz $(am__post_remove_distdir) dist-zip: distdir -rm -f $(distdir).zip zip -rq $(distdir).zip $(distdir) $(am__post_remove_distdir) dist dist-all: $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:' $(am__post_remove_distdir) # This target untars the dist file and tries a VPATH configuration. Then # it guarantees that the distribution is self-contained by making another # tarfile. distcheck: dist case '$(DIST_ARCHIVES)' in \ *.tar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ *.tar.bz2*) \ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ *.tar.lz*) \ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\ *.tar.xz*) \ xz -dc $(distdir).tar.xz | $(am__untar) ;;\ *.tar.Z*) \ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ *.shar.gz*) \ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ *.zip*) \ unzip $(distdir).zip ;;\ esac chmod -R a-w $(distdir) chmod u+w $(distdir) mkdir $(distdir)/_build $(distdir)/_inst chmod a-w $(distdir) test -d $(distdir)/_build || exit 0; \ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ && am__cwd=`pwd` \ && $(am__cd) $(distdir)/_build \ && ../configure \ $(AM_DISTCHECK_CONFIGURE_FLAGS) \ $(DISTCHECK_CONFIGURE_FLAGS) \ --srcdir=.. --prefix="$$dc_install_base" \ && $(MAKE) $(AM_MAKEFLAGS) \ && $(MAKE) $(AM_MAKEFLAGS) dvi \ && $(MAKE) $(AM_MAKEFLAGS) check \ && $(MAKE) $(AM_MAKEFLAGS) install \ && $(MAKE) $(AM_MAKEFLAGS) installcheck \ && $(MAKE) $(AM_MAKEFLAGS) uninstall \ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ distuninstallcheck \ && chmod -R a-w "$$dc_install_base" \ && ({ \ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ } || { rm -rf "$$dc_destdir"; exit 1; }) \ && rm -rf "$$dc_destdir" \ && $(MAKE) $(AM_MAKEFLAGS) dist \ && rm -rf $(DIST_ARCHIVES) \ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ && cd "$$am__cwd" \ || exit 1 $(am__post_remove_distdir) @(echo "$(distdir) archives ready for distribution: "; \ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' distuninstallcheck: @test -n '$(distuninstallcheck_dir)' || { \ echo 'ERROR: trying to run $@ with an empty' \ '$$(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ $(am__cd) '$(distuninstallcheck_dir)' || { \ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \ exit 1; \ }; \ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left after uninstall:" ; \ if test -n "$(DESTDIR)"; then \ echo " (check DESTDIR support)"; \ fi ; \ $(distuninstallcheck_listfiles) ; \ exit 1; } >&2 distcleancheck: distclean @if test '$(srcdir)' = . ; then \ echo "ERROR: distcleancheck can only run from a VPATH build" ; \ exit 1 ; \ fi @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ || { echo "ERROR: files left in build directory after distclean:" ; \ $(distcleancheck_listfiles) ; \ exit 1; } >&2 check-am: all-am check: check-recursive all-am: Makefile $(PROGRAMS) $(DATA) gnuconfig.h installdirs: installdirs-recursive installdirs-am: for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(configfilesdir)"; do \ test -z "$$dir" || $(MKDIR_P) "$$dir"; \ done install: install-recursive install-exec: install-exec-recursive install-data: install-data-recursive uninstall: uninstall-recursive install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-recursive install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-recursive clean-am: clean-binPROGRAMS clean-generic mostlyclean-am distclean: distclean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf ./$(DEPDIR) -rm -f Makefile distclean-am: clean-am distclean-compile distclean-generic \ distclean-hdr distclean-tags dvi: dvi-recursive dvi-am: html: html-recursive html-am: info: info-recursive info-am: install-data-am: install-dist_configfilesDATA install-dvi: install-dvi-recursive install-dvi-am: install-exec-am: install-binPROGRAMS install-html: install-html-recursive install-html-am: install-info: install-info-recursive install-info-am: install-man: install-pdf: install-pdf-recursive install-pdf-am: install-ps: install-ps-recursive install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-recursive -rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -rf $(top_srcdir)/autom4te.cache -rm -rf ./$(DEPDIR) -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-recursive mostlyclean-am: mostlyclean-compile mostlyclean-generic pdf: pdf-recursive pdf-am: ps: ps-recursive ps-am: uninstall-am: uninstall-binPROGRAMS uninstall-dist_configfilesDATA .MAKE: $(am__recursive_targets) all install-am install-strip .PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ am--refresh check check-am clean clean-binPROGRAMS \ clean-cscope clean-generic cscope cscopelist-am ctags ctags-am \ dist dist-all dist-bzip2 dist-gzip dist-lzip dist-shar \ dist-tarZ dist-xz dist-zip distcheck distclean \ distclean-compile distclean-generic distclean-hdr \ distclean-tags distcleancheck distdir distuninstallcheck dvi \ dvi-am html html-am info info-am install install-am \ install-binPROGRAMS install-data install-data-am \ install-dist_configfilesDATA install-dvi install-dvi-am \ install-exec install-exec-am install-html install-html-am \ install-info install-info-am install-man install-pdf \ install-pdf-am install-ps install-ps-am install-strip \ installcheck installcheck-am installdirs installdirs-am \ maintainer-clean maintainer-clean-generic mostlyclean \ mostlyclean-compile mostlyclean-generic pdf pdf-am ps ps-am \ tags tags-am uninstall uninstall-am uninstall-binPROGRAMS \ uninstall-dist_configfilesDATA cl: cvs2cl.pl --utc --no-wrap --separate-header --no-times -f ChangeLog.cvs rm -f ChangeLog.cvs.bak qstat.core # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: qstat-2.15/haze.h0000644000175000017500000000120412420765615010623 00000000000000/* * qstat * by Steve Jankowski * * New Haze query protocol * Copyright 2007 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_HAZE_H #define QSTAT_HAZE_H #include "qserver.h" #define HAZE_BASIC_INFO 0x01 #define HAZE_GAME_RULES 0x02 #define HAZE_PLAYER_INFO 0x04 #define HAZE_TEAM_INFO 0x08 // Packet processing methods query_status_t deal_with_haze_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t deal_with_haze_status( struct qserver *server, char *rawpkt, int pktlen ); query_status_t send_haze_request_packet( struct qserver *server ); #endif qstat-2.15/config.c0000644000175000017500000006115012420765614011141 00000000000000/* * qstat * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Copyright 1996,1997,1998,1999 by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #include #include #include #include "config.h" #ifdef __hpux #define STATIC static #else #define STATIC #endif #ifdef _WIN32 #define strcasecmp stricmp #endif #ifdef _WIN32 #define HOME_CONFIG_FILE "qstat.cfg" #else #define HOME_CONFIG_FILE ".qstatrc" #endif static server_type ** config_types; static int n_config_types; static int max_config_types; static int next_gametype_id= LAST_BUILTIN_SERVER+1; static int load_config_file(char const* filename); static int try_load_config_file(char const* filename, int const show_error); static int pf_top_level( char *text, void *context); static int pf_gametype_new( char *text, void *context); static int pf_gametype_modify( char *text, void *context); static int set_game_type_value( server_type *gametype, int key, char *value); static int modify_game_type_value( server_type *gametype, int key, char *value); static int set_packet_value(server_type* gametype, char const* value, char const* packet_name, char** packet, int* len); static char *first_token( char *text); static char *next_token(); static char *next_token_dup(); static char *next_value(); static char * parse_value( char *source, int len); static unsigned int parse_hex( char *hex, int len, int *error); static unsigned int parse_oct( char *oct, int len, int *error); static char *force_lower_case( char *string); static char *force_upper_case( char *string); static char *get_token(); static void *memdup( const void *mem, unsigned int len); int parse_config_file( FILE *file); static int (*parse_func)( char *, void *); static void *parse_context; static int line; static char const* current_file_name; static char *parse_text; static char *parse_end; static char *lex; static char *token_end; static char token_buf[1024]; static int value_len; static int debug= 0; #define REPORT_ERROR(a) print_location(); fprintf a; fprintf(stderr, "\n") enum { CK_NONE = 0, CK_MASTER_PROTOCOL, CK_MASTER_QUERY, CK_MASTER_PACKET, CK_FLAGS, CK_NAME, CK_DEFAULT_PORT, CK_GAME_RULE, CK_TEMPLATE_VAR, CK_MASTER_TYPE, CK_STATUS_PACKET, CK_STATUS2_PACKET, CK_PLAYER_PACKET, CK_RULE_PACKET, CK_PORT_OFFSET }; typedef struct _config_key { int key; char *key_name; } ConfigKey; static ConfigKey const new_keys[] = { { CK_MASTER_PROTOCOL, "master protocol" }, { CK_MASTER_QUERY, "master query" }, { CK_MASTER_PACKET, "master packet" }, { CK_FLAGS, "flags" }, { CK_NAME, "name" }, { CK_DEFAULT_PORT, "default port" }, { CK_GAME_RULE, "game rule" }, { CK_TEMPLATE_VAR, "template var" }, { CK_MASTER_TYPE, "master for gametype" }, { CK_STATUS_PACKET, "status packet" }, { CK_STATUS2_PACKET, "status2 packet" }, { CK_PLAYER_PACKET, "player packet" }, { CK_RULE_PACKET, "rule packet" }, { CK_PORT_OFFSET, "status port offset" }, { 0, NULL }, }; static ConfigKey const modify_keys[] = { { CK_MASTER_PROTOCOL, "master protocol" }, { CK_MASTER_QUERY, "master query" }, { CK_MASTER_PACKET, "master packet" }, { CK_FLAGS, "flags" }, { CK_MASTER_TYPE, "master for gametype" }, { 0, NULL }, }; typedef struct { const char *name; int value; } ServerFlag; #define SERVER_FLAG(x) { #x, x } ServerFlag const server_flags[] = { SERVER_FLAG(TF_SINGLE_QUERY), SERVER_FLAG(TF_OUTFILE), SERVER_FLAG(TF_MASTER_MULTI_RESPONSE), SERVER_FLAG(TF_TCP_CONNECT), SERVER_FLAG(TF_QUERY_ARG), SERVER_FLAG(TF_QUERY_ARG_REQUIRED), SERVER_FLAG(TF_QUAKE3_NAMES), SERVER_FLAG(TF_TRIBES2_NAMES), SERVER_FLAG(TF_SOF_NAMES), SERVER_FLAG(TF_U2_NAMES), SERVER_FLAG(TF_RAW_STYLE_QUAKE), SERVER_FLAG(TF_RAW_STYLE_TRIBES), SERVER_FLAG(TF_RAW_STYLE_GHOSTRECON), SERVER_FLAG(TF_NO_PORT_OFFSET), SERVER_FLAG(TF_SHOW_GAME_PORT), { NULL, 0 } }; #undef SERVER_FLAG static int get_config_key( char *first_token, const ConfigKey *keys); static void add_config_type( server_type *gametype); static server_type * get_config_type( char *game_type); static void copy_server_type( server_type *dest, server_type *source); static server_type * get_server_type( char *game_type); static server_type * get_builtin_type( char *game_type); typedef struct _gametype_context { char *type; char *extend_type; server_type *gametype; } GameTypeContext; static void print_location() { fprintf( stderr, "%s line %d: ", current_file_name, line); } int qsc_load_default_config_files() { int rc= 0; char *filename= NULL, *var; char path[1024]; var= getenv( "QSTAT_CONFIG"); if ( var != NULL && var[0] != '\0') { rc= try_load_config_file( var, 1); if ( rc == 0 || rc == -1) return rc; } var= getenv( "HOME"); if ( var != NULL && var[0] != '\0') { int len= strlen(var); if ( len > 900) len= 900; strncpy( path, var, len); path[len]= '\0'; strcat( path, "/"); strcat( path, HOME_CONFIG_FILE); /* sprintf( path, "%s/%s", var, HOME_CONFIG_FILE); */ rc= try_load_config_file( path, 0); if ( rc == 0 || rc == -1) return rc; } #ifdef sysconfdir strcpy( path, sysconfdir "/qstat.cfg"); filename= path; #elif defined(_WIN32) if ( filename == NULL && _pgmptr && strchr( _pgmptr, '\\')) { char *slash= strrchr( _pgmptr, '\\'); strncpy( path, _pgmptr, slash - _pgmptr); path[slash - _pgmptr]= '\0'; strcat( path, "\\qstat.cfg"); filename= path; } #endif if ( filename != NULL) { rc= try_load_config_file( filename, 0); if ( rc == 0 || rc == -1) return rc; } return rc; /* if ( rc == -2 && show_error) { perror( filename); fprintf( stderr, "Error: Could not open config file \"%s\"\n", filename); } else if ( rc == -1 && show_error) fprintf( stderr, "Error: Error loading $QSTAT_CONFIG file\n"); return rc; */ #ifdef foo filename= getenv( "HOME"); if ( filename != NULL && filename[0] != '\0') { char path[1024]; snprintf( path, (sizeof(path) -1),"%s/%s", var, HOME_CONFIG_FILE); } /* 1. $QSTAT_CONFIG 2. UNIX: $HOME/.qstatrc WIN: $HOME/qstat.cfg 3. UNIX: sysconfdir/qstat.cfg WIN: qstat.exe-dir/qstat.cfg */ rc= load_config_file( "qstat.cfg"); if ( rc == -1) fprintf( stderr, "Warning: Error loading default qstat.cfg\n"); return 0; #endif } int qsc_load_config_file(char const* filename) { int rc= load_config_file( filename); if ( rc == -2) { perror( filename); fprintf( stderr, "Could not open config file \"%s\"\n", filename); return -1; } return rc; } server_type ** qsc_get_config_server_types( int *n_config_types_ref) { if ( n_config_types_ref) *n_config_types_ref= n_config_types; return config_types; } STATIC int try_load_config_file(char const* filename, int const show_error) { int rc= load_config_file( filename); if ( rc == -2 && show_error) { perror( filename); fprintf( stderr, "Error: Could not open config file \"%s\"\n", filename); } else if ( rc == -1) fprintf( stderr, "Error: Could not load config file \"%s\"\n", filename); return rc; } STATIC int load_config_file(char const* filename) { FILE *file; int rc; file= fopen( filename, "r"); if ( file == NULL) return -2; current_file_name= filename; rc= parse_config_file( file); fclose(file); return rc; } int parse_config_file( FILE *file) { char buf[4096]; int rc; line= 0; parse_func= pf_top_level; while ( fgets( buf, sizeof(buf), file) != NULL) { int len= strlen(buf); while ( len && (buf[len-1] == '\n' || buf[len-1] == '\r')) len--; buf[len]= '\0'; line++; rc= parse_func( buf, parse_context); if ( rc != 0) return rc; } return 0; } /* Top level * Keywords: gametype */ STATIC int pf_top_level( char *text, void *_context) { GameTypeContext *context; server_type *extend; char *token, *game_type, *extend_type; token= first_token( text); if ( token == NULL) return 0; if ( strcmp( token, "gametype") != 0) { REPORT_ERROR(( stderr, "Unknown config command \"%s\"", token)); return -1; } game_type= next_token_dup(); if ( game_type == NULL) { REPORT_ERROR(( stderr, "Missing game type")); return -1; } force_lower_case( game_type); token= next_token(); if ( token == NULL) { REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\"")); return -1; } if ( strcmp( token, "new") == 0) { parse_func= pf_gametype_new; } else if ( strcmp( token, "modify") == 0) { parse_func= pf_gametype_modify; } else { REPORT_ERROR(( stderr, "Expecting \"new\" or \"modify\"")); return -1; } context= (GameTypeContext*) malloc( sizeof(GameTypeContext)); context->type= game_type; context->extend_type= NULL; context->gametype= NULL; token= next_token(); if ( parse_func == pf_gametype_modify) { if ( token != NULL) { REPORT_ERROR(( stderr, "Extra text after gametype modify")); return -1; } context->gametype= get_server_type( game_type); if ( context->gametype == NULL) { REPORT_ERROR(( stderr, "Unknown game type \"%s\"", game_type)); free(context); return -1; } parse_context= context; return 0; } if ( token == NULL || strcmp( token, "extend") != 0) { REPORT_ERROR(( stderr, "Expecting \"extend\"")); return -1; } extend_type= next_token(); if ( extend_type == NULL) { REPORT_ERROR(( stderr, "Missing extend game type")); return -1; } force_lower_case( extend_type); if ( strcasecmp( extend_type, game_type) == 0) { REPORT_ERROR(( stderr, "Identical game type and extend type")); return -1; } context->extend_type= extend_type; extend= get_server_type( extend_type); if ( extend == NULL) { REPORT_ERROR(( stderr, "Unknown extend game type \"%s\"", extend_type)); return -1; } /* Over-write a previous gametype new */ context->gametype= get_config_type( game_type); if ( context->gametype == NULL) context->gametype= (server_type*) malloc( sizeof(server_type)); copy_server_type( context->gametype, extend); /* Set flag for new type-id if not re-defining previous config type */ if ( get_config_type( game_type) == NULL) context->gametype->id= 0; context->gametype->type_string= game_type; context->gametype->type_prefix= strdup(game_type); force_upper_case( context->gametype->type_prefix); context->gametype->type_option= (char*)malloc( strlen(game_type)+2); context->gametype->type_option[0]= '-'; strcpy( &context->gametype->type_option[1], game_type); parse_context= context; return 0; } STATIC int pf_gametype_modify( char *text, void *_context) { GameTypeContext *context= (GameTypeContext*) _context; char *token; int key; token= first_token( text); if ( token == NULL) return 0; if ( strcmp( token, "end") == 0) { parse_func= pf_top_level; parse_context= NULL; return 0; } key= get_config_key( token, modify_keys); token= next_token(); if ( strcmp( token, "=") != 0) { REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token)); return -1; } token= next_value(); if ( token == NULL) { REPORT_ERROR(( stderr, "Missing value after \"=\"")); return -1; } if ( debug) printf( "%d %s = <%s>\n", key, modify_keys[key-1].key_name, token?token:""); return modify_game_type_value( context->gametype, key, token); } STATIC int pf_gametype_new( char *text, void *_context) { GameTypeContext *context= (GameTypeContext*) _context; char *token; int key; token= first_token( text); if ( token == NULL) return 0; if ( strcmp( token, "end") == 0) { add_config_type( context->gametype); parse_func= pf_top_level; parse_context= NULL; return 0; } key= get_config_key( token, new_keys); if ( key <= 0) return key; token= next_token(); if ( strcmp( token, "=") != 0) { REPORT_ERROR(( stderr, "Expecting \"=\", found \"%s\"", token)); return -1; } token= next_value(); if ( token == NULL && (key != CK_MASTER_PROTOCOL && key != CK_MASTER_QUERY)) { REPORT_ERROR(( stderr, "Missing value after \"=\"")); return -1; } if ( debug) printf("%d %s = <%s>\n", key, new_keys[key-1].key_name, token?token:""); return set_game_type_value( context->gametype, key, token); } STATIC int get_config_key( char *first_token, const ConfigKey *keys) { char key_name[1024], *token; int key= 0; strcpy( key_name, first_token); do { int k; for ( k= 0; keys[k].key_name; k++) { if ( strcmp( keys[k].key_name, key_name) == 0) { key= keys[k].key; break; } } if ( key) break; token= next_token(); if ( token == NULL || strcmp( token, "=") == 0) break; if ( strlen(key_name) + strlen(token) > sizeof(key_name)-2) { REPORT_ERROR(( stderr, "Key name too long")); return -1; } strcat( key_name, " "); strcat( key_name, token); } while ( 1); if ( key == 0) { REPORT_ERROR(( stderr, "Unknown config key \"%s\"", key_name)); return -1; } return key; } STATIC int get_server_flag_value(const char* value, unsigned len) { int i= 0; for ( i= 0; server_flags[i].name; ++i) { if ( len == strlen(server_flags[i].name) && strncmp( server_flags[i].name, value, len) == 0) { return server_flags[i].value; } } return -1; } STATIC int parse_server_flags(const char* value) { int val = 0, v, first = 1; const char* s = value; const char* e; while(*s) { while(isspace((unsigned char)*s)) ++s; if(!first) { if(*s != '|') { REPORT_ERROR(( stderr, "Syntax error: expecting |")); val = -1; break; } ++s; while(isspace((unsigned char)*s)) ++s; } else first = 0; e = s; while(isalnum((unsigned char)*e) || *e == '_') ++e; if(e == s) { REPORT_ERROR(( stderr, "Syntax error: expecting flag")); val = -1; break; } v = get_server_flag_value(s, e-s); if(v == -1) { REPORT_ERROR(( stderr, "Syntax error: invalid flag")); val = -1; break; } s = e; val |= v; } return val; } STATIC int set_game_type_value( server_type *gametype, int key, char *value) { switch ( key) { case CK_NAME: gametype->game_name= strdup(value); break; case CK_FLAGS: { int flags = parse_server_flags(value); if(flags == -1) return -1; gametype->flags = flags; } break; case CK_DEFAULT_PORT: { unsigned short port; if ( sscanf( value, "%hu", &port) != 1) { REPORT_ERROR(( stderr, "Syntax error on port. Should be a number between 1 and 65535.")); return -1; } gametype->default_port= port; break; } case CK_GAME_RULE: gametype->game_rule= strdup(value); break; case CK_TEMPLATE_VAR: gametype->template_var= strdup(value); force_upper_case( gametype->template_var); break; case CK_MASTER_PROTOCOL: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type\n")); return -1; } if ( value) gametype->master_protocol= strdup(value); else gametype->master_protocol= NULL; break; case CK_MASTER_QUERY: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master query on non-master game type\n")); return -1; } if ( value) gametype->master_query= strdup(value); else gametype->master_query= NULL; break; case CK_MASTER_TYPE: { server_type *type; if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master type on non-master game type\n")); return -1; } force_lower_case( value); type= get_server_type( value); if ( type == NULL) { REPORT_ERROR((stderr, "Unknown server type \"%s\"\n", value)); return -1; } gametype->master= type->id; } break; case CK_MASTER_PACKET: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master packet on non-master game type")); return -1; } if ( value == NULL || value[0] == '\0') { REPORT_ERROR((stderr, "Empty master packet")); return -1; } gametype->master_packet= memdup( value, value_len); gametype->master_len= value_len; break; case CK_STATUS_PACKET: return set_packet_value( gametype, value, "status", &gametype->status_packet, &gametype->status_len); case CK_STATUS2_PACKET: return set_packet_value( gametype, value, "status2", &gametype->rule_packet, &gametype->rule_len); case CK_PLAYER_PACKET: return set_packet_value( gametype, value, "player", &gametype->player_packet, &gametype->player_len); case CK_RULE_PACKET: return set_packet_value( gametype, value, "rule", &gametype->rule_packet, &gametype->rule_len); case CK_PORT_OFFSET: { short port; if ( sscanf( value, "%hd", &port) != 1) { REPORT_ERROR(( stderr, "Syntax error on port. Should be a number between 32767 and -32768.")); return -1; } gametype->port_offset= port; break; } } return 0; } STATIC int set_packet_value(server_type* gametype, char const* value, char const* packet_name, char **packet, int *len) { if ( gametype->master) { REPORT_ERROR((stderr, "Cannot set info packet on master game type")); return -1; } if ( value == NULL || value[0] == '\0') { REPORT_ERROR((stderr, "Empty %s packet", packet_name)); return -1; } // Removed as this doesn't seem to be any reason why we can't do this and it works just fine for warsow //if ( *packet == NULL) { // REPORT_ERROR((stderr, "Cannot set %s packet; extend game type does not define a %s packet", packet_name, packet_name)); // return -1; //} *packet= memdup( value, value_len); *len= value_len; return 0; } STATIC int modify_game_type_value( server_type *gametype, int key, char *value) { switch ( key) { case CK_FLAGS: { int flags = parse_server_flags(value); if(flags == -1) return -1; gametype->flags = flags; } break; case CK_MASTER_PROTOCOL: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master protocol on non-master game type")); return -1; } if ( value) gametype->master_protocol= strdup(value); else gametype->master_protocol= NULL; break; case CK_MASTER_QUERY: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master query on non-master game type")); return -1; } if ( value) gametype->master_query= strdup(value); else gametype->master_query= NULL; break; case CK_MASTER_PACKET: if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master packet on non-master game type")); return -1; } if ( value == NULL || value[0] == '\0') { REPORT_ERROR((stderr, "Empty master packet")); return -1; } gametype->master_packet= memdup( value, value_len); gametype->master_len= value_len; break; case CK_MASTER_TYPE: { server_type *type; if ( ! gametype->master) { REPORT_ERROR((stderr, "Cannot set master type on non-master game type\n")); return -1; } force_lower_case( value); type= get_server_type( value); if ( type == NULL) { REPORT_ERROR((stderr, "Unknown server type \"%s\"\n", value)); return -1; } gametype->master= type->id; } break; } return 0; } STATIC server_type * get_server_type( char *game_type) { server_type *result; result= get_builtin_type( game_type); if ( result != NULL) return result; return get_config_type( game_type); } STATIC server_type* get_builtin_type( char* type_string) { server_type *type= &builtin_types[0]; for ( ; type->id != Q_UNKNOWN_TYPE; type++) if ( strcmp( type->type_string, type_string) == 0) return type; return NULL; } STATIC void add_config_type( server_type *gametype) { if ( gametype->id == 0) { if ( next_gametype_id >= MASTER_SERVER) { REPORT_ERROR(( stderr, "Exceeded game type limit, ignoring \"%s\"", gametype->type_string)); return; } gametype->id= next_gametype_id; if ( gametype->master) gametype->id |= MASTER_SERVER; next_gametype_id++; } if ( max_config_types == 0) { max_config_types= 4; config_types= (server_type**) malloc(sizeof(server_type*) * (max_config_types + 1)); } else if ( n_config_types >= max_config_types) { max_config_types*= 2; config_types= (server_type**) realloc( config_types, sizeof(server_type*) * (max_config_types + 1)); } config_types[ n_config_types]= gametype; n_config_types++; } STATIC server_type * get_config_type( char *game_type) { int i; for ( i= 0; i < n_config_types; i++) if ( strcmp( config_types[i]->type_string, game_type) == 0) return config_types[i]; return NULL; } STATIC void copy_server_type( server_type *dest, server_type *source) { *dest= *source; } STATIC void * memdup( const void *mem, unsigned int len) { void *result= malloc( len); if ( NULL == result ) { REPORT_ERROR(( stderr, "Failed to malloc %d bytes of memory", len ) ); return NULL; } memcpy( result, mem, len); return result; } /* Parsing primitives */ STATIC char * first_token( char *text) { parse_text= text; parse_end= parse_text + strlen( parse_text); lex= text; token_end= text; if ( *lex == '#') return NULL; return get_token(); } STATIC char * next_token() { lex= token_end; return get_token(); } STATIC char * next_token_dup() { return strdup( next_token()); } STATIC char * get_token() { char *token= &token_buf[0]; while ( isspace((unsigned char)*token_end)) token_end++; if ( token_end == parse_end) return NULL; while ( (isalnum((unsigned char)*token_end) || *token_end == '.' || *token_end == '_' || *token_end == '-') && token < &token_buf[0] + sizeof(token_buf)) *token++= *token_end++; if ( token == &token_buf[0]) *token++= *token_end++; *token= '\0'; return &token_buf[0]; } STATIC char * next_value() { char *token= &token_buf[0]; while ( isspace((unsigned char)*token_end)) token_end++; if ( token_end == parse_end) return NULL; while ( token_end < parse_end && token < &token_buf[0] + sizeof(token_buf)) *token++= *token_end++; *token--= '\0'; if ( strchr( token_buf, '\\')) return parse_value(token_buf, (token - token_buf)+1); while ( isspace((unsigned char)*token)) *token--= '\0'; value_len= token - token_buf + 1; return &token_buf[0]; } STATIC char * parse_value( char *source, int len) { char *value, *v, *end; int error= 0; value= (char*)malloc( len + 1); end = v = value; /* printf( "parse_value <%.*s>\n", len, source); */ for ( ; len; len--, source++) { if ( *source != '\\') { *v++= *source; if ( *source != ' ') end= v; continue; } source++; len--; if ( len == 0) break; if ( *source == '\\') *v++= *source; else if ( *source == 'n') *v++= '\n'; else if ( *source == 'r') *v++= '\r'; else if ( *source == ' ') *v++= ' '; else if ( *source == 'x') { source++; len--; if ( len < 2) break; *v++= parse_hex(source, 2, &error); if ( error) break; source++; len--; } else if ( isdigit( (unsigned char)*source)) { if ( len < 3) break; *v++= parse_oct(source, 3, &error); if ( error) break; source++; len--; source++; len--; } else { error= 1; REPORT_ERROR(( stderr, "Invalid character escape \"%.*s\"", 2, source-1)); break; } end= v; } if ( error) { free(value); return NULL; } value_len= end - value; memcpy( token_buf, value, value_len); token_buf[value_len]= '\0'; free(value); return &token_buf[0]; } STATIC unsigned int parse_hex( char *hex, int len, int *error) { char *save_hex= hex; int save_len= len; unsigned int result= 0; *error= 0; for ( ; len; len--, hex++) { result <<= 4; if ( ! isxdigit( (unsigned char)*hex)) { *error= 1; REPORT_ERROR(( stderr, "Invalid hex \"%.*s\"", save_len+2, save_hex-2)); return 0; } if ( *hex >= '0' && *hex <= '9') result|= *hex - '0'; else if ( *hex >= 'A' && *hex <= 'F') result|= ((*hex - 'A') + 10); else if ( *hex >= 'a' && *hex <= 'f') result|= ((*hex - 'a') + 10); } return result; } STATIC unsigned int parse_oct( char *oct, int len, int *error) { char *save_oct= oct; int save_len= len; unsigned int result= 0; *error= 0; for ( ; len; len--, oct++) { result <<= 3; if ( *oct >= '0' && *oct <= '7') result|= *oct - '0'; else { *error= 1; REPORT_ERROR(( stderr, "Invalid octal \"%.*s\"", save_len+1, save_oct-1)); return 0; } } return result; } STATIC char * force_lower_case( char *string) { char *s= string; for ( ; *s; s++) *s= tolower(*s); return string; } STATIC char * force_upper_case( char *string) { char *s= string; for ( ; *s; s++) *s= toupper(*s); return string; } qstat-2.15/utils.h0000644000175000017500000000231312420765614011035 00000000000000/* * Utility Functions * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_UTILS_H #define QSTAT_UTILS_H // BSD has strnstr #if defined(__FreeBSD__) || defined(__MidnightBSD__) || defined(__OpenBSD__) #ifndef HAVE_STRNSTR #define HAVE_STRNSTR 1 #endif /* HAVE_STRNSTR */ #endif #ifndef _WIN32 #ifndef HAVE_ERR_H #define HAVE_ERR_H 1 #endif /* HAVE_ERR */ #endif #if !HAVE_STRNSTR #include char * qstat_strnstr(const char *s, const char *find, size_t slen); #define strnstr(s,find,slen) qstat_strnstr(s,find,slen) #endif #ifndef EX_OSERR #define EX_OSERR 71 /* system error (e.g., can't fork) */ #endif #if !HAVE_ERR_H void err(int eval, const char *fmt, ...); void warn(const char *fmt, ...); #endif #if defined(_MSC_VER) && _MSC_VER < 1600 typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; #elif defined(_MSC_VER) // && _MSC_VER >= 1600 #include #else #include #endif char *str_replace(char *, char *, char *); #endif qstat-2.15/depcomp0000755000175000017500000005601612420766264011114 00000000000000#! /bin/sh # depcomp - compile a program generating dependencies as side-effects scriptversion=2013-05-30.07; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # Originally written by Alexandre Oliva . case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: depcomp [--help] [--version] PROGRAM [ARGS] Run PROGRAMS ARGS to compile a file, generating dependencies as side-effects. Environment variables: depmode Dependency tracking mode. source Source file read by 'PROGRAMS ARGS'. object Object file output by 'PROGRAMS ARGS'. DEPDIR directory where to store dependencies. depfile Dependency file to output. tmpdepfile Temporary file to use when outputting dependencies. libtool Whether libtool is used (yes/no). Report bugs to . EOF exit $? ;; -v | --v*) echo "depcomp $scriptversion" exit $? ;; esac # Get the directory component of the given path, and save it in the # global variables '$dir'. Note that this directory component will # be either empty or ending with a '/' character. This is deliberate. set_dir_from () { case $1 in */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;; *) dir=;; esac } # Get the suffix-stripped basename of the given path, and save it the # global variable '$base'. set_base_from () { base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'` } # If no dependency file was actually created by the compiler invocation, # we still have to create a dummy depfile, to avoid errors with the # Makefile "include basename.Plo" scheme. make_dummy_depfile () { echo "#dummy" > "$depfile" } # Factor out some common post-processing of the generated depfile. # Requires the auxiliary global variable '$tmpdepfile' to be set. aix_post_process_depfile () { # If the compiler actually managed to produce a dependency file, # post-process it. if test -f "$tmpdepfile"; then # Each line is of the form 'foo.o: dependency.h'. # Do two passes, one to just change these to # $object: dependency.h # and one to simply output # dependency.h: # which is needed to avoid the deleted-header problem. { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile" sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile" } > "$depfile" rm -f "$tmpdepfile" else make_dummy_depfile fi } # A tabulation character. tab=' ' # A newline character. nl=' ' # Character ranges might be problematic outside the C locale. # These definitions help. upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ lower=abcdefghijklmnopqrstuvwxyz digits=0123456789 alpha=${upper}${lower} if test -z "$depmode" || test -z "$source" || test -z "$object"; then echo "depcomp: Variables source, object and depmode must be set" 1>&2 exit 1 fi # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. depfile=${depfile-`echo "$object" | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} rm -f "$tmpdepfile" # Avoid interferences from the environment. gccflag= dashmflag= # Some modes work just like other modes, but use different flags. We # parameterize here, but still list the modes in the big case below, # to make depend.m4 easier to write. Note that we *cannot* use a case # here, because this file can only contain one case statement. if test "$depmode" = hp; then # HP compiler uses -M and no extra arg. gccflag=-M depmode=gcc fi if test "$depmode" = dashXmstdout; then # This is just like dashmstdout with a different argument. dashmflag=-xM depmode=dashmstdout fi cygpath_u="cygpath -u -f -" if test "$depmode" = msvcmsys; then # This is just like msvisualcpp but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvisualcpp fi if test "$depmode" = msvc7msys; then # This is just like msvc7 but w/o cygpath translation. # Just convert the backslash-escaped backslashes to single forward # slashes to satisfy depend.m4 cygpath_u='sed s,\\\\,/,g' depmode=msvc7 fi if test "$depmode" = xlc; then # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information. gccflag=-qmakedep=gcc,-MF depmode=gcc fi case "$depmode" in gcc3) ## gcc 3 implements dependency tracking that does exactly what ## we want. Yay! Note: for some reason libtool 1.4 doesn't like ## it if -MD -MP comes after the -MF stuff. Hmm. ## Unfortunately, FreeBSD c89 acceptance of flags depends upon ## the command line argument order; so add the flags where they ## appear in depend2.am. Note that the slowdown incurred here ## affects only configure: in makefiles, %FASTDEP% shortcuts this. for arg do case $arg in -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; *) set fnord "$@" "$arg" ;; esac shift # fnord shift # $arg done "$@" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi mv "$tmpdepfile" "$depfile" ;; gcc) ## Note that this doesn't just cater to obsosete pre-3.x GCC compilers. ## but also to in-use compilers like IMB xlc/xlC and the HP C compiler. ## (see the conditional assignment to $gccflag above). ## There are various ways to get dependency output from gcc. Here's ## why we pick this rather obscure method: ## - Don't want to use -MD because we'd like the dependencies to end ## up in a subdir. Having to rename by hand is ugly. ## (We might end up doing this anyway to support other compilers.) ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like ## -MM, not -M (despite what the docs say). Also, it might not be ## supported by the other compilers which use the 'gcc' depmode. ## - Using -M directly means running the compiler twice (even worse ## than renaming). if test -z "$gccflag"; then gccflag=-MD, fi "$@" -Wp,"$gccflag$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The second -e expression handles DOS-style file names with drive # letters. sed -e 's/^[^:]*: / /' \ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" ## This next piece of magic avoids the "deleted header file" problem. ## The problem is that when a header file which appears in a .P file ## is deleted, the dependency causes make to die (because there is ## typically no way to rebuild the header). We avoid this by adding ## dummy dependencies for each header file. Too bad gcc doesn't do ## this for us directly. ## Some versions of gcc put a space before the ':'. On the theory ## that the space means something, we add a space to the output as ## well. hp depmode also adds that space, but also prefixes the VPATH ## to the object. Take care to not repeat it in the output. ## Some versions of the HPUX 10.20 sed can't process this invocation ## correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; sgi) if test "$libtool" = yes; then "$@" "-Wp,-MDupdate,$tmpdepfile" else "$@" -MDupdate "$tmpdepfile" fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files echo "$object : \\" > "$depfile" # Clip off the initial element (the dependent). Don't try to be # clever and replace this with sed code, as IRIX sed won't handle # lines with more than a fixed number of characters (4096 in # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; # the IRIX cc adds comments like '#:fec' to the end of the # dependency line. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \ | tr "$nl" ' ' >> "$depfile" echo >> "$depfile" # The second pass generates a dummy entry for each header file. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" ;; xlc) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; aix) # The C for AIX Compiler uses -M and outputs the dependencies # in a .u file. In older versions, this file always lives in the # current directory. Also, the AIX compiler puts '$object:' at the # start of each line; $object doesn't have directory information. # Version 6 uses the directory in both cases. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.u tmpdepfile2=$base.u tmpdepfile3=$dir.libs/$base.u "$@" -Wc,-M else tmpdepfile1=$dir$base.u tmpdepfile2=$dir$base.u tmpdepfile3=$dir$base.u "$@" -M fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done aix_post_process_depfile ;; tcc) # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26 # FIXME: That version still under development at the moment of writing. # Make that this statement remains true also for stable, released # versions. # It will wrap lines (doesn't matter whether long or short) with a # trailing '\', as in: # # foo.o : \ # foo.c \ # foo.h \ # # It will put a trailing '\' even on the last line, and will use leading # spaces rather than leading tabs (at least since its commit 0394caf7 # "Emit spaces for -MD"). "$@" -MD -MF "$tmpdepfile" stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'. # We have to change lines of the first kind to '$object: \'. sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile" # And for each line of the second kind, we have to emit a 'dep.h:' # dummy dependency, to avoid the deleted-header problem. sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile" rm -f "$tmpdepfile" ;; ## The order of this option in the case statement is important, since the ## shell code in configure will try each of these formats in the order ## listed in this file. A plain '-MD' option would be understood by many ## compilers, so we must ensure this comes after the gcc and icc options. pgcc) # Portland's C compiler understands '-MD'. # Will always output deps to 'file.d' where file is the root name of the # source file under compilation, even if file resides in a subdirectory. # The object file name does not affect the name of the '.d' file. # pgcc 10.2 will output # foo.o: sub/foo.c sub/foo.h # and will wrap long lines using '\' : # foo.o: sub/foo.c ... \ # sub/foo.h ... \ # ... set_dir_from "$object" # Use the source, not the object, to determine the base name, since # that's sadly what pgcc will do too. set_base_from "$source" tmpdepfile=$base.d # For projects that build the same source file twice into different object # files, the pgcc approach of using the *source* file root name can cause # problems in parallel builds. Use a locking strategy to avoid stomping on # the same $tmpdepfile. lockdir=$base.d-lock trap " echo '$0: caught signal, cleaning up...' >&2 rmdir '$lockdir' exit 1 " 1 2 13 15 numtries=100 i=$numtries while test $i -gt 0; do # mkdir is a portable test-and-set. if mkdir "$lockdir" 2>/dev/null; then # This process acquired the lock. "$@" -MD stat=$? # Release the lock. rmdir "$lockdir" break else # If the lock is being held by a different process, wait # until the winning process is done or we timeout. while test -d "$lockdir" && test $i -gt 0; do sleep 1 i=`expr $i - 1` done fi i=`expr $i - 1` done trap - 1 2 13 15 if test $i -le 0; then echo "$0: failed to acquire lock after $numtries attempts" >&2 echo "$0: check lockdir '$lockdir'" >&2 exit 1 fi if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" # Each line is of the form `foo.o: dependent.h', # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. # Do two passes, one to just change these to # `$object: dependent.h' and one to simply `dependent.h:'. sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this invocation # correctly. Breaking it into two sed invocations is a workaround. sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; hp2) # The "hp" stanza above does not work with aCC (C++) and HP's ia64 # compilers, which have integrated preprocessors. The correct option # to use with these is +Maked; it writes dependencies to a file named # 'foo.d', which lands next to the object file, wherever that # happens to be. # Much of this is similar to the tru64 case; see comments there. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then tmpdepfile1=$dir$base.d tmpdepfile2=$dir.libs/$base.d "$@" -Wc,+Maked else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d "$@" +Maked fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" do test -f "$tmpdepfile" && break done if test -f "$tmpdepfile"; then sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile" # Add 'dependent.h:' lines. sed -ne '2,${ s/^ *// s/ \\*$// s/$/:/ p }' "$tmpdepfile" >> "$depfile" else make_dummy_depfile fi rm -f "$tmpdepfile" "$tmpdepfile2" ;; tru64) # The Tru64 compiler uses -MD to generate dependencies as a side # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'. # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put # dependencies in 'foo.d' instead, so we check for that too. # Subdirectories are respected. set_dir_from "$object" set_base_from "$object" if test "$libtool" = yes; then # Libtool generates 2 separate objects for the 2 libraries. These # two compilations output dependencies in $dir.libs/$base.o.d and # in $dir$base.o.d. We have to check for both files, because # one of the two compilations can be disabled. We should prefer # $dir$base.o.d over $dir.libs/$base.o.d because the latter is # automatically cleaned when .libs/ is deleted, while ignoring # the former would cause a distcleancheck panic. tmpdepfile1=$dir$base.o.d # libtool 1.5 tmpdepfile2=$dir.libs/$base.o.d # Likewise. tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504 "$@" -Wc,-MD else tmpdepfile1=$dir$base.d tmpdepfile2=$dir$base.d tmpdepfile3=$dir$base.d "$@" -MD fi stat=$? if test $stat -ne 0; then rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" exit $stat fi for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" do test -f "$tmpdepfile" && break done # Same post-processing that is required for AIX mode. aix_post_process_depfile ;; msvc7) if test "$libtool" = yes; then showIncludes=-Wc,-showIncludes else showIncludes=-showIncludes fi "$@" $showIncludes > "$tmpdepfile" stat=$? grep -v '^Note: including file: ' "$tmpdepfile" if test $stat -ne 0; then rm -f "$tmpdepfile" exit $stat fi rm -f "$depfile" echo "$object : \\" > "$depfile" # The first sed program below extracts the file names and escapes # backslashes for cygpath. The second sed program outputs the file # name when reading, but also accumulates all include files in the # hold buffer in order to output them again at the end. This only # works with sed implementations that can handle large buffers. sed < "$tmpdepfile" -n ' /^Note: including file: *\(.*\)/ { s//\1/ s/\\/\\\\/g p }' | $cygpath_u | sort -u | sed -n ' s/ /\\ /g s/\(.*\)/'"$tab"'\1 \\/p s/.\(.*\) \\/\1:/ H $ { s/.*/'"$tab"'/ G p }' >> "$depfile" echo >> "$depfile" # make sure the fragment doesn't end with a backslash rm -f "$tmpdepfile" ;; msvc7msys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; #nosideeffect) # This comment above is used by automake to tell side-effect # dependency tracking mechanisms from slower ones. dashmstdout) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout, regardless of -o. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done test -z "$dashmflag" && dashmflag=-M # Require at least two characters before searching for ':' # in the target name. This is to cope with DOS-style filenames: # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise. "$@" $dashmflag | sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile" rm -f "$depfile" cat < "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process this sed invocation # correctly. Breaking it into two sed invocations is a workaround. tr ' ' "$nl" < "$tmpdepfile" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; dashXmstdout) # This case only exists to satisfy depend.m4. It is never actually # run, as this mode is specially recognized in the preamble. exit 1 ;; makedepend) "$@" || exit $? # Remove any Libtool call if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # X makedepend shift cleared=no eat=no for arg do case $cleared in no) set ""; shift cleared=yes ;; esac if test $eat = yes; then eat=no continue fi case "$arg" in -D*|-I*) set fnord "$@" "$arg"; shift ;; # Strip any option that makedepend may not understand. Remove # the object too, otherwise makedepend will parse it as a source file. -arch) eat=yes ;; -*|$object) ;; *) set fnord "$@" "$arg"; shift ;; esac done obj_suffix=`echo "$object" | sed 's/^.*\././'` touch "$tmpdepfile" ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" rm -f "$depfile" # makedepend may prepend the VPATH from the source file name to the object. # No need to regex-escape $object, excess matching of '.' is harmless. sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile" # Some versions of the HPUX 10.20 sed can't process the last invocation # correctly. Breaking it into two sed invocations is a workaround. sed '1,2d' "$tmpdepfile" \ | tr ' ' "$nl" \ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \ | sed -e 's/$/ :/' >> "$depfile" rm -f "$tmpdepfile" "$tmpdepfile".bak ;; cpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi # Remove '-o $object'. IFS=" " for arg do case $arg in -o) shift ;; $object) shift ;; *) set fnord "$@" "$arg" shift # fnord shift # $arg ;; esac done "$@" -E \ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ | sed '$ s: \\$::' > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" cat < "$tmpdepfile" >> "$depfile" sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" rm -f "$tmpdepfile" ;; msvisualcpp) # Important note: in order to support this mode, a compiler *must* # always write the preprocessed file to stdout. "$@" || exit $? # Remove the call to Libtool. if test "$libtool" = yes; then while test "X$1" != 'X--mode=compile'; do shift done shift fi IFS=" " for arg do case "$arg" in -o) shift ;; $object) shift ;; "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") set fnord "$@" shift shift ;; *) set fnord "$@" "$arg" shift shift ;; esac done "$@" -E 2>/dev/null | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile" rm -f "$depfile" echo "$object : \\" > "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile" echo "$tab" >> "$depfile" sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile" rm -f "$tmpdepfile" ;; msvcmsys) # This case exists only to let depend.m4 do its work. It works by # looking at the text of this script. This case will never be run, # since it is checked for above. exit 1 ;; none) exec "$@" ;; *) echo "Unknown depmode $depmode" 1>&2 exit 1 ;; esac exit 0 # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: qstat-2.15/crysis.h0000644000175000017500000000066412420765615011221 00000000000000/* * qstat * by Steve Jankowski * * Crysis protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_CRYSIS_H #define QSTAT_CRYSIS_H #include "qserver.h" // Packet processing methods query_status_t deal_with_crysis_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_crysis_request_packet( struct qserver *server ); #endif qstat-2.15/wic.h0000644000175000017500000000066312420765614010465 00000000000000/* * qstat * by Steve Jankowski * * World in Conflict Protocol * Copyright 2007 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_WIC_H #define QSTAT_WIC_H #include "qserver.h" // Packet processing methods query_status_t deal_with_wic_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_wic_request_packet( struct qserver *server ); #endif qstat-2.15/ventrilo.c0000644000175000017500000002572412420765614011545 00000000000000/* * qstat * by Steve Jankowski * * Ventrilo query protocol * Algorithm by Luigi Auriemma * QStat port 2010 by Michael Willigens * Fixes by Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #ifndef _WIN32 #include #include #include #define strtok_ret strtok_r #define VENTRILO_RAND random() #else #include #define strtok_ret strtok_s #define VENTRILO_RAND rand() #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" int VENTRILO_COMMAND_GENERIC_INFO = 1; int VENTRILO_COMMAND_DETAILED_INFO = 2; // includes generic infos int VENTRILO_COMMAND_DIFFERENT = 7; typedef struct { unsigned short pckkey; // key for decoding this header unsigned short zero; // ever 0 unsigned short cmd; // command number: 1 generic info, 2 for details unsigned short id; // packet ID used for tracking the replies unsigned short totlen; // total data size (for data splitted in packets) unsigned short len; // size of the data in this packet (max 492) unsigned short totpck; // total amount of packets (max 32) unsigned short pck; // current packet number unsigned short datakey; // key for decoding the data unsigned short crc; // checksum of the total plain-text data } ventrilo_udp_head; const static unsigned char ventrilo_udp_encdata_head[] = "\x80\xe5\x0e\x38\xba\x63\x4c\x99\x88\x63\x4c\xd6\x54\xb8\x65\x7e" "\xbf\x8a\xf0\x17\x8a\xaa\x4d\x0f\xb7\x23\x27\xf6\xeb\x12\xf8\xea" "\x17\xb7\xcf\x52\x57\xcb\x51\xcf\x1b\x14\xfd\x6f\x84\x38\xb5\x24" "\x11\xcf\x7a\x75\x7a\xbb\x78\x74\xdc\xbc\x42\xf0\x17\x3f\x5e\xeb" "\x74\x77\x04\x4e\x8c\xaf\x23\xdc\x65\xdf\xa5\x65\xdd\x7d\xf4\x3c" "\x4c\x95\xbd\xeb\x65\x1c\xf4\x24\x5d\x82\x18\xfb\x50\x86\xb8\x53" "\xe0\x4e\x36\x96\x1f\xb7\xcb\xaa\xaf\xea\xcb\x20\x27\x30\x2a\xae" "\xb9\x07\x40\xdf\x12\x75\xc9\x09\x82\x9c\x30\x80\x5d\x8f\x0d\x09" "\xa1\x64\xec\x91\xd8\x8a\x50\x1f\x40\x5d\xf7\x08\x2a\xf8\x60\x62" "\xa0\x4a\x8b\xba\x4a\x6d\x00\x0a\x93\x32\x12\xe5\x07\x01\x65\xf5" "\xff\xe0\xae\xa7\x81\xd1\xba\x25\x62\x61\xb2\x85\xad\x7e\x9d\x3f" "\x49\x89\x26\xe5\xd5\xac\x9f\x0e\xd7\x6e\x47\x94\x16\x84\xc8\xff" "\x44\xea\x04\x40\xe0\x33\x11\xa3\x5b\x1e\x82\xff\x7a\x69\xe9\x2f" "\xfb\xea\x9a\xc6\x7b\xdb\xb1\xff\x97\x76\x56\xf3\x52\xc2\x3f\x0f" "\xb6\xac\x77\xc4\xbf\x59\x5e\x80\x74\xbb\xf2\xde\x57\x62\x4c\x1a" "\xff\x95\x6d\xc7\x04\xa2\x3b\xc4\x1b\x72\xc7\x6c\x82\x60\xd1\x0d"; const static unsigned char ventrilo_udp_encdata_data[] = "\x82\x8b\x7f\x68\x90\xe0\x44\x09\x19\x3b\x8e\x5f\xc2\x82\x38\x23" "\x6d\xdb\x62\x49\x52\x6e\x21\xdf\x51\x6c\x76\x37\x86\x50\x7d\x48" "\x1f\x65\xe7\x52\x6a\x88\xaa\xc1\x32\x2f\xf7\x54\x4c\xaa\x6d\x7e" "\x6d\xa9\x8c\x0d\x3f\xff\x6c\x09\xb3\xa5\xaf\xdf\x98\x02\xb4\xbe" "\x6d\x69\x0d\x42\x73\xe4\x34\x50\x07\x30\x79\x41\x2f\x08\x3f\x42" "\x73\xa7\x68\xfa\xee\x88\x0e\x6e\xa4\x70\x74\x22\x16\xae\x3c\x81" "\x14\xa1\xda\x7f\xd3\x7c\x48\x7d\x3f\x46\xfb\x6d\x92\x25\x17\x36" "\x26\xdb\xdf\x5a\x87\x91\x6f\xd6\xcd\xd4\xad\x4a\x29\xdd\x7d\x59" "\xbd\x15\x34\x53\xb1\xd8\x50\x11\x83\x79\x66\x21\x9e\x87\x5b\x24" "\x2f\x4f\xd7\x73\x34\xa2\xf7\x09\xd5\xd9\x42\x9d\xf8\x15\xdf\x0e" "\x10\xcc\x05\x04\x35\x81\xb2\xd5\x7a\xd2\xa0\xa5\x7b\xb8\x75\xd2" "\x35\x0b\x39\x8f\x1b\x44\x0e\xce\x66\x87\x1b\x64\xac\xe1\xca\x67" "\xb4\xce\x33\xdb\x89\xfe\xd8\x8e\xcd\x58\x92\x41\x50\x40\xcb\x08" "\xe1\x15\xee\xf4\x64\xfe\x1c\xee\x25\xe7\x21\xe6\x6c\xc6\xa6\x2e" "\x52\x23\xa7\x20\xd2\xd7\x28\x07\x23\x14\x24\x3d\x45\xa5\xc7\x90" "\xdb\x77\xdd\xea\x38\x59\x89\x32\xbc\x00\x3a\x6d\x61\x4e\xdb\x29"; const static unsigned short ventrilo_crc_table[] = { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 }; void ventrilo_udp_head_dec(unsigned char *data) { int i; unsigned short *p; unsigned char a1; unsigned char a2; p = (unsigned short *)data; data += 2; *p = ntohs(*p); a1 = *p; if( ! a1 ) { return; } a2 = *p >> 8; for( i = 0; i < 18; i++ ) { data[i] -= ventrilo_udp_encdata_head[a2] + (i % 5); a2 += a1; } for( i = 0; i < 9; i++ ) { p++; *p = ntohs(*p); } } void ventrilo_udp_head_enc(unsigned char *data) { int i; unsigned short *p; unsigned char a1; unsigned char a2; p = (unsigned short *)data; data += 2; *p = (((VENTRILO_RAND * 0x343fd) + 0x269ec3) >> 16) & 0x7fff; a1 = *p; a2 = *p >> 8; if( ! a2 ) { a2 = 69; *p |= (a2 << 8); } for( i = 0; i < 10; i++ ) { *p = htons(*p); p++; } for( i = 0; i < 18; i++ ) { data[i] += ventrilo_udp_encdata_head[a2] + (i % 5); a2 += a1; } } void ventrilo_udp_data_dec(unsigned char *data, int len, unsigned short key) { int i; unsigned char a1; unsigned char a2; a1 = key; if( ! a1 ) { return; } a2 = key >> 8; for( i = 0; i < len; i++ ) { data[i] -= ventrilo_udp_encdata_data[a2] + (i % 72); a2 += a1; } } unsigned short ventrilo_udp_data_enc(unsigned char *data, int len) { int i; unsigned short key; unsigned char a1; unsigned char a2; key = (((VENTRILO_RAND * 0x343fd) + 0x269ec3) >> 16) & 0x7fff; a1 = key; a2 = key >> 8; if( ! a2 ) { a2 = 1; key |= (a2 << 8); } for( i = 0; i < len; i++ ) { data[i] += ventrilo_udp_encdata_data[a2] + (i % 72); a2 += a1; } return key; } unsigned short ventrilo_udp_crc(unsigned char *data, int len) { unsigned short crc = 0; while( len-- ) { crc = ventrilo_crc_table[crc >> 8] ^ *data ^ (crc << 8); data++; } return(crc); } int buildVentriloRequest(unsigned char *buf, int cmd, char *pass, int id) { ventrilo_udp_head *stat = (ventrilo_udp_head *) buf; unsigned char *data = buf + 20; strncpy((char *) data, pass, 16); stat->zero = 0; stat->cmd = cmd; stat->id = id; stat->totlen = 16; stat->len = 16; stat->totpck = 1; stat->pck = 0; stat->crc = ventrilo_udp_crc(data, 16); stat->datakey = ventrilo_udp_data_enc(data, 16); ventrilo_udp_head_enc(buf); return 20+16; } query_status_t send_ventrilo_request_packet( struct qserver *server ) { char buf[1500]; char *password = get_param_value( server, "password", "" ); int size = buildVentriloRequest((unsigned char *) buf, VENTRILO_COMMAND_DETAILED_INFO, password, server->challenge); server->n_requests++; gettimeofday( &server->packet_time1, NULL ); debug( 2, "send status request"); return send_packet( server, buf, size ); } query_status_t deal_with_ventrilo_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *line, *last_line; debug( 3, "deal_with_ventrilo_packet: state = %ld", server->challenge ); if( 20 > pktlen ) { debug( 2, "wrong or incomplete packet received. retrying..."); return INPROGRESS; } /* add to the data previously saved to get a full packet*/ if ( ! server->combined ) { ventrilo_udp_head *header = (ventrilo_udp_head *) rawpkt; unsigned char *data = (unsigned char *) header+20; ventrilo_udp_head_dec( (unsigned char*) header ); ventrilo_udp_data_dec(data, header->len, header->datakey); if (header->id != server->challenge) { debug( 2, "ignoring unnecessary packet..."); return INPROGRESS; } debug( 3, "decoded ventrilo fragment: id:%i - len:%i - totlen:%i - totpck:%i - zero:%i - cmd:%i", header->id, header->len, header->totlen, header->totpck, header->zero, header->cmd); add_packet(server, header->id, packet_count(server), header->totpck, header->len, (char *) data, 0); return combine_packets( server ); } debug( 4, "combined ventrilo packet: %s", rawpkt); server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); line = strtok_ret( rawpkt, "\n", &last_line ); debug( 3, "processing detailed response..." ); while (line != NULL) { debug( 4, "processing line: %s", line ); if ( 0 == strncmp( line, "NAME: ", 6 ) ) { server->server_name = strdup( line + 6 ); } else if ( 0 == strncmp( line, "MAXCLIENTS: ", 12 ) ) { server->max_players = atoi( line + 12 ); } else if ( 0 == strncmp( line, "CLIENTCOUNT: ", 13 ) ) { server->num_players = atoi( line + 13 ); } else if ( 0 == strncmp( line, "CLIENT: ", 8 ) ) { // Client e.g. // CLIENT: UID=406,ADMIN=0,CID=17,PHAN=0,PING=73,SEC=2245,NAME=Darrimu,COMM= struct player *player = add_player( server, server->n_player_info ); char *last_info = NULL; char *player_info = strtok_ret( line + 8, ",", &last_info ); while ( NULL != player_info ) { debug( 5, "player info: %s", player_info ); if ( 0 == strncmp( player_info, "NAME=", 5 ) ) { player->name = strdup( player_info + 5 ); } else if ( strncmp( player_info, "PING=", 5 ) ) { player->ping = atoi( player_info + 5 ); } else if ( 0 == strncmp( player_info, "CID=", 4 ) ) { player->team = atoi( player_info + 4 ); } else if ( strncmp( player_info, "SEC=", 4 ) ) { player->connect_time = atoi( player_info + 4 ); } player_info = strtok_ret( NULL, ",", &last_info ); } } line = strtok_ret( NULL, "\n", &last_line ); } server->map_name = strdup( "N/A" ); return DONE_FORCE; } qstat-2.15/compile0000755000175000017500000001624512420766264011115 00000000000000#! /bin/sh # Wrapper for compilers which do not understand '-c -o'. scriptversion=2012-10-14.11; # UTC # Copyright (C) 1999-2013 Free Software Foundation, Inc. # Written by Tom Tromey . # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a # configuration script generated by Autoconf, you may include it under # the same distribution terms that you use for the rest of that program. # This file is maintained in Automake, please report # bugs to or send patches to # . nl=' ' # We need space, tab and new line, in precisely that order. Quoting is # there to prevent tools from complaining about whitespace usage. IFS=" "" $nl" file_conv= # func_file_conv build_file lazy # Convert a $build file to $host form and store it in $file # Currently only supports Windows hosts. If the determined conversion # type is listed in (the comma separated) LAZY, no conversion will # take place. func_file_conv () { file=$1 case $file in / | /[!/]*) # absolute file, and not a UNC file if test -z "$file_conv"; then # lazily determine how to convert abs files case `uname -s` in MINGW*) file_conv=mingw ;; CYGWIN*) file_conv=cygwin ;; *) file_conv=wine ;; esac fi case $file_conv/,$2, in *,$file_conv,*) ;; mingw/*) file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'` ;; cygwin/*) file=`cygpath -m "$file" || echo "$file"` ;; wine/*) file=`winepath -w "$file" || echo "$file"` ;; esac ;; esac } # func_cl_dashL linkdir # Make cl look for libraries in LINKDIR func_cl_dashL () { func_file_conv "$1" if test -z "$lib_path"; then lib_path=$file else lib_path="$lib_path;$file" fi linker_opts="$linker_opts -LIBPATH:$file" } # func_cl_dashl library # Do a library search-path lookup for cl func_cl_dashl () { lib=$1 found=no save_IFS=$IFS IFS=';' for dir in $lib_path $LIB do IFS=$save_IFS if $shared && test -f "$dir/$lib.dll.lib"; then found=yes lib=$dir/$lib.dll.lib break fi if test -f "$dir/$lib.lib"; then found=yes lib=$dir/$lib.lib break fi if test -f "$dir/lib$lib.a"; then found=yes lib=$dir/lib$lib.a break fi done IFS=$save_IFS if test "$found" != yes; then lib=$lib.lib fi } # func_cl_wrapper cl arg... # Adjust compile command to suit cl func_cl_wrapper () { # Assume a capable shell lib_path= shared=: linker_opts= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. eat=1 case $2 in *.o | *.[oO][bB][jJ]) func_file_conv "$2" set x "$@" -Fo"$file" shift ;; *) func_file_conv "$2" set x "$@" -Fe"$file" shift ;; esac ;; -I) eat=1 func_file_conv "$2" mingw set x "$@" -I"$file" shift ;; -I*) func_file_conv "${1#-I}" mingw set x "$@" -I"$file" shift ;; -l) eat=1 func_cl_dashl "$2" set x "$@" "$lib" shift ;; -l*) func_cl_dashl "${1#-l}" set x "$@" "$lib" shift ;; -L) eat=1 func_cl_dashL "$2" ;; -L*) func_cl_dashL "${1#-L}" ;; -static) shared=false ;; -Wl,*) arg=${1#-Wl,} save_ifs="$IFS"; IFS=',' for flag in $arg; do IFS="$save_ifs" linker_opts="$linker_opts $flag" done IFS="$save_ifs" ;; -Xlinker) eat=1 linker_opts="$linker_opts $2" ;; -*) set x "$@" "$1" shift ;; *.cc | *.CC | *.cxx | *.CXX | *.[cC]++) func_file_conv "$1" set x "$@" -Tp"$file" shift ;; *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO]) func_file_conv "$1" mingw set x "$@" "$file" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -n "$linker_opts"; then linker_opts="-link$linker_opts" fi exec "$@" $linker_opts exit 1 } eat= case $1 in '') echo "$0: No command. Try '$0 --help' for more information." 1>&2 exit 1; ;; -h | --h*) cat <<\EOF Usage: compile [--help] [--version] PROGRAM [ARGS] Wrapper for compilers which do not understand '-c -o'. Remove '-o dest.o' from ARGS, run PROGRAM with the remaining arguments, and rename the output as expected. If you are trying to build a whole package this is not the right script to run: please start by reading the file 'INSTALL'. Report bugs to . EOF exit $? ;; -v | --v*) echo "compile $scriptversion" exit $? ;; cl | *[/\\]cl | cl.exe | *[/\\]cl.exe ) func_cl_wrapper "$@" # Doesn't return... ;; esac ofile= cfile= for arg do if test -n "$eat"; then eat= else case $1 in -o) # configure might choose to run compile as 'compile cc -o foo foo.c'. # So we strip '-o arg' only if arg is an object. eat=1 case $2 in *.o | *.obj) ofile=$2 ;; *) set x "$@" -o "$2" shift ;; esac ;; *.c) cfile=$1 set x "$@" "$1" shift ;; *) set x "$@" "$1" shift ;; esac fi shift done if test -z "$ofile" || test -z "$cfile"; then # If no '-o' option was seen then we might have been invoked from a # pattern rule where we don't need one. That is ok -- this is a # normal compilation that the losing compiler can handle. If no # '.c' file was seen then we are probably linking. That is also # ok. exec "$@" fi # Name of file we expect compiler to create. cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'` # Create the lock directory. # Note: use '[/\\:.-]' here to ensure that we don't use the same name # that we are using for the .o file. Also, base the name on the expected # object file name, since that is what matters with a parallel build. lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d while true; do if mkdir "$lockdir" >/dev/null 2>&1; then break fi sleep 1 done # FIXME: race condition here if user kills between mkdir and trap. trap "rmdir '$lockdir'; exit 1" 1 2 15 # Run the compile. "$@" ret=$? if test -f "$cofile"; then test "$cofile" = "$ofile" || mv "$cofile" "$ofile" elif test -f "${cofile}bj"; then test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile" fi rmdir "$lockdir" exit $ret # Local Variables: # mode: shell-script # sh-indentation: 2 # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "scriptversion=" # time-stamp-format: "%:y-%02m-%02d.%02H" # time-stamp-time-zone: "UTC" # time-stamp-end: "; # UTC" # End: qstat-2.15/terraria.c0000644000175000017500000001110412420765614011477 00000000000000/* * qstat * by Steve Jankowski * * Terraria / TShock query protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #define strtok_ret strtok_r #else #include #define strtok_ret strtok_s #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" query_status_t send_terraria_request_packet( struct qserver *server ) { return send_packet( server, server->type->status_packet, server->type->status_len ); } query_status_t deal_with_terraria_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *end, *key, *val, *sep, *linep, *varp; int complete_response = 0; char last_char; unsigned short port = 0; debug( 2, "processing..." ); if ( 0 == pktlen ) { // Disconnect? return REQ_ERROR; } complete_response = ( 0 == strncmp( "HTTP/1.1 200", rawpkt, 12 ) && '}' == rawpkt[pktlen-1] ) ? 1 : 0; last_char = rawpkt[pktlen-1]; rawpkt[pktlen-1] = '\0'; debug( 3, "packet: combined = %d, complete = %d", server->combined, complete_response ); if ( ! complete_response ) { if ( ! server->combined ) { // response fragment recieved int pkt_id; int pkt_max; server->retry1 = n_retries; if ( 0 == server->n_requests ) { server->ping_total = time_delta( &packet_recv_time, &server->packet_time1 ); server->n_requests++; } // 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; } if ( 0 == pkt_id ) { return INPROGRESS; } // combine_packets will call us recursively return combine_packets( server ); } // recursive call which is still incomplete return INPROGRESS; } // find the end of the headers s = strstr( rawpkt, "\x0d\x0a\x0d\x0a" ); if ( NULL == s ) { debug(1, "Error: missing end of headers"); return REQ_ERROR; } s += 4; end = &rawpkt[pktlen-1]; // 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_ret( s, "\x0d\x0a", &linep ); // NOTE: id=XXX and msg=XXX will be processed by the mod following the one they where the response of while ( NULL != s ) { debug( 2, "LINE: %s\n", s ); if ( 0 == strcmp( s, "{" ) ) { s = strtok_ret( NULL, "\x0d\x0a", &linep ); continue; } s = strtok_ret( s, "\"", &varp ); key = strtok_ret( NULL, "\"", &varp ); sep = strtok_ret( NULL, " ", &varp ); val = strtok_ret( NULL, "\"", &varp ); if ( NULL == val ) { // world etc may be empty which results in NULL val s = strtok_ret( NULL, "\x0d\x0a", &linep ); continue; } //if ( NULL == val && sep debug( 2, "var: '%s' = '%s', sep: '%s'\n", key, val, sep ); if ( 0 == strcmp( key, "name" ) ) { server->server_name = strdup( val ); } else if ( 0 == strcmp( key, "port" ) ) { port = atoi( val ); change_server_port( server, port, 0 ); add_rule( server, key, val, NO_FLAGS ); } else if ( 0 == strcmp( key, "playercount" ) ) { server->num_players = atoi( val ); } else if ( 0 == strcmp( key, "maxplayers" ) ) { server->max_players = atoi( val ); } else if ( 0 == strcmp( key, "world" ) ) { server->map_name = strdup( val ); } else if ( 0 == strcmp( key, "players" ) ) { // Players are ", " seperated but potentially player names can have spaces // so we manually check for the leading space and fix if found char *playersp; char *player_name = strtok_ret( val, ",", &playersp ); while ( NULL != player_name ) { struct player *player = add_player( server, server->n_player_info ); if ( NULL != player ) { if ( ' ' == player_name[0] ) { player_name++; } player->name = strdup( player_name ); debug( 4, "Player: %s\n", player->name ); } player_name = strtok_ret( NULL, ",", &playersp ); } } else if ( 0 == strcmp( key, "status" ) ) { if ( 200 != atoi( val ) ) { server->server_name = DOWN; return DONE_FORCE; } } else { add_rule( server, key, val, NO_FLAGS); } s = strtok_ret( NULL, "\x0d\x0a", &linep ); } gettimeofday( &server->packet_time1, NULL ); return DONE_FORCE; } qstat-2.15/configure0000755000175000017500000052315512420766264011451 00000000000000#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.69 for qstat 2.15. # # Report bugs to . # # # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # Use a proper internal environment variable to ensure we don't fall # into an infinite loop, continuously re-executing ourselves. if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then _as_can_reexec=no; export _as_can_reexec; # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 as_fn_exit 255 fi # We don't want this to propagate to other subprocesses. { _as_can_reexec=; unset _as_can_reexec;} if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1 test -x / || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : export CONFIG_SHELL # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"} # Admittedly, this is quite paranoid, since all the known shells bail # out after a failed `exec'. $as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2 exit 255 fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org and $0: qstat-users@yahoogroups.com about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # If we had to re-execute with $CONFIG_SHELL, we're ensured to have # already done that, so ensure we don't try to do so again and fall # in an infinite loop. This has already happened in practice. _as_can_reexec=no; export _as_can_reexec # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 &1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='qstat' PACKAGE_TARNAME='qstat' PACKAGE_VERSION='2.15' PACKAGE_STRING='qstat 2.15' PACKAGE_BUGREPORT='qstat-users@yahoogroups.com' PACKAGE_URL='' ac_unique_file="qstat.c" # Factoring default headers for most tests. ac_includes_default="\ #include #ifdef HAVE_SYS_TYPES_H # include #endif #ifdef HAVE_SYS_STAT_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include # endif # include #endif #ifdef HAVE_STRINGS_H # include #endif #ifdef HAVE_INTTYPES_H # include #endif #ifdef HAVE_STDINT_H # include #endif #ifdef HAVE_UNISTD_H # include #endif" ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS LIBOBJS EGREP GREP CPP am__fastdepCC_FALSE am__fastdepCC_TRUE CCDEPMODE am__nodep AMDEPBACKSLASH AMDEP_FALSE AMDEP_TRUE am__quote am__include DEPDIR OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC AM_BACKSLASH AM_DEFAULT_VERBOSITY AM_DEFAULT_V AM_V am__untar am__tar AMTAR am__leading_dot SET_MAKE AWK mkdir_p MKDIR_P INSTALL_STRIP_PROGRAM STRIP install_sh MAKEINFO AUTOHEADER AUTOMAKE AUTOCONF ACLOCAL VERSION PACKAGE CYGPATH_W am__isrc INSTALL_DATA INSTALL_SCRIPT INSTALL_PROGRAM host_os host_vendor host_cpu host build_os build_vendor build_cpu build target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_silent_rules enable_dependency_tracking enable_optimize enable_debug enable_dump with_efence ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures qstat 2.15 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/qstat] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF Program names: --program-prefix=PREFIX prepend PREFIX to installed program names --program-suffix=SUFFIX append SUFFIX to installed program names --program-transform-name=PROGRAM run sed PROGRAM on installed program names System types: --build=BUILD configure for building on BUILD [guessed] --host=HOST cross-compile to build programs to run on HOST [BUILD] _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of qstat 2.15:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-silent-rules less verbose build output (undo: "make V=1") --disable-silent-rules verbose build output (undo: "make V=0") --enable-dependency-tracking do not reject slow dependency extractors --disable-dependency-tracking speeds up one-time build --disable-optimize turn off optimization --disable-debug turn off debugging code --enable-dump enable packet dumps Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-efence= Use electric fence for malloc debugging. Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L if you have libraries in a nonstandard directory LIBS libraries to pass to the linker, e.g. -l CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to . _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF qstat configure 2.15 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_c_try_cpp LINENO # ---------------------- # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_cpp # ac_fn_c_try_run LINENO # ---------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_c_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_run # ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_c_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ( $as_echo "## ------------------------------------------ ## ## Report this to qstat-users@yahoogroups.com ## ## ------------------------------------------ ##" ) | sed "s/^/$as_me: WARNING: /" >&2 ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_mongrel # ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES # ------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_c_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_c_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_c_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by qstat $as_me 2.15, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_config_headers="$ac_config_headers gnuconfig.h" ac_aux_dir= for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do if test -f "$ac_dir/install-sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install-sh -c" break elif test -f "$ac_dir/install.sh"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/install.sh -c" break elif test -f "$ac_dir/shtool"; then ac_aux_dir=$ac_dir ac_install_sh="$ac_aux_dir/shtool install -c" break fi done if test -z "$ac_aux_dir"; then as_fn_error $? "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 fi # These three variables are undocumented and unsupported, # and are intended to be withdrawn in a future Autoconf release. # They can cause serious problems if a builder's source tree is in a directory # whose full name contains unusual characters. ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. # Make sure we can run config.sub. $SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 { $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 $as_echo_n "checking build system type... " >&6; } if ${ac_cv_build+:} false; then : $as_echo_n "(cached) " >&6 else ac_build_alias=$build_alias test "x$ac_build_alias" = x && ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` test "x$ac_build_alias" = x && as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5 ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 $as_echo "$ac_cv_build" >&6; } case $ac_cv_build in *-*-*) ;; *) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;; esac build=$ac_cv_build ac_save_IFS=$IFS; IFS='-' set x $ac_cv_build shift build_cpu=$1 build_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: build_os=$* IFS=$ac_save_IFS case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 $as_echo_n "checking host system type... " >&6; } if ${ac_cv_host+:} false; then : $as_echo_n "(cached) " >&6 else if test "x$host_alias" = x; then ac_cv_host=$ac_cv_build else ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 $as_echo "$ac_cv_host" >&6; } case $ac_cv_host in *-*-*) ;; *) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;; esac host=$ac_cv_host ac_save_IFS=$IFS; IFS='-' set x $ac_cv_host shift host_cpu=$1 host_vendor=$2 shift; shift # Remember, the first character of IFS is used to create $*, # except with old shells: host_os=$* IFS=$ac_save_IFS case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac am__api_version='1.14' # Find a good install program. We prefer a C program (faster), # so one script is as good as another. But avoid the broken or # incompatible versions: # SysV /etc/install, /usr/sbin/install # SunOS /usr/etc/install # IRIX /sbin/install # AIX /bin/install # AmigaOS /C/install, which installs bootblocks on floppy discs # AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag # AFS /usr/afsws/bin/install, which mishandles nonexistent args # SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" # OS/2's system install, which has a completely different semantic # ./install, which can be erroneously created by make from ./install.sh. # Reject install programs that cannot install multiple files. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 $as_echo_n "checking for a BSD-compatible install... " >&6; } if test -z "$INSTALL"; then if ${ac_cv_path_install+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. # Account for people who put trailing slashes in PATH elements. case $as_dir/ in #(( ./ | .// | /[cC]/* | \ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ /usr/ucb/* ) ;; *) # OSF1 and SCO ODT 3.0 have their own names for install. # Don't use installbsd from OSF since it installs stuff as root # by default. for ac_prog in ginstall scoinst install; do for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then if test $ac_prog = install && grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # AIX install. It has an incompatible calling convention. : elif test $ac_prog = install && grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then # program-specific install script used by HP pwplus--don't use. : else rm -rf conftest.one conftest.two conftest.dir echo one > conftest.one echo two > conftest.two mkdir conftest.dir if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && test -s conftest.one && test -s conftest.two && test -s conftest.dir/conftest.one && test -s conftest.dir/conftest.two then ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" break 3 fi fi fi done done ;; esac done IFS=$as_save_IFS rm -rf conftest.one conftest.two conftest.dir fi if test "${ac_cv_path_install+set}" = set; then INSTALL=$ac_cv_path_install else # As a last resort, use the slow shell script. Don't cache a # value for INSTALL within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. INSTALL=$ac_install_sh fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 $as_echo "$INSTALL" >&6; } # Use test -z because SunOS4 sh mishandles braces in ${var-val}. # It thinks the first close brace ends the variable substitution. test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 $as_echo_n "checking whether build environment is sane... " >&6; } # Reject unsafe characters in $srcdir or the absolute working directory # name. Accept space and tab only in the latter. am_lf=' ' case `pwd` in *[\\\"\#\$\&\'\`$am_lf]*) as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;; esac case $srcdir in *[\\\"\#\$\&\'\`$am_lf\ \ ]*) as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;; esac # Do 'set' in a subshell so we don't clobber the current shell's # arguments. Must try -L first in case configure is actually a # symlink; some systems play weird games with the mod time of symlinks # (eg FreeBSD returns the mod time of the symlink's containing # directory). if ( am_has_slept=no for am_try in 1 2; do echo "timestamp, slept: $am_has_slept" > conftest.file set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` if test "$*" = "X"; then # -L didn't work. set X `ls -t "$srcdir/configure" conftest.file` fi if test "$*" != "X $srcdir/configure conftest.file" \ && test "$*" != "X conftest.file $srcdir/configure"; then # If neither matched, then we have a broken ls. This can happen # if, for instance, CONFIG_SHELL is bash and it inherits a # broken ls alias from the environment. This has actually # happened. Such a system could not be considered "sane". as_fn_error $? "ls -t appears to fail. Make sure there is not a broken alias in your environment" "$LINENO" 5 fi if test "$2" = conftest.file || test $am_try -eq 2; then break fi # Just in case. sleep 1 am_has_slept=yes done test "$2" = conftest.file ) then # Ok. : else as_fn_error $? "newly created file is older than distributed files! Check your system clock" "$LINENO" 5 fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } # If we didn't sleep, we still need to ensure time stamps of config.status and # generated files are strictly newer. am_sleep_pid= if grep 'slept: no' conftest.file >/dev/null 2>&1; then ( sleep 1 ) & am_sleep_pid=$! fi rm -f conftest.file test "$program_prefix" != NONE && program_transform_name="s&^&$program_prefix&;$program_transform_name" # Use a double $ so make ignores it. test "$program_suffix" != NONE && program_transform_name="s&\$&$program_suffix&;$program_transform_name" # Double any \ or $. # By default was `s,x,x', remove it if useless. ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` # expand $ac_aux_dir to an absolute path am_aux_dir=`cd $ac_aux_dir && pwd` if test x"${MISSING+set}" != xset; then case $am_aux_dir in *\ * | *\ *) MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; *) MISSING="\${SHELL} $am_aux_dir/missing" ;; esac fi # Use eval to expand $SHELL if eval "$MISSING --is-lightweight"; then am_missing_run="$MISSING " else am_missing_run= { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5 $as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;} fi if test x"${install_sh}" != xset; then case $am_aux_dir in *\ * | *\ *) install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; *) install_sh="\${SHELL} $am_aux_dir/install-sh" esac fi # Installed binaries are usually stripped using 'strip' when the user # run "make install-strip". However 'strip' might not be the right # tool to use in cross-compilation environments, therefore Automake # will honor the 'STRIP' environment variable to overrule this program. if test "$cross_compiling" != no; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. set dummy ${ac_tool_prefix}strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$STRIP"; then ac_cv_prog_STRIP="$STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_STRIP="${ac_tool_prefix}strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi STRIP=$ac_cv_prog_STRIP if test -n "$STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 $as_echo "$STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_STRIP"; then ac_ct_STRIP=$STRIP # Extract the first word of "strip", so it can be a program name with args. set dummy strip; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_STRIP+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_STRIP"; then ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_STRIP="strip" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP if test -n "$ac_ct_STRIP"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 $as_echo "$ac_ct_STRIP" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_STRIP" = x; then STRIP=":" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac STRIP=$ac_ct_STRIP fi else STRIP="$ac_cv_prog_STRIP" fi fi INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 $as_echo_n "checking for a thread-safe mkdir -p... " >&6; } if test -z "$MKDIR_P"; then if ${ac_cv_path_mkdir+:} false; then : $as_echo_n "(cached) " >&6 else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in mkdir gmkdir; do for ac_exec_ext in '' $ac_executable_extensions; do as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( 'mkdir (GNU coreutils) '* | \ 'mkdir (coreutils) '* | \ 'mkdir (fileutils) '4.1*) ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext break 3;; esac done done done IFS=$as_save_IFS fi test -d ./--version && rmdir ./--version if test "${ac_cv_path_mkdir+set}" = set; then MKDIR_P="$ac_cv_path_mkdir -p" else # As a last resort, use the slow shell script. Don't cache a # value for MKDIR_P within a source directory, because that will # break other packages using the cache if that directory is # removed, or if the value is a relative name. MKDIR_P="$ac_install_sh -d" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 $as_echo "$MKDIR_P" >&6; } for ac_prog in gawk mawk nawk awk do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_AWK+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$AWK"; then ac_cv_prog_AWK="$AWK" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_AWK="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi AWK=$ac_cv_prog_AWK if test -n "$AWK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 $as_echo "$AWK" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$AWK" && break done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 $as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } set x ${MAKE-make} ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then : $as_echo_n "(cached) " >&6 else cat >conftest.make <<\_ACEOF SHELL = /bin/sh all: @echo '@@@%%%=$(MAKE)=@@@%%%' _ACEOF # GNU make sometimes prints "make[1]: Entering ...", which would confuse us. case `${MAKE-make} -f conftest.make 2>/dev/null` in *@@@%%%=?*=@@@%%%*) eval ac_cv_prog_make_${ac_make}_set=yes;; *) eval ac_cv_prog_make_${ac_make}_set=no;; esac rm -f conftest.make fi if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } SET_MAKE= else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } SET_MAKE="MAKE=${MAKE-make}" fi rm -rf .tst 2>/dev/null mkdir .tst 2>/dev/null if test -d .tst; then am__leading_dot=. else am__leading_dot=_ fi rmdir .tst 2>/dev/null # Check whether --enable-silent-rules was given. if test "${enable_silent_rules+set}" = set; then : enableval=$enable_silent_rules; fi case $enable_silent_rules in # ((( yes) AM_DEFAULT_VERBOSITY=0;; no) AM_DEFAULT_VERBOSITY=1;; *) AM_DEFAULT_VERBOSITY=1;; esac am_make=${MAKE-make} { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5 $as_echo_n "checking whether $am_make supports nested variables... " >&6; } if ${am_cv_make_support_nested_variables+:} false; then : $as_echo_n "(cached) " >&6 else if $as_echo 'TRUE=$(BAR$(V)) BAR0=false BAR1=true V=1 am__doit: @$(TRUE) .PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then am_cv_make_support_nested_variables=yes else am_cv_make_support_nested_variables=no fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5 $as_echo "$am_cv_make_support_nested_variables" >&6; } if test $am_cv_make_support_nested_variables = yes; then AM_V='$(V)' AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)' else AM_V=$AM_DEFAULT_VERBOSITY AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY fi AM_BACKSLASH='\' if test "`cd $srcdir && pwd`" != "`pwd`"; then # Use -I$(srcdir) only when $(srcdir) != ., so that make's output # is not polluted with repeated "-I." am__isrc=' -I$(srcdir)' # test to see if srcdir already configured if test -f $srcdir/config.status; then as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 fi fi # test whether we have cygpath if test -z "$CYGPATH_W"; then if (cygpath --version) >/dev/null 2>/dev/null; then CYGPATH_W='cygpath -w' else CYGPATH_W=echo fi fi # Define the identity of the package. PACKAGE='qstat' VERSION='2.15' cat >>confdefs.h <<_ACEOF #define PACKAGE "$PACKAGE" _ACEOF cat >>confdefs.h <<_ACEOF #define VERSION "$VERSION" _ACEOF # Some tools Automake needs. ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} # For better backward compatibility. To be removed once Automake 1.9.x # dies out for good. For more background, see: # # mkdir_p='$(MKDIR_P)' # We need awk for the "check" target. The system "awk" is bad on # some platforms. # Always define AMTAR for backward compatibility. Yes, it's still used # in the wild :-( We should find a proper way to deprecate it ... AMTAR='$${TAR-tar}' # We'll loop over all known methods to create a tar archive until one works. _am_tools='gnutar pax cpio none' am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -' # POSIX will say in a future version that running "rm -f" with no argument # is OK; and we want to be able to make that assumption in our Makefile # recipes. So use an aggressive probe to check that the usage we want is # actually supported "in the wild" to an acceptable degree. # See automake bug#10828. # To make any issue more visible, cause the running configure to be aborted # by default if the 'rm' program in use doesn't match our expectations; the # user can still override this though. if rm -f && rm -fr && rm -rf; then : OK; else cat >&2 <<'END' Oops! Your 'rm' program seems unable to run without file operands specified on the command line, even when the '-f' option is present. This is contrary to the behaviour of most rm programs out there, and not conforming with the upcoming POSIX standard: Please tell bug-automake@gnu.org about your system, including the value of your $PATH and any error possibly output before this message. This can help us improve future automake versions. END if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then echo 'Configuration will proceed anyway, since you have set the' >&2 echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2 echo >&2 else cat >&2 <<'END' Aborting the configuration process, to ensure you take notice of the issue. You can download and install GNU coreutils to get an 'rm' implementation that behaves properly: . If you want to complete the configuration process using your problematic 'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM to "yes", and re-run configure. END as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5 fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include struct stat; /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5 $as_echo_n "checking whether $CC understands -c and -o together... " >&6; } if ${am_cv_prog_cc_c_o+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF # Make sure it works both with $CC and with simple cc. # Following AC_PROG_CC_C_O, we do the test twice because some # compilers refuse to overwrite an existing .o file with -o, # though they will create one. am_cv_prog_cc_c_o=yes for am_i in 1 2; do if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5 ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5 ac_status=$? echo "$as_me:$LINENO: \$? = $ac_status" >&5 (exit $ac_status); } \ && test -f conftest2.$ac_objext; then : OK else am_cv_prog_cc_c_o=no break fi done rm -f core conftest* unset am_i fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5 $as_echo "$am_cv_prog_cc_c_o" >&6; } if test "$am_cv_prog_cc_c_o" != yes; then # Losing compiler, so override with the script. # FIXME: It is wrong to rewrite CC. # But if we don't then we get into trouble of one sort or another. # A longer-term fix would be to have automake use am__CC in this case, # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" CC="$am_aux_dir/compile $CC" fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu DEPDIR="${am__leading_dot}deps" ac_config_commands="$ac_config_commands depfiles" am_make=${MAKE-make} cat > confinc << 'END' am__doit: @echo this is the am__doit target .PHONY: am__doit END # If we don't find an include directive, just comment out the code. { $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 $as_echo_n "checking for style of include used by $am_make... " >&6; } am__include="#" am__quote= _am_result=none # First try GNU make style include. echo "include confinc" > confmf # Ignore all kinds of additional output from 'make'. case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=include am__quote= _am_result=GNU ;; esac # Now try BSD make style include. if test "$am__include" = "#"; then echo '.include "confinc"' > confmf case `$am_make -s -f confmf 2> /dev/null` in #( *the\ am__doit\ target*) am__include=.include am__quote="\"" _am_result=BSD ;; esac fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 $as_echo "$_am_result" >&6; } rm -f confinc confmf # Check whether --enable-dependency-tracking was given. if test "${enable_dependency_tracking+set}" = set; then : enableval=$enable_dependency_tracking; fi if test "x$enable_dependency_tracking" != xno; then am_depcomp="$ac_aux_dir/depcomp" AMDEPBACKSLASH='\' am__nodep='_no' fi if test "x$enable_dependency_tracking" != xno; then AMDEP_TRUE= AMDEP_FALSE='#' else AMDEP_TRUE='#' AMDEP_FALSE= fi depcc="$CC" am_compiler_list= { $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 $as_echo_n "checking dependency style of $depcc... " >&6; } if ${am_cv_CC_dependencies_compiler_type+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then # We make a subdir and do the tests there. Otherwise we can end up # making bogus files that we don't know about and never remove. For # instance it was reported that on HP-UX the gcc test will end up # making a dummy file named 'D' -- because '-MD' means "put the output # in D". rm -rf conftest.dir mkdir conftest.dir # Copy depcomp to subdir because otherwise we won't find it if we're # using a relative directory. cp "$am_depcomp" conftest.dir cd conftest.dir # We will build objects and dependencies in a subdirectory because # it helps to detect inapplicable dependency modes. For instance # both Tru64's cc and ICC support -MD to output dependencies as a # side effect of compilation, but ICC will put the dependencies in # the current directory while Tru64 will put them in the object # directory. mkdir sub am_cv_CC_dependencies_compiler_type=none if test "$am_compiler_list" = ""; then am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` fi am__universal=false case " $depcc " in #( *\ -arch\ *\ -arch\ *) am__universal=true ;; esac for depmode in $am_compiler_list; do # Setup a source with many dependencies, because some compilers # like to wrap large dependency lists on column 80 (with \), and # we should not choose a depcomp mode which is confused by this. # # We need to recreate these files for each test, as the compiler may # overwrite some of them when testing with obscure command lines. # This happens at least with the AIX C compiler. : > sub/conftest.c for i in 1 2 3 4 5 6; do echo '#include "conftst'$i'.h"' >> sub/conftest.c # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with # Solaris 10 /bin/sh. echo '/* dummy */' > sub/conftst$i.h done echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf # We check with '-c' and '-o' for the sake of the "dashmstdout" # mode. It turns out that the SunPro C++ compiler does not properly # handle '-M -o', and we need to detect this. Also, some Intel # versions had trouble with output in subdirs. am__obj=sub/conftest.${OBJEXT-o} am__minus_obj="-o $am__obj" case $depmode in gcc) # This depmode causes a compiler race in universal mode. test "$am__universal" = false || continue ;; nosideeffect) # After this tag, mechanisms are not by side-effect, so they'll # only be used when explicitly requested. if test "x$enable_dependency_tracking" = xyes; then continue else break fi ;; msvc7 | msvc7msys | msvisualcpp | msvcmsys) # This compiler won't grok '-c -o', but also, the minuso test has # not run yet. These depmodes are late enough in the game, and # so weak that their functioning should not be impacted. am__obj=conftest.${OBJEXT-o} am__minus_obj= ;; none) break ;; esac if depmode=$depmode \ source=sub/conftest.c object=$am__obj \ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ >/dev/null 2>conftest.err && grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && grep $am__obj sub/conftest.Po > /dev/null 2>&1 && ${MAKE-make} -s -f confmf > /dev/null 2>&1; then # icc doesn't choke on unknown options, it will just issue warnings # or remarks (even with -Werror). So we grep stderr for any message # that says an option was ignored or not supported. # When given -MP, icc 7.0 and 7.1 complain thusly: # icc: Command line warning: ignoring option '-M'; no argument required # The diagnosis changed in icc 8.0: # icc: Command line remark: option '-MP' not supported if (grep 'ignoring option' conftest.err || grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else am_cv_CC_dependencies_compiler_type=$depmode break fi fi done cd .. rm -rf conftest.dir else am_cv_CC_dependencies_compiler_type=none fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 $as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type if test "x$enable_dependency_tracking" != xno \ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then am__fastdepCC_TRUE= am__fastdepCC_FALSE='#' else am__fastdepCC_TRUE='#' am__fastdepCC_FALSE= fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5 $as_echo_n "checking how to run the C preprocessor... " >&6; } # On Suns, sometimes $CPP names a directory. if test -n "$CPP" && test -d "$CPP"; then CPP= fi if test -z "$CPP"; then if ${ac_cv_prog_CPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CPP needs to be expanded for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" do ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CPP=$CPP fi CPP=$ac_cv_prog_CPP else ac_cv_prog_CPP=$CPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5 $as_echo "$CPP" >&6; } ac_preproc_ok=false for ac_c_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer to if __STDC__ is defined, since # exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include #else # include #endif Syntax error _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if ac_fn_c_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C preprocessor \"$CPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_GREP" || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" as_fn_executable_p "$ac_path_EGREP" || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include #include int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_c_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default" if test "x$ac_cv_header_sys_mman_h" = xyes; then : have_mman_h=yes fi case $host in *mingw32*) { $as_echo "$as_me:${as_lineno-$LINENO}: compiling for $host, adding -lwsock32" >&5 $as_echo "$as_me: compiling for $host, adding -lwsock32" >&6;} LIBS="$LIBS -lwsock32" ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for strnstr" >&5 $as_echo_n "checking for strnstr... " >&6; } if ${ac_cv_func_strnstr+:} false; then : $as_echo_n "(cached) " >&6 else if test "$cross_compiling" = yes; then : { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run test program while cross compiling See \`config.log' for more details" "$LINENO" 5; } else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include #include #include // we expect this to succeed, or crash on over-run. // if it passes otherwise we may need a better check. int main(int argc, char **argv) { int size = 20; char *str = malloc(size); memset(str, 'x', size); strnstr(str, "fubar", size); return 0; } _ACEOF if ac_fn_c_try_run "$LINENO"; then : ac_cv_func_strnstr="yes" else ac_cv_func_strnstr="no" fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_strnstr" >&5 $as_echo "$ac_cv_func_strnstr" >&6; } if test "$ac_cv_func_strnstr" = "yes" ; then $as_echo "#define HAVE_STRNSTR 1" >>confdefs.h else $as_echo "#define HAVE_STRNSTR 0" >>confdefs.h fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable optimization" >&5 $as_echo_n "checking whether to enable optimization... " >&6; } # Check whether --enable-optimize was given. if test "${enable_optimize+set}" = set; then : enableval=$enable_optimize; fi if test x$enable_optimize != xno; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else CPPFLAGS="" CFLAGS="-ggdb" { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debug output" >&5 $as_echo_n "checking whether to enable debug output... " >&6; } # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi if test x$enable_debug != xno; then CPPFLAGS="$CPPFLAGS -DDEBUG" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable packet dumps" >&5 $as_echo_n "checking whether to enable packet dumps... " >&6; } # Check whether --enable-dump was given. if test "${enable_dump+set}" = set; then : enableval=$enable_dump; fi if test x$enable_dump != xno; then if test x$have_mman_h = xyes; then CPPFLAGS="$CPPFLAGS -DENABLE_DUMP" { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, sys/mman.h missing" >&5 $as_echo "no, sys/mman.h missing" >&6; } fi else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi # Check whether --with-efence was given. if test "${with_efence+set}" = set; then : withval=$with_efence; if test x$withval != xyes ; then LDFLAGS="${LDFLAGS} -L$withval" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for malloc in -lefence" >&5 $as_echo_n "checking for malloc in -lefence... " >&6; } if ${ac_cv_lib_efence_malloc+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lefence $LIBS" # ac_fn_c_try_link LINENO # ----------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || test -x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_link cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ /* Override any GCC internal prototype to avoid an error. Use char because int might match the return type of a GCC builtin and then its argument prototype would still apply. */ #ifdef __cplusplus extern "C" #endif char malloc (); int main () { return malloc (); ; return 0; } _ACEOF if ac_fn_c_try_link "$LINENO"; then : ac_cv_lib_efence_malloc=yes else ac_cv_lib_efence_malloc=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_efence_malloc" >&5 $as_echo "$ac_cv_lib_efence_malloc" >&6; } if test "x$ac_cv_lib_efence_malloc" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBEFENCE 1 _ACEOF LIBS="-lefence $LIBS" fi fi if test "x$GCC" = "xyes"; then case " $CFLAGS " in *[\ \ ]-Wall[\ \ ]*) ;; *) CFLAGS="$CFLAGS -Wall" ;; esac fi ac_config_files="$ac_config_files Makefile template/Makefile info/Makefile" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' DEFS=-DHAVE_CONFIG_H ac_libobjs= ac_ltlibobjs= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs { $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5 $as_echo_n "checking that generated files are newer than configure... " >&6; } if test -n "$am_sleep_pid"; then # Hide warnings about reused PIDs. wait $am_sleep_pid 2>/dev/null fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5 $as_echo "done" >&6; } if test -n "$EXEEXT"; then am__EXEEXT_TRUE= am__EXEEXT_FALSE='#' else am__EXEEXT_TRUE='#' am__EXEEXT_FALSE= fi if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then as_fn_error $? "conditional \"AMDEP\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then as_fn_error $? "conditional \"am__fastdepCC\" was never defined. Usually this means the macro was only invoked conditionally." "$LINENO" 5 fi : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -pR'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -pR' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -pR' fi else as_ln_s='cp -pR' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi # as_fn_executable_p FILE # ----------------------- # Test if FILE is an executable regular file. as_fn_executable_p () { test -f "$1" && test -x "$1" } # as_fn_executable_p as_test_x='test -x' as_executable_p=as_fn_executable_p # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by qstat $as_me 2.15, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac case $ac_config_headers in *" "*) set x $ac_config_headers; shift; ac_config_headers=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" config_headers="$ac_config_headers" config_commands="$ac_config_commands" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE --header=FILE[:TEMPLATE] instantiate the configuration header FILE Configuration files: $config_files Configuration headers: $config_headers Configuration commands: $config_commands Report bugs to ." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ qstat config.status 2.15 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" Copyright (C) 2012 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' INSTALL='$INSTALL' MKDIR_P='$MKDIR_P' AWK='$AWK' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --header | --heade | --head | --hea ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; esac as_fn_append CONFIG_HEADERS " '$ac_optarg'" ac_need_defaults=false;; --he | --h) # Conflict between --help and --header as_fn_error $? "ambiguous option: \`$1' Try \`$0 --help' for more information.";; --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # # INIT-COMMANDS # AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "gnuconfig.h") CONFIG_HEADERS="$CONFIG_HEADERS gnuconfig.h" ;; "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "template/Makefile") CONFIG_FILES="$CONFIG_FILES template/Makefile" ;; "info/Makefile") CONFIG_FILES="$CONFIG_FILES info/Makefile" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' >$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" # Set up the scripts for CONFIG_HEADERS section. # No need to generate them if there are no CONFIG_HEADERS. # This happens for instance with `./config.status Makefile'. if test -n "$CONFIG_HEADERS"; then cat >"$ac_tmp/defines.awk" <<\_ACAWK || BEGIN { _ACEOF # Transform confdefs.h into an awk script `defines.awk', embedded as # here-document in config.status, that substitutes the proper values into # config.h.in to produce config.h. # Create a delimiter string that does not exist in confdefs.h, to ease # handling of long lines. ac_delim='%!_!# ' for ac_last_try in false false :; do ac_tt=`sed -n "/$ac_delim/p" confdefs.h` if test -z "$ac_tt"; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done # For the awk script, D is an array of macro values keyed by name, # likewise P contains macro parameters if any. Preserve backslash # newline sequences. ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* sed -n ' s/.\{148\}/&'"$ac_delim"'/g t rset :rset s/^[ ]*#[ ]*define[ ][ ]*/ / t def d :def s/\\$// t bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3"/p s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p d :bsnl s/["\\]/\\&/g s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\ D["\1"]=" \3\\\\\\n"\\/p t cont s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p t cont d :cont n s/.\{148\}/&'"$ac_delim"'/g t clear :clear s/\\$// t bsnlc s/["\\]/\\&/g; s/^/"/; s/$/"/p d :bsnlc s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p b cont ' >$CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 for (key in D) D_is_set[key] = 1 FS = "" } /^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ { line = \$ 0 split(line, arg, " ") if (arg[1] == "#") { defundef = arg[2] mac1 = arg[3] } else { defundef = substr(arg[1], 2) mac1 = arg[2] } split(mac1, mac2, "(") #) macro = mac2[1] prefix = substr(line, 1, index(line, defundef) - 1) if (D_is_set[macro]) { # Preserve the white space surrounding the "#". print prefix "define", macro P[macro] D[macro] next } else { # Replace #undef with comments. This is necessary, for example, # in the case of _POSIX_SOURCE, which is predefined and required # on some systems where configure will not decide to define it. if (defundef == "undef") { print "/*", prefix defundef, macro, "*/" next } } } { print } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 as_fn_error $? "could not setup config headers machinery" "$LINENO" 5 fi # test -n "$CONFIG_HEADERS" eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS" shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # case $INSTALL in [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; esac ac_MKDIR_P=$MKDIR_P case $MKDIR_P in [\\/$]* | ?:[\\/]* ) ;; */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; esac _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t s&@INSTALL@&$ac_INSTALL&;t t s&@MKDIR_P@&$ac_MKDIR_P&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; :H) # # CONFIG_HEADER # if test x"$ac_file" != x-; then { $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" } >"$ac_tmp/config.h" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5 $as_echo "$as_me: $ac_file is unchanged" >&6;} else rm -f "$ac_file" mv "$ac_tmp/config.h" "$ac_file" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 fi else $as_echo "/* $configure_input */" \ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \ || as_fn_error $? "could not create -" "$LINENO" 5 fi # Compute "$ac_file"'s index in $config_headers. _am_arg="$ac_file" _am_stamp_count=1 for _am_header in $config_headers :; do case $_am_header in $_am_arg | $_am_arg:* ) break ;; * ) _am_stamp_count=`expr $_am_stamp_count + 1` ;; esac done echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" || $as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$_am_arg" : 'X\(//\)[^/]' \| \ X"$_am_arg" : 'X\(//\)$' \| \ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$_am_arg" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'`/stamp-h$_am_stamp_count ;; :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 $as_echo "$as_me: executing $ac_file commands" >&6;} ;; esac case $ac_file$ac_mode in "depfiles":C) test x"$AMDEP_TRUE" != x"" || { # Older Autoconf quotes --file arguments for eval, but not when files # are listed without --file. Let's play safe and only enable the eval # if we detect the quoting. case $CONFIG_FILES in *\'*) eval set x "$CONFIG_FILES" ;; *) set x $CONFIG_FILES ;; esac shift for mf do # Strip MF so we end up with the name of the file. mf=`echo "$mf" | sed -e 's/:.*$//'` # Check whether this is an Automake generated Makefile or not. # We used to match only the files named 'Makefile.in', but # some people rename them; so instead we look at the file content. # Grep'ing the first line is not enough: some people post-process # each Makefile.in and add a new line on top of each file to say so. # Grep'ing the whole file is not good either: AIX grep has a line # limit of 2048, but all sed's we know have understand at least 4000. if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then dirpart=`$as_dirname -- "$mf" || $as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$mf" : 'X\(//\)[^/]' \| \ X"$mf" : 'X\(//\)$' \| \ X"$mf" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$mf" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` else continue fi # Extract the definition of DEPDIR, am__include, and am__quote # from the Makefile without running 'make'. DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` test -z "$DEPDIR" && continue am__include=`sed -n 's/^am__include = //p' < "$mf"` test -z "$am__include" && continue am__quote=`sed -n 's/^am__quote = //p' < "$mf"` # Find all dependency output files, they are included files with # $(DEPDIR) in their names. We invoke sed twice because it is the # simplest approach to changing $(DEPDIR) to its actual value in the # expansion. for file in `sed -n " s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do # Make sure the directory exists. test -f "$dirpart/$file" && continue fdir=`$as_dirname -- "$file" || $as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$file" : 'X\(//\)[^/]' \| \ X"$file" : 'X\(//\)$' \| \ X"$file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir=$dirpart/$fdir; as_fn_mkdir_p # echo "creating $dirpart/$file" echo '# dummy' > "$dirpart/$file" done done } ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi qstat-2.15/gs3.c0000644000175000017500000004710012420765614010367 00000000000000/* * qstat * by Steve Jankowski * * New Gamespy v3 query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #endif #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" int process_gs3_packet( struct qserver *server ); // Player headers #define PLAYER_NAME_HEADER 1 #define PLAYER_SCORE_HEADER 2 #define PLAYER_DEATHS_HEADER 3 #define PLAYER_PING_HEADER 4 #define PLAYER_KILLS_HEADER 5 #define PLAYER_TEAM_HEADER 6 #define PLAYER_OTHER_HEADER 7 // Team headers #define TEAM_NAME_HEADER 1 #define TEAM_OTHER_HEADER 2 // Challenge response algorithum // Before sending a qr2 query (type 0x00) the client must first send a // challenge request (type 0x09). The host will respond with the same // packet type containing a string signed integer. // // Once the challenge is received the client should convert the string to a // network byte order integer and embed it in the keys query. // // Example: // // challenge request: [0xFE][0xFD][0x09][0x.. 4-byte-instance] // challenge response: [0x09][0x.. 4-byte-instance]["-1287574694"] // query: [0xFE][0xFD][0x00][0x.. 4-byte-instance][0xb3412b5a "-1287574694"] // query_status_t deal_with_gs3_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *ptr = rawpkt; unsigned int pkt_id; int pkt_index; unsigned char flag; unsigned int pkti, final; debug( 2, "packet n_requests %d, retry1 %d, n_retries %d, delta %d", server->n_requests, server->retry1, n_retries, time_delta( &packet_recv_time, &server->packet_time1 ) ); server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); if ( 7 == pktlen && 0x09 == *ptr ) { // gs4 query sent to a gs3 server // switch protocols and try again // Correct the stats due to two phase protocol int i; server_type *gs3_type = &builtin_types[50]; debug( 3, "Attempting gs3 fallback from gs4" ); server->retry1++; if ( GAMESPY3_PROTOCOL_SERVER != gs3_type->id ) { // Static coding failure do it the hard way debug( 1, "gs3 static lookup failure, using dynamic lookup" ); for( i = 0; i < GAMESPY3_PROTOCOL_SERVER; i++ ) { if ( GAMESPY3_PROTOCOL_SERVER == builtin_types[i].id ) { // found it gs3_type = &builtin_types[i]; i = GAMESPY3_PROTOCOL_SERVER; } } if ( GAMESPY3_PROTOCOL_SERVER != gs3_type->id ) { malformed_packet( server, "GS3 protocol not found" ); return PKT_ERROR; } } server->type = gs3_type; return send_gs3_request_packet( server ); } if ( pktlen < 12 ) { // invalid packet? malformed_packet( server, "too short" ); return PKT_ERROR; } if ( 0x09 == *ptr ) { // challenge response // Could check the header here should // match the 4 byte id sent ptr++; memcpy( &pkt_id, ptr, 4 ); ptr += 4; server->challenge = atoi( ptr ); debug( 3, "Challenge: %ld", server->challenge ); server->retry1++; return send_gs3_request_packet( server ); } if ( 0x00 != *ptr ) { malformed_packet( server, "bad initial byte '%hhx'", *ptr ); return PKT_ERROR; } ptr++; server->n_servers++; // Could check the header here should // match the 4 byte id sent memcpy( &pkt_id, ptr, 4 ); ptr += 4; // Next we have the splitnum details if ( 0 != strncmp( ptr, "splitnum", 8 ) ) { if ( server->flags & TF_STATUS_QUERY ) { // we have the status response return deal_with_gs3_status( server, ptr, pktlen - ( ptr - rawpkt ) ); } else { malformed_packet( server, "missing splitnum" ); return PKT_ERROR; } } ptr += 9; pkt_index = ((unsigned char)*ptr) & 127; final = ((unsigned char)*ptr) >> 7; flag = *ptr++; pkti = *ptr++; debug( 1, "splitnum: flag = 0x%hhx, index = %d, final = %d, %d", flag, pkt_index, final, pkti ); if ( 0xFF != flag ) { // not a single packet response or a callback int pkt_max = pkt_index + 1; if ( ! final ) { // Guess that we have more to come pkt_max++; debug( 2, "more to come 0x%hhx 0x%hhx 0x%hhx", rawpkt[pktlen-3], rawpkt[pktlen-2], rawpkt[pktlen-1] ); } debug( 2, "pkt_max %d", pkt_max ); if ( 0 == pkt_index ) { // to prevent reprocessing when we get the call back // override the packet flag so it looks like a single // packet response rawpkt[14] = 0xFF; } // add the packet recalcing maxes if ( ! add_packet( server, pkt_id, pkt_index, 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 ); } // if we get here we have what should be a full packet return process_gs3_packet( server ); } query_status_t deal_with_gs3_status( struct qserver *server, char *rawpkt, int pktlen ) { char *pkt = rawpkt; debug( 1, "status packet" ); // Server name server->server_name = strdup( pkt ); pkt += strlen( pkt ) + 1; // gametype add_rule( server, "gametype", pkt, NO_FLAGS ); pkt += strlen( pkt ) + 1; // map // UT3 retail compatibility if ( 0 == strncmp( pkt, "OwningPlayerId", 13 ) ) { char *end = pkt + strlen( pkt ) + 1; char *var = pkt; while ( NULL != var ) { char *next; char *val = strstr( var, "=" ); *val = '\0'; val++; next = strstr( val, "," ); if ( NULL != next ) { *next = '\0'; next++; } if ( 0 == strcmp( var, "mapname" ) ) { if ( server->map_name ) { free( server->map_name ); } server->map_name = strdup( val ); } else if ( 0 == strcmp( var, "p1073741825" ) ) { if ( server->map_name ) { free( server->map_name ); } server->map_name = strdup( val ); } else if ( 0 == strcmp( var, "p1073741826" ) ) { add_rule( server, "gametype", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p268435705" ) ) { add_rule( server, "timelimit", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p1073741827" ) ) { add_rule( server, "description", val, OVERWITE_DUPLICATES ); #ifndef UT3_PATCHED if ( 0 != strlen( val ) ) { if ( server->server_name ) { char *name = (char*)realloc( server->server_name, strlen( server->server_name ) + strlen( val ) + 3 ); if ( name ) { strcat( name, ": " ); strcat( name, val ); server->server_name = name; } } server->server_name = strdup( val ); } #endif } else if ( 0 == strcmp( var, "p268435704" ) ) { add_rule( server, "goalscore", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "s32779" ) ) { add_rule( server, "gamemode", val, OVERWITE_DUPLICATES ); } else { add_rule( server, var, val, OVERWITE_DUPLICATES ); } var = next; } pkt = end; } else { server->map_name = strdup( pkt ); pkt += strlen( pkt ) + 1; } // num players server->num_players = atoi( pkt ); pkt += strlen( pkt ) + 1; // max_players server->max_players = atoi( pkt ); pkt += strlen( pkt ) + 1; // hostport change_server_port( server, atoi( pkt ), 0 ); pkt += strlen( pkt ) + 1; return DONE_FORCE; } int process_gs3_packet( struct qserver *server ) { unsigned char state = 0; unsigned char no_players = 0; unsigned char total_players = 0; unsigned char no_teams = 0; unsigned char total_teams = 0; int pkt_index = 0; SavedData *fragment; debug( 2, "processing packet..." ); while ( NULL != ( fragment = get_packet_fragment( pkt_index++ ) ) ) { int pktlen = fragment->datalen; char *ptr = fragment->data; char *end = ptr + pktlen; debug( 2, "processing fragment[%d]...", fragment->pkt_index ); if( 6 <= get_debug_level() ) { print_packet( server, ptr, pktlen ); } // check we have a full header if ( pktlen < 16 ) { // invalid packet? malformed_packet( server, "too short" ); return PKT_ERROR; } // skip over the header ptr += 16; while ( 0 == state && 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; if ( ptr + 1 >= end ) { debug( 4, "state = %d, %hhx, bytes left = %d", state, ptr[0], (int)(end - ptr) ); } else { debug( 4, "state = %d, %hhx, %hhx, bytes left = %d", state, ptr[0], ptr[1], (int)(end - ptr) ); } if ( 0x00 == ptr[0] && ( ptr + 1 >= end || 0x01 >= ptr[1] ) ) { // not quite sure of the significance of these bytes // but we use them as a check for end of section state = 1; ptr += 2; break; } var = ptr; var_len = strlen( var ); ptr += var_len + 1; if ( ptr + 1 > end ) { malformed_packet( server, "no rule value" ); return PKT_ERROR; } 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 ); add_rule( server, var, val, NO_FLAGS ); } 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" ) ) { // UT3 retail compatibility if ( 0 == strncmp( val, "OwningPlayerId", 13 ) ) { var = val; while ( NULL != var ) { char *next; char *val = strstr( var, "=" ); *val = '\0'; val++; next = strstr( val, "," ); if ( NULL != next ) { *next = '\0'; next++; } if ( 0 == strcmp( var, "mapname" ) ) { if ( server->map_name ) { free( server->map_name ); } server->map_name = strdup( val ); } else if ( 0 == strcmp( var, "p1073741825" ) ) { if ( server->map_name ) { free( server->map_name ); } server->map_name = strdup( val ); } else if ( 0 == strcmp( var, "p1073741826" ) ) { add_rule( server, "gametype", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p268435705" ) ) { add_rule( server, "timelimit", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p1073741827" ) ) { #ifndef UT3_PATCHED if ( 0 != strlen( val ) ) { if ( server->server_name ) { char *name = (char*)realloc( server->server_name, strlen( server->server_name ) + strlen( val ) + 3 ); if ( name ) { strcat( name, ": " ); strcat( name, val ); server->server_name = name; } } server->server_name = strdup( val ); } #endif } else if ( 0 == strcmp( var, "p268435704" ) ) { add_rule( server, "goalscore", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "s32779" ) ) { add_rule( server, "gamemode", val, OVERWITE_DUPLICATES ); } else { add_rule( server, var, val, OVERWITE_DUPLICATES ); } var = next; } } else { server->map_name = strdup( val ); } } else if( 0 == strcmp( var, "map" ) ) { // 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 == strcmp( var, "p1073741825" ) ) { // UT3 demo compatibility if ( server->map_name ) { free( server->map_name ); } server->map_name = strdup( val ); } else if ( 0 == strcmp( var, "p1073741826" ) ) { // UT3 demo compatibility add_rule( server, "gametype", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p268435705" ) ) { // UT3 demo compatibility add_rule( server, "timelimit", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "p1073741827" ) ) { // UT3 demo compatibility add_rule( server, "description", val, OVERWITE_DUPLICATES ); #ifndef UT3_PATCHED if ( 0 != strlen( val ) ) { if ( server->server_name ) { char *name = (char*)realloc( server->server_name, strlen( server->server_name ) + strlen( val ) + 3 ); if ( name ) { strcat( name, ": " ); strcat( name, val ); server->server_name = name; } } server->server_name = strdup( val ); } #endif } else if ( 0 == strcmp( var, "p268435704" ) ) { // UT3 demo compatibility add_rule( server, "goalscore", val, OVERWITE_DUPLICATES ); } else if ( 0 == strcmp( var, "s32779" ) ) { // UT3 demo compatibility add_rule( server, "gamemode", val, OVERWITE_DUPLICATES ); } else { add_rule( server, var, val, OVERWITE_DUPLICATES ); } } while ( 1 == state && ptr < end ) { // first we have the header char *header = ptr; int head_len = strlen( header ); int header_type; debug( 4, "state = %d, bytes left = %d, head_len = %d", state, (int)(end - ptr), head_len ); if ( 0 == head_len ) { // no more info debug( 3, "All done" ); return DONE_FORCE; } ptr += head_len + 1; if ( ptr >= end ) { // partial header, should be restarted in the next fragment debug( 5, "partial header '%s'", header ); // ensure gt than ptr++; break; } debug( 2, "player header '%s'", header ); // the next byte is the starting number total_players = *ptr++; if ( 0 == strcmp( header, "player_" ) || 0 == strcmp( header, "name_" ) ) { header_type = PLAYER_NAME_HEADER; } else if ( 0 == strcmp( header, "score_" ) ) { header_type = PLAYER_SCORE_HEADER; } else if ( 0 == strcmp( header, "deaths_" ) ) { header_type = PLAYER_DEATHS_HEADER; } else if ( 0 == strcmp( header, "ping_" ) ) { header_type = PLAYER_PING_HEADER; } else if ( 0 == strcmp( header, "kills_" ) ) { header_type = PLAYER_KILLS_HEADER; } else if ( 0 == strcmp( header, "team_" ) ) { header_type = PLAYER_TEAM_HEADER; } else { header_type = PLAYER_OTHER_HEADER; } while( ptr < end ) { // now each player details // add the player struct player *player; char *val; int val_len; // check for end of this headers player info if ( 0x00 == *ptr ) { debug( 3, "end of '%s' detail, %d bytes left", header, (int)(end - ptr) ); ptr++; // Note: can't check ( total_players != no_players ) here as we may have more packets if ( ptr < end && 0x00 == *ptr ) { debug( 3, "end of players" ); // end of all player headers / detail state = 2; ptr++; } break; } player = get_player_by_number( server, total_players ); if ( NULL == player ) { player = add_player( server, total_players ); } if ( ptr >= end ) { malformed_packet( server, "short player detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "Player[%d][%s]=%s\n", total_players, header, val ); // lets see what we got switch( header_type ) { case PLAYER_NAME_HEADER: player->name = strdup( val ); break; case PLAYER_SCORE_HEADER: player->score = atoi( val ); break; case PLAYER_DEATHS_HEADER: player->deaths = atoi( val ); break; case PLAYER_PING_HEADER: player->ping = atoi( val ); break; case PLAYER_KILLS_HEADER: player->frags = atoi( val ); break; case PLAYER_TEAM_HEADER: player->team = atoi( val ); break; case PLAYER_OTHER_HEADER: default: if ( '_' == header[head_len-1] ) { header[head_len-1] = '\0'; player_add_info( player, header, val, NO_FLAGS ); header[head_len-1] = '_'; } else { player_add_info( player, header, val, NO_FLAGS ); } break; } total_players++; if ( total_players > no_players ) { malformed_packet( server, "to many players %d > %d", total_players, no_players ); return PKT_ERROR; } } } debug( 4, "state = %d, bytes left = %d", state, (int)(end - ptr) ); if ( 2 == state && ptr < end ) { no_teams = (unsigned char)*ptr; ptr++; debug( 2, "No teams:%d\n", no_teams ); state = 3; } while ( 3 == state && ptr < end ) { // first we have the header char *header = ptr; int head_len = strlen( header ); int header_type; ptr += head_len + 1; if ( 0 == head_len ) { // no more info debug( 3, "All done" ); return DONE_FORCE; } if ( ptr >= end ) { // partial header, should be restarted in the next fragment debug( 5, "partial header '%s'", header ); break; } debug( 2, "team header '%s'", header ); if ( 0 == strcmp( header, "team_t" ) ) { header_type = TEAM_NAME_HEADER; } else { header_type = TEAM_OTHER_HEADER; } // the next byte is the starting number total_teams = *ptr++; while( ptr < end ) { // now each teams details char *val; int val_len; char rule[512]; if ( ptr >= end ) { malformed_packet( server, "short team detail" ); return PKT_ERROR; } val = ptr; val_len = strlen( val ); ptr += val_len + 1; debug( 2, "Team[%d][%s]=%s\n", total_teams, header, val ); // lets see what we got switch ( header_type ) { case TEAM_NAME_HEADER: // BF being stupid again teams 1 based instead of 0 players_set_teamname( server, total_teams + 1, val ); // N.B. yes no break case TEAM_OTHER_HEADER: default: // add as a server rule sprintf( rule, "%s%d", header, total_teams ); add_rule( server, rule, val, NO_FLAGS ); break; } total_teams++; if ( 0x00 == *ptr ) { // end of this headers teams ptr++; break; } } } } return DONE_FORCE; } query_status_t send_gs3_request_packet( struct qserver *server ) { char *packet; char query_buf[128]; int len; // In the old v3 protocol the doesnt seems to make a difference // to what the servers sends but in the challenge version it definitely does if ( get_player_info || get_server_rules ) { server->flags |= TF_PLAYER_QUERY|TF_RULES_QUERY; if ( server->challenge ) { // we've recieved a challenge response, send the query + challenge id len = sprintf( query_buf, "\xfe\xfd%c\x10\x20\x30\x40%c%c%c%c\xff\xff\xff\x01", 0x00, (unsigned char)(server->challenge >> 24), (unsigned char)(server->challenge >> 16), (unsigned char)(server->challenge >> 8), (unsigned char)(server->challenge >> 0) ); packet = query_buf; } else { // Either basic v3 protocol or challenge request packet = server->type->player_packet; len = server->type->player_len; } } else { server->flags |= TF_STATUS_QUERY; if ( server->challenge ) { // we've recieved a challenge response, send the query + challenge id len = sprintf( query_buf, "\xfe\xfd%c\x10\x20\x30\x40%c%c%c%c\x06\x01\x06\x05\x08\x0a\x04%c%c", 0x00, (unsigned char)(server->challenge >> 24), (unsigned char)(server->challenge >> 16), (unsigned char)(server->challenge >> 8), (unsigned char)(server->challenge >> 0), 0x00, 0x00 ); packet = query_buf; } else { // Either basic v3 protocol or challenge request packet = server->type->status_packet; len = server->type->status_len; } } return send_packet( server, packet, len ); } qstat-2.15/gs2.h0000644000175000017500000000066612420765614010401 00000000000000/* * qstat * by Steve Jankowski * * New Gamespy v2 query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_GS2_H #define QSTAT_GS2_H #include "qserver.h" // Packet processing methods query_status_t deal_with_gs2_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_gs2_request_packet( struct qserver *server ); #endif qstat-2.15/ksp.c0000644000175000017500000001232412420765614010470 00000000000000/* * qstat * by Steve Jankowski * * KSP query protocol * Copyright 2014 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "utils.h" #include "qstat.h" #include "md5.h" #include "packet_manip.h" char *decode_ksp_val(char *val) { // Very basic html conversion val = str_replace(val, """, "\""); return str_replace(val, "&", "&"); } query_status_t send_ksp_request_packet(struct qserver *server) { char buf[256]; server->saved_data.pkt_max = -1; sprintf(buf, "GET / HTTP/1.1\015\012User-Agent: qstat\015\012Host: %s:%d\015\012\015\012", server->host_name, server->port); return send_packet(server, buf, strlen(buf)); } query_status_t valid_ksp_response(struct qserver *server, char *rawpkt, int pktlen) { char *s; int len; int cnt = packet_count(server); if (0 == cnt && 0 != strncmp("HTTP/1.1 200 OK", rawpkt, 15)) { // not valid response debug(2, "Invalid"); return REQ_ERROR; } s = strnstr(rawpkt, "Content-Length: ", pktlen); if (s == NULL) { // not valid response debug(2, "Invalid (no content-length)"); return INPROGRESS; } s += 16; // TODO: remove this bug work around if (*s == ':') { s += 2; } if (sscanf(s, "%d", &len) != 1) { debug(2, "Invalid (no length)"); return INPROGRESS; } s = strnstr(rawpkt, "\015\012\015\012", pktlen); if (s == NULL) { debug(2, "Invalid (no end of header"); return INPROGRESS; } s += 4; if (pktlen != (s - rawpkt + len)) { debug(2, "Outstanding data"); return INPROGRESS; } debug(2, "Valid data"); return DONE_FORCE; } char *ksp_json_attrib(char *line, char *name) { char *q, *p, *val; p = strstr(line, name); if (p == NULL) { return NULL; } p += strlen(name); if (strlen(p) < 3) { return NULL; } p += 2; if (*p == '"') { // String p++; q = strchr(p, '"'); if (q == NULL) { return NULL; } } else { // Integer, bool etc q = strchr(p, ','); if (q == NULL) { return NULL; } } *q = '\0'; val = strdup(p); *q = '"'; debug(4, "%s = %s", name, val); return val; } query_status_t deal_with_ksp_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *val, *line; query_status_t state = INPROGRESS; debug(2, "processing..."); if (!server->combined) { state = valid_ksp_response(server, rawpkt, pktlen); server->retry1 = n_retries; if (server->n_requests == 0) { server->ping_total = time_delta(&packet_recv_time, &server->packet_time1); server->n_requests++; } switch (state) { case INPROGRESS: { // 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; 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); } case DONE_FORCE: break; // single packet response fall through default: return state; } } if (state != DONE_FORCE) { state = valid_ksp_response(server, rawpkt, pktlen); switch (state) { case DONE_FORCE: break; // actually process default: return state; } } // 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 = rawpkt; // Ensure we're null terminated (will only loose the last \x0a) s[pktlen - 1] = '\0'; s = decode_ksp_val(s); line = strtok(s, "\012"); // NOTE: id=XXX and msg=XXX will be processed by the mod following the one they where the response of while (line != NULL) { debug(4, "LINE: %s\n", line); if (strstr(line, "{") != NULL) { debug(1, "{..."); // { // "cheats":true, // "game_mode":"SANDBOX", // "lastPlayerActivity":81403, // "max_players":12, // "modControlSha":"e46569487926a3273f58e06a080b0747b0ae702ec1877906511fe2c29816528b", // "mod_control":1, // "player_count":0, // "players":"", // "port":6752, // "protocol_version":25, // "server_name":"Multiplay :: Online - Clanserver", // "universeSize":96576, // "version":"v0.1.5.6" // } // Server Name val = ksp_json_attrib(line, "server_name"); if (val != NULL) { server->server_name = val; } else { server->server_name = strdup("Unknown"); } // Map Name val = ksp_json_attrib(line, "mapName"); if (val != NULL) { server->map_name = val; } else { server->map_name = strdup("Default"); } // Max Players val = ksp_json_attrib(line, "max_players"); if (val != NULL) { server->max_players = atoi(val); free(val); } else { server->max_players = get_param_ui_value(server, "max_players", 1); } // Num Players val = ksp_json_attrib(line, "player_count"); if (val != NULL) { server->num_players = atoi(val); free(val); } else { server->num_players = 0; } } line = strtok(NULL, "\012"); } gettimeofday(&server->packet_time1, NULL); return DONE_FORCE; } qstat-2.15/qstat.cfg0000644000175000017500000001647612420765614011360 00000000000000# QStat configuration file # # See qstat documentation (qstatdoc.html) for instructions # http://www.qstat.org gametype SOF2S new extend Q3S name = Soldier of Fortune 2 default port = 20100 template var = SOLDIEROFFORTUNE2 game rule = gametype end # SOF2 public master: master.sof2.ravensoft.com # The 2003 protocol is for SOF2 1.01 # The 2004 protocol is for SOF2 1.02 gametype SOF2M new extend Q3M name = SOF2 Master default port = 20110 template var = SOF2MASTER master protocol = 2004 master query = SOF2FULL master for gametype = sof2s end # The 2002 protocol is for SOF2 1.0 gametype SOF2M1.0 new extend SOF2M name = SOF2 Master (1.0) master protocol = 2002 end gametype CRS new extend GPS name = Command and Conquer: Renegade default port = 25300 template var = CNCRENEGADE game rule = gametype end # MOHAA supports two status protocols, Gamespy and Quake 3. # Seems like servers support one or the other, but not both at the same time. # The Gamespy protocol returns player name, frags, ping, and deaths. gametype MAS new extend GPS name = Medal of Honor: Allied Assault default port = 12300 template var = MOHALLIEDASSAULT game rule = gametype end # MOHAA support for the Q3 protocol is broken and more limited. The # response to "getinfo" does not include the current and max players # (they're always zero). The response to "getstatus" has the correct # current and max players, but only reports player name and ping. # If -R or -P options are specified, then both "getinfo" and "getstatus" # are sent. Otherwise only "getinfo" is sent. gametype MAQS new extend Q3S name = Medal of Honor: Allied Assault (Q) default port = 12300 template var = MOHALLIEDASSAULT game rule = gametype status packet = \xff\xff\xff\xff\x02getinfo\n status2 packet = \xff\xff\xff\xff\x02getstatus\n end # Half-Life supports a Quake 2 style status protocol, but only for # basic status, there's no player or extended rule information. The # server rule names are different from HLS. gametype HLQS new extend Q2S name = Half-Life template var = HALFLIFE default port = 27015 game rule = gamedir status packet = \xff\xff\xff\xffinfostring\x00 end # Config for Serious Sam SMS gametype SMS new extend GPS name = Serious Sam default port = 25600 status port offset = 1 template var = SERIOUSSAM game rule = gametype end # Config for Medal of Honor: Allied Assault MHS gametype MHS new extend Q3S name = Medal of Honor: Allied Assault default port = 12204 template var = MOHALLIEDASSAULT game rule = gametype status packet = \377\377\377\377\002getinfo xxx status2 packet = \377\377\377\377\002getstatus xxx end # Config for Call of Duty gametype CODS new extend Q3S name = Call of Duty default port = 28960 template var = CALLOFDUTY game rule = gamename end gametype CODM new extend Q3M name = Call of Duty Master default port = 20510 template var = CODMASTER master protocol = 5 master for gametype = CODS master query = full empty end # Config for Call of Duty 2 gametype COD2S new extend Q3S name = Call of Duty 2 default port = 28960 template var = CALLOFDUTY2 game rule = gamename end gametype COD2M new extend Q3M name = Call of Duty 2 Master default port = 20710 template var = COD2MASTER master protocol = 118 master for gametype = COD2S master query = full empty end # Config for Call of Duty 4 gametype COD4S new extend Q3S name = Call of Duty 4 default port = 28960 template var = CALLOFDUTY4 game rule = gamename end gametype COD4M new extend Q3M name = Call of Duty 4 Master default port = 20810 template var = COD4MASTER master protocol = 6 master for gametype = COD4S master query = full empty end # Config for Call of Duty Word at War gametype WAWS new extend Q3S name = Call of Duty World at War default port = 28960 template var = CALLOFDUTYWAW game rule = gametype end # enemy territory gametype WOETS new extend Q3S name = Enemy Territory template var = ENEMYTERRITORY game rule = gamename end gametype WOETM new extend Q3M name = Enemy Territory Master template var = WOETSMASTER master protocol = 84 master for gametype = WOETS master query = end # NetPanzer > 0.1.6 gametype NETP new extend GPS name = NetPanzer template var = NETPANZER end gametype NETPM new extend GSM name = NetPanzer Master template var = NETPANZERMASTER master for gametype = NETP end gametype STMHL2 new extend STM name = Steam Master for HL2 template var = STEAMMASTERHL2 master for gametype = HL2S default port = 27011 end gametype STMA2S new extend STM name = Steam Master for A2S template var = STEAMMASTERA2S master for gametype = A2S default port = 27011 end gametype UT2004S new extend UT2S name = UT2004 template var = UT2004 end gametype UT2004M modify master for gametype = UT2004S end gametype NEXUIZS new extend Q3S name = Nexuiz template var = NEXUIZ game rule = gamename end gametype NEXUIZM new extend Q3M name = Nexuiz Master template var = NEXUIZMASTER default port = 27950 master packet = \377\377\377\377getservers Nexuiz %s %s master protocol = 3 master query = empty full master for gametype = NEXUIZS end gametype WARSOWS new extend Q2S name = Warsow default port = 44400 template var = WARSOW game rule = gamename status packet = \377\377\377\377getinfo status2 packet = \377\377\377\377getstatus end gametype WARSOWM new extend Q3M name = Warsow Master template var = WARSOWMASTER default port = 27950 master packet = \377\377\377\377getservers Warsow %s %s master protocol = 8 master query = empty full master for gametype = WARSOWS end gametype TREMULOUS new extend Q3S name = Tremulous template var = TREMULOUS game rule = gamename end gametype TREMULOUSM new extend Q3M name = Tremulous Master template var = TREMULOUSMASTER default port = 30710 master protocol = 69 master for gametype = TREMULOUS end gametype HLA2S new extend A2S name = Half-Life template var = HLA2S end gametype HLA2SM new extend STM master for gametype = HLA2S default port = 27010 end gametype PREYM new extend DM3M name = Prey Master template var = PREYMASTER default port = 27655 master query = empty full master for gametype = PREYS end gametype UT3S new extend GS4 name = UT3 default port = 6500 template var = UT3 end # ioq3 fork gametype OPENARENAS new extend Q3S name = OpenArena template var = OPENARENA game rule = gamename end gametype OPENARENAM new extend Q3M name = OpenArena Master template var = OPENARENAMASTER default port = 27950 master packet = \377\377\377\377getservers %s %s master protocol = 70 master query = empty full master for gametype = OPENARENAS end # ioq3 fork gametype IOURTS new extend Q3S name = ioUrbanTerror template var = IOURT game rule = gamename end gametype IOURTM new extend Q3M name = ioUrbanTerror Master template var = IOURTMASTER default port = 27950 master packet = \377\377\377\377getservers %s %s master protocol = 68 master query = empty full master for gametype = IOURTS end qstat-2.15/ts3.h0000644000175000017500000000065512420765614010415 00000000000000/* * qstat * by Steve Jankowski * * Teamspeak 3 protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_TS3_H #define QSTAT_TS3_H #include "qserver.h" // Packet processing methods query_status_t deal_with_ts3_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_ts3_request_packet( struct qserver *server ); #endif qstat-2.15/starmade.c0000644000175000017500000001241612420765614011475 00000000000000/* * qstat * by Steve Jankowski * * StarMade query protocol * Copyright 2013 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "utils.h" #include "packet_manip.h" typedef enum { SM_INT = 0x01, SM_LONG, SM_FLOAT, SM_STRING, SM_BOOLEAN, SM_BYTE, SM_SHORT, SM_BYTE_ARRAY } starmade_param_type; query_status_t send_starmade_request_packet(struct qserver *server) { char buf[13] = { 0x00, 0x00, 0x00, 0x09, 0x2a, 0xff, 0xff, 0x01, 0x6f, 0x00, 0x00, 0x00, 0x00 }; /* * Header * int(4) - packet length * byte - packet type : 0x2a = packet, 0x20 = ping, test = 0x64, logout = 0x41 * short(2) - packet id * byte - command id : 0x01 = status, 0x02 = exec * byte - command type : 0x6f = parameterised command, 0x84 = stream command * * Paramters * int(4) - paramter count * byte - paramter type : 1 = int, 2 = long, 3 = float, 4 = UTF8 string, 5 = boolean, 6 = byte, 7 = short, 8 = byte array * ... */ debug(3, "send_starmade_request_packet: state = %ld", server->challenge); return send_packet(server, buf, 13); } static query_status_t starmade_read_parameter(char **datap, int *datalen, void *val, int vlen, starmade_param_type type) { int size; if (**datap != type) { /* unexpected type */ debug(2, "Invalid type detected, expected 0x%02x got 0x%02x", type, **datap); return REQ_ERROR; } (*datap)++; (*datalen)--; switch(type) { case SM_INT: size = 4; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(uint32_t*)val = ((uint32_t)(*datap)[3]) | ((uint32_t)(*datap)[2] << 8) | ((uint32_t)(*datap)[1] << 16) | ((uint32_t)(*datap)[0] << 24); break; case SM_LONG: size = 8; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(uint64_t*)val = ((uint64_t)(*datap)[7]) | ((uint64_t)(*datap)[6] << 8) | ((uint64_t)(*datap)[5] << 16) | ((uint64_t)(*datap)[4] << 24) | ((uint64_t)(*datap)[3] << 32) | ((uint64_t)(*datap)[2] << 40) | ((uint64_t)(*datap)[1] << 48) | ((uint64_t)(*datap)[0] << 56); break; case SM_FLOAT: size = 4; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(uint32_t*)val = (uint32_t)(*datap)[3] | ((uint32_t)(*datap)[2] << 8) | ((uint32_t)(*datap)[1] << 16) | ((uint32_t)(*datap)[0] << 24); break; case SM_STRING: size = ((short)(*datap)[1]) | ((short)(*datap)[0] << 8); if (size > vlen || size > *datalen) { return MEM_ERROR; } (*datap) += 2; memcpy(val, *datap, size); ((char*)val)[size] = 0x00; break; case SM_BOOLEAN: size = 1; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(unsigned char*)val = **datap; break; case SM_BYTE: size = 1; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(unsigned char*)val = **datap; break; case SM_SHORT: size = 2; if (size > vlen || size > *datalen) { return MEM_ERROR; } *(short*)val = (short)(*datap)[1] | ((short)(*datap)[0] << 8); break; case SM_BYTE_ARRAY: debug(2, "Unsupport type 0x%02x requested / received", type); return REQ_ERROR; default: debug(2, "Unknown type 0x%02x requested / received", type); return REQ_ERROR; } (*datap) += size; (*datalen) -= size; return INPROGRESS; } query_status_t deal_with_starmade_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, buf[256]; int ret; debug(2, "processing..."); if (pktlen < 54) { // Invalid password return REQ_ERROR; } s = rawpkt; // TODO: continue reading / combining packets until we've read enough. debug(3, "packet: combined = %d, challenge = %ld", server->combined, server->challenge); // Packet Header // int - response size excluding header (12 bytes) s += 4; // long - ts?? s += 8; // Response Header // TODO: validate header details // byte - packet type s += 1; // short - packet id s += 2; // byte - command id s += 1; // byte - command type s += 1; // Parameters // int - paramater count s += 4; // byte - info version ret = starmade_read_parameter(&s, &pktlen, buf, sizeof(buf), SM_BYTE); if (ret != INPROGRESS) return ret; // float - version ret = starmade_read_parameter(&s, &pktlen, buf, sizeof(buf), SM_FLOAT); if (ret != INPROGRESS) return ret; // string - server name ret = starmade_read_parameter(&s, &pktlen, buf, sizeof(buf), SM_STRING); if (ret != INPROGRESS) return ret; server->server_name = strdup(buf); // string - description ret = starmade_read_parameter(&s, &pktlen, buf, sizeof(buf), SM_STRING); if (ret != INPROGRESS) return ret; // long - start time ret = starmade_read_parameter(&s, &pktlen, buf, sizeof(buf), SM_LONG); if (ret != INPROGRESS) return ret; // int - player count ret = starmade_read_parameter(&s, &pktlen, &server->num_players, sizeof(server->num_players), SM_INT); if (ret != INPROGRESS) return ret; // int - max players ret = starmade_read_parameter(&s, &pktlen, &server->max_players, sizeof(server->max_players), SM_INT); if (ret != INPROGRESS) return ret; gettimeofday(&server->packet_time1, NULL); server->map_name = strdup("default"); return DONE_FORCE; } qstat-2.15/gps.c0000644000175000017500000002432012420765615010464 00000000000000/* * qstat * by Steve Jankowski * * Gamespy query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" int gps_max_players( struct qserver *server ) { struct player *player; int no_players = 0; if ( 0 == server->num_players ) { return 0; } for ( player= server->players; player; player= player->next) { no_players++; } return ( no_players < server->num_players ) ? 1 : 0; } int gps_player_info_key( char *s, char *end) { static char *keys[] = { "frags_", "team_", "ping_", "species_", "race_", "deaths_", "score_", "enemy_", "player_", "keyhash_", "teamname_", "playername_", "keyhash_", "kills_", "queryid" }; int i; for ( i= 0; i < sizeof(keys)/sizeof(char*); i++) { int len= strlen(keys[i]); if ( s+len < end && strncmp( s, keys[i], len) == 0) { return len; } } return 0; } query_status_t send_gps_request_packet( struct qserver *server ) { return send_packet( server, server->type->status_packet, server->type->status_len ); } query_status_t deal_with_gps_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *key, *value, *end; struct player *player = NULL; int id_major=0, id_minor=0, final=0, player_num; char tmp[256]; debug( 2, "processing..." ); 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 ); } /* // We're using the saved_data a bit differently here to track received // packets. // pkt_id is the id_major from the \queryid\ // pkt_max is the total number of packets expected // pkt_index is a bit mask of the packets received. The id_minor of // \queryid\ provides packet numbers (1 through pkt_max). */ if ( server->saved_data.pkt_index == -1) { server->saved_data.pkt_index= 0; } rawpkt[pktlen]= '\0'; end= &rawpkt[pktlen]; s= rawpkt; while ( *s) { // find the '\' while ( *s && *s == '\\') { s++; } if ( !*s ) { // out of packet break; } // Start of key key = s; // while we still have data and its not a '\' while ( *s && *s != '\\') { s++; } if ( !*s ) { // out of packet break; } // Terminate the key *s++= '\0'; // Now for the value value = s; // while we still have data and its not a '\' while ( *s && *s != '\\') { s++; } if ( s[0] && s[1] ) { //fprintf( stderr, "%s = %s\n", key, value ); if ( ! isalpha((unsigned char)s[1]) ) { // escape char? s++; // while we still have data and its not a '\' while ( *s && *s != '\\') { s++; } } else if ( isalpha((unsigned char)s[1]) && 0 == strncmp( key, "player_", 7 ) && 0 != strcmp( key, "player_flags" ) ) { // possible '\' in player name if ( ! gps_player_info_key( s+1, end ) ) { // yep there was an escape in the player name s++; // while we still have data and its not a '\' while ( *s && *s != '\\') { s++; } } } } if ( *s) { *s++= '\0'; } //fprintf( stderr, "%s = %s\n", key, value ); if ( *value == '\0') { if ( strcmp( key, "final" ) == 0 ) { final= 1; if ( id_minor > server->saved_data.pkt_max ) { server->saved_data.pkt_max = id_minor; } continue; } } /* This must be done before looking for player info because "queryid" is a valid according to gps_player_info_key(). */ if ( strcmp( key, "queryid") == 0) { sscanf( value, "%d.%d", &id_major, &id_minor); if ( server->saved_data.pkt_id == 0) { server->saved_data.pkt_id = id_major; } if ( id_major == server->saved_data.pkt_id) { if ( id_minor > 0) { // pkt_index is bitmask of packets recieved server->saved_data.pkt_index |= 1 << (id_minor-1); } if ( final && id_minor > server->saved_data.pkt_max) { server->saved_data.pkt_max = id_minor; } } continue; } if ( player == NULL ) { int len = gps_player_info_key( key, end); if ( len ) { // We have player info int player_number = atoi( key + len ); player = get_player_by_number( server, player_number); // && gps_max_players( server ) due to bf1942 issue // where the actual no players is correct but more player // details are returned if ( player == NULL && gps_max_players( server ) ) { player = add_player( server, player_number ); if ( player ) { // init to -1 so we can tell if // we have team info player->team = -1; player->deaths = -999; } } } } if ( strcmp( key, "mapname") == 0 && !server->map_name) { server->map_name= strdup( value ); } else if ( strcmp( key, "hostname") == 0 && !server->server_name) { server->server_name= strdup( value ); } else if ( strcmp( key, "hostport") == 0) { change_server_port( server, atoi( value), 0 ); } else if ( strcmp( key, "maxplayers") == 0) { server->max_players= atoi( value ); } else if ( strcmp( key, "numplayers") == 0) { server->num_players= atoi( value); } else if ( strcmp( key, server->type->game_rule) == 0 && !server->game) { server->game= strdup( value ); add_rule( server, key, value, NO_FLAGS); } else if ( strcmp( key, "final") == 0) { final= 1; if ( id_minor > server->saved_data.pkt_max) { server->saved_data.pkt_max = id_minor; } continue; } else if ( strncmp( key, "player_", 7) == 0 || strncmp( key, "playername_", 11) == 0 ) { int no; if ( strncmp( key, "player_", 7) == 0 ) { no = atoi(key+7); } else { no = atoi(key+11); } if ( player && player->number == no ) { player->name = strdup( value); player = NULL; } else if ( NULL != ( player = get_player_by_number( server, no ) ) ) { player->name = strdup( value); player = NULL; } else if ( gps_max_players( server ) ) { // gps_max_players( server ) due to bf1942 issue // where the actual no players is correct but more player // details are returned player = add_player( server, no ); if ( player ) { player->name= strdup( value); // init to -1 so we can tell if // we have team info player->team = -1; player->deaths = -999; } } } else if ( strncmp( key, "teamname_", 9) == 0 ) { // Yes plus 1 BF1942 is a silly players_set_teamname( server, atoi( key+9 ) + 1, value ); } else if ( strncmp( key, "team_t", 6) == 0 ) { players_set_teamname( server, atoi( key+6 ), value ); } else if ( strncmp( key, "frags_", 6) == 0 ) { player = get_player_by_number( server, atoi( key+6 ) ); if ( NULL != player ) { player->frags= atoi( value ); } } else if ( strncmp( key, "kills_", 6) == 0 ) { player = get_player_by_number( server, atoi( key+6 ) ); if ( NULL != player ) { player->frags= atoi( value ); } } else if ( strncmp( key, "team_", 5) == 0 ) { player = get_player_by_number( server, atoi( key+5 ) ); if ( NULL != player ) { if ( ! isdigit( (unsigned char)*value ) ) { player->team_name= strdup(value); } else { player->team= atoi( value); } server->flags|= FLAG_PLAYER_TEAMS; } } else if ( strncmp( key, "skin_", 5) == 0 ) { player = get_player_by_number( server, atoi( key+5 ) ); if ( NULL != player ) { player->skin= strdup( value); } } else if ( strncmp( key, "mesh_", 5) == 0 ) { player = get_player_by_number( server, atoi( key+5 ) ); if ( NULL != player ) { player->mesh = strdup( value); } } else if ( strncmp( key, "ping_", 5) == 0 ) { player = get_player_by_number( server, atoi( key+5 ) ); if ( NULL != player ) { player->ping= atoi( value); } } else if ( strncmp( key, "face_", 5) == 0 ) { player = get_player_by_number( server, atoi( key+5 ) ); if ( NULL != player ) { player->face= strdup( value); } } else if ( strncmp( key, "deaths_", 7) == 0 ) { player = get_player_by_number( server, atoi( key+7 ) ); if ( NULL != player ) { player->deaths= atoi( value ); } } // isnum( key[6] ) as halo uses score_tX for team scores else if ( strncmp( key, "score_", 6) == 0 && isdigit( (unsigned char)key[6] ) ) { player = get_player_by_number( server, atoi( key+6 ) ); if ( NULL != player ) { player->score = atoi( value ); } } else if ( player && strncmp( key, "playertype", 10) == 0) { player->team_name= strdup( value ); } else if ( player && strncmp( key, "charactername", 13) == 0) { player->face = strdup( value ); } else if ( player && strncmp( key, "characterlevel", 14) == 0) { player->ship= atoi( value ); } else if ( strncmp( key, "keyhash_", 8) == 0) { // Ensure these dont make it into the rules } else if ( 2 == sscanf( key, "%255[^_]_%d", tmp, &player_num ) ) { // arbitary player info player = get_player_by_number( server, player_num ); if ( NULL != player ) { player_add_info( player, tmp, value, NO_FLAGS ); } else if ( gps_max_players( server ) ) { // gps_max_players( server ) due to bf1942 issue // where the actual no players is correct but more player // details are returned player = add_player( server, player_num ); if ( player ) { player->name = NULL; // init to -1 so we can tell if // we have team info player->team = -1; player->deaths = -999; } player_add_info( player, tmp, value, NO_FLAGS ); } } else { player = NULL; add_rule( server, key, value, NO_FLAGS); } } debug( 2, "final %d\n", final ); debug( 2, "pkt_id %d\n", server->saved_data.pkt_id ); debug( 2, "pkt_max %d\n", server->saved_data.pkt_max ); debug( 2, "pkt_index %x\n", server->saved_data.pkt_index ); if ( ( final && server->saved_data.pkt_id == 0 ) || ( server->saved_data.pkt_max && server->saved_data.pkt_index >= ((1<<(server->saved_data.pkt_max))-1) ) || ( server->num_players < 0 && id_minor >= 3) ) { return DONE_FORCE; } return INPROGRESS; } qstat-2.15/md5.h0000644000175000017500000000664112420765614010372 00000000000000/* Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.h 374 2012-04-20 10:22:15Z stevenhartland $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.h is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Removed support for non-ANSI compilers; removed references to Ghostscript; clarified derivation from RFC 1321; now handles byte order either statically or dynamically. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); added conditionalization for C++ compilation from Martin Purschke . 1999-05-03 lpd Original version. */ #ifndef md5_INCLUDED # define md5_INCLUDED /* * This package supports both compile-time and run-time determination of CPU * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is * defined as non-zero, the code will be compiled to run only on big-endian * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to * run on either big- or little-endian CPUs, but will run slightly less * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. */ typedef unsigned char md5_byte_t; /* 8-bit byte */ typedef unsigned int md5_word_t; /* 32-bit word */ /* Define the state of the MD5 Algorithm. */ typedef struct md5_state_s { md5_word_t count[2]; /* message length in bits, lsw first */ md5_word_t abcd[4]; /* digest buffer */ md5_byte_t buf[64]; /* accumulate block */ } md5_state_t; #ifdef __cplusplus extern "C" { #endif /* Initialize the algorithm. */ void md5_init(md5_state_t *pms); /* Append a string to the message. */ void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); /* Finish the message and return the digest. */ void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); /* Return an hex md5 of the given string */ char* md5_hex(const char *bytes, int nbytes); #ifdef __cplusplus } /* end extern "C" */ #endif #endif /* md5_INCLUDED */ qstat-2.15/qstat.c0000644000175000017500000104120212420765615011026 00000000000000/* * qstat * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk) * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net) * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com) * Thanks to Simon Garner for the XML patch (sgarner@gameplanet.co.nz) * Thanks to Bob Marriott for the Ghost Recon code (bmarriott@speakeasy.net) * * Inspired by QuakePing by Len Norton * * Copyright 1996,1997,1998,1999,2000,2001,2002,2003,2004 by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #define RECV_BUF 204800 /* OS/2 defines */ #ifdef __OS2__ #define BSD_SELECT #endif #include #include #include #include #include #include #include #include #define QUERY_PACKETS #include "qstat.h" #include "packet_manip.h" #include "config.h" #include "xform.h" #ifndef _WIN32 #include #include #include #ifndef VMS #include #endif #include #include #include #include #include #ifndef F_SETFL #include #endif #ifdef __hpux extern int h_errno; #define STATIC static #else #define STATIC #endif #define INVALID_SOCKET -1 #ifndef INADDR_NONE #define INADDR_NONE ~0 #endif #define sockerr() errno #endif /* _WIN32 */ #ifdef __OS2__ #include #include #include #include #include #include #define INVALID_SOCKET -1 #define SOCKET_ERROR -1 #define close(a) soclose(a) #endif /* __OS2__ */ #ifndef FD_SETSIZE #define FD_SETSIZE 64 #endif /* Figure out whether to use poll() or select() */ #ifndef USE_POLL #ifndef USE_SELECT #ifdef sun #define USE_POLL #endif #ifdef linux #define USE_POLL #include #endif #ifdef __linux__ #define USE_POLL #include #endif #ifdef __linux #define USE_POLL #include #endif #ifdef __hpux #define USE_POLL #include #endif #ifdef __OpenBSD__ #define USE_POLL #include #endif #ifdef _AIX #define USE_POLL #include #endif #ifdef _WIN32 #define USE_SELECT #endif #ifdef __EMX__ #define USE_SELECT #endif #endif /* USE_SELECT */ #endif /* USE_POLL */ /* If did not chose, then use select() */ #ifndef USE_POLL #ifndef USE_SELECT #define USE_SELECT #endif #endif #include "debug.h" server_type *types; int n_server_types; char *qstat_version = VERSION; /* * Values set by command-line arguments */ int hostname_lookup = 0; /* set if -H was specified */ int new_style = 1; /* unset if -old was specified */ int n_retries = DEFAULT_RETRIES; int retry_interval = DEFAULT_RETRY_INTERVAL; int master_retry_interval = DEFAULT_RETRY_INTERVAL * 4; int syncconnect = 0; int get_player_info = 0; int get_server_rules = 0; int up_servers_only = 0; int no_full_servers = 0; int no_empty_servers = 0; int no_header_display = 0; int raw_display = 0; char *raw_delimiter = "\t"; char *multi_delimiter = "|"; int player_address = 0; int max_simultaneous = MAXFD_DEFAULT; int sendinterval = 5; extern int xform_names; extern int xform_strip_unprintable; extern int xform_hex_player_names; extern int xform_hex_server_names; extern int xform_strip_carets; extern int xform_html_names; extern int html_mode; int raw_arg = 0; int show_game_in_raw = 0; int progress = 0; int num_servers_total = 0; int num_players_total = 0; int max_players_total = 0; int num_servers_returned = 0; int num_servers_timed_out = 0; int num_servers_down = 0; server_type *default_server_type = NULL; FILE *OF; /* output file */ unsigned int source_ip = INADDR_ANY; unsigned short source_port_low = 0; unsigned short source_port_high = 0; unsigned short source_port = 0; int show_game_port = 0; int no_port_offset = 0; #define ENCODING_LATIN_1 1 #define ENCODING_UTF_8 8 #define UTF8BYTESWAPNOTACHAR 0xFFFE #define UTF8NOTACHAR 0xFFFF #define UTF8MAXFROMUCS4 0x10FFFF int output_bom = 0; int xml_display = 0; int xml_encoding = ENCODING_LATIN_1; #define SUPPORTED_SERVER_SORT "pgihn" #define SUPPORTED_PLAYER_SORT "PFTNS" #define SUPPORTED_SORT_KEYS "l" SUPPORTED_SERVER_SORT SUPPORTED_PLAYER_SORT char sort_keys[32]; int player_sort = 0; int server_sort = 0; void quicksort(void **array, int i, int j, int(*compare)(void *, void*)); int qpartition(void **array, int i, int j, int(*compare)(void *, void*)); void sort_servers(struct qserver **array, int size); void sort_players(struct qserver *server); int server_compare(struct qserver *one, struct qserver *two); int player_compare(struct player *one, struct player *two); int type_option_compare(server_type *one, server_type *two); int type_string_compare(server_type *one, server_type *two); int process_func_ret( struct qserver *server, int ret ); int connection_inprogress(); void clear_socketerror(); int show_errors = 0; static int noserverdups = 1; #define DEFAULT_COLOR_NAMES_RAW 0 #define DEFAULT_COLOR_NAMES_DISPLAY 1 int color_names = -1; #define SECONDS 0 #define CLOCK_TIME 1 #define STOPWATCH_TIME 2 #define DEFAULT_TIME_FMT_RAW SECONDS #define DEFAULT_TIME_FMT_DISPLAY CLOCK_TIME int time_format = -1; struct qserver *servers = NULL; struct qserver **last_server = &servers; struct qserver **connmap = NULL; int max_connmap; struct qserver *last_server_bind = NULL; struct qserver *first_server_bind = NULL; int connected = 0; time_t run_timeout = 0; time_t start_time; int waiting_for_masters; #define ADDRESS_HASH_LENGTH 2999 static unsigned num_servers; /* current number of servers in memory */ static struct qserver **server_hash[ADDRESS_HASH_LENGTH]; static unsigned int server_hash_len[ADDRESS_HASH_LENGTH]; static void free_server_hash(); static void xml_display_player_info_info(struct player *player); char *DOWN = "DOWN"; char *SYSERROR = "SYSERROR"; char *TIMEOUT = "TIMEOUT"; char *MASTER = "MASTER"; char *SERVERERROR = "ERROR"; char *HOSTNOTFOUND = "HOSTNOTFOUND"; char *BFRIS_SERVER_NAME = "BFRIS Server"; char *GAMESPY_MASTER_NAME = "Gamespy Master"; int display_prefix = 0; char *current_filename; int current_fileline; int count_bits(int n); static int qserver_get_timeout(struct qserver *server, struct timeval *now); static int wait_for_timeout(unsigned int ms); static void finish_output(); static int decode_stefmaster_packet(struct qserver *server, char *pkt, int pktlen); static int decode_q3master_packet(struct qserver *server, char *ikt, int pktlen); char *ut2003_strdup(const char *string, const char *end, char **next); void free_server(struct qserver *server); void free_player(struct player *player); void free_rule(struct rule *rule); void standard_display_server(struct qserver *server); /* MODIFY HERE * Change these functions to display however you want */ void display_server(struct qserver *server) { if (player_sort) { sort_players(server); } if (raw_display) { raw_display_server(server); } else if (xml_display) { xml_display_server(server); } else if (have_server_template()) { template_display_server(server); } else { standard_display_server(server); } free_server(server); } void standard_display_server(struct qserver *server) { char prefix[64]; if (display_prefix) { sprintf(prefix, "%-4s ", server->type->type_prefix); } else { prefix[0] = '\0'; } if (server->server_name == DOWN || server->server_name == SYSERROR) { if (!up_servers_only) { xform_printf(OF, "%s%-16s %10s\n", prefix, (hostname_lookup) ? server->host_name: server->arg, server->server_name); } return ; } if (server->server_name == TIMEOUT) { if (server->flags &FLAG_BROADCAST && server->n_servers) { xform_printf(OF, "%s%-16s %d servers\n", prefix, server->arg, server->n_servers); } else if (!up_servers_only) { xform_printf(OF, "%s%-16s no response\n", prefix, (hostname_lookup) ? server->host_name: server->arg); } return ; } if (server->type->master) { display_qwmaster(server); return ; } if (no_full_servers && server->num_players >= server->max_players) { return ; } if (no_empty_servers && server->num_players == 0) { return ; } if (server->error != NULL) { xform_printf(OF, "%s%-21s ERROR <%s>\n", prefix, (hostname_lookup) ? server->host_name: server->arg, server->error); return ; } if (new_style) { char *game = get_qw_game(server); int map_name_width = 8, game_width = 0; switch (server->type->id) { case QW_SERVER: case Q2_SERVER: case Q3_SERVER: game_width = 9; break; case TRIBES2_SERVER: map_name_width = 14; game_width = 8; break; case GHOSTRECON_SERVER: map_name_width = 15; game_width = 15; break; case HL_SERVER: map_name_width = 12; break; default: break; } xform_printf(OF, "%s%-21s %2d/%-2d %2d/%-2d %*s %6d / %1d %*s %s\n", prefix, (hostname_lookup) ? server->host_name: server->arg, server->num_players, server->max_players, server->num_spectators, server->max_spectators, map_name_width, (server->map_name) ? xform_name(server->map_name, server): "?", server->n_requests ? server->ping_total / server->n_requests: 999, server->n_retries, game_width, game, xform_name(server->server_name, server) ); if (get_server_rules && NULL != server->type->display_rule_func ) { server->type->display_rule_func(server); } if (get_player_info && NULL != server->type->display_player_func ) { server->type->display_player_func(server); } } else { char name[512]; sprintf(name, "\"%s\"", server->server_name); xform_printf(OF, "%-16s %10s map %s at %22s %d/%d players %d ms\n", (hostname_lookup) ? server->host_name: server->arg, name, server->map_name, server->address, server->num_players, server->max_players, server->n_requests ? server->ping_total / server->n_requests: 999 ); } } void display_qwmaster(struct qserver *server) { char *prefix; prefix = server->type->type_prefix; if (server->error != NULL) { xform_printf(OF, "%s %-17s ERROR <%s>\n", prefix, (hostname_lookup) ? server->host_name: server->arg, server->error ); } else { xform_printf(OF, "%s %-17s %d servers %6d / %1d\n", prefix, (hostname_lookup) ? server->host_name: server->arg, server->n_servers, server->n_requests ? server->ping_total / server->n_requests: 999, server->n_retries ); } } void display_header() { if (!no_header_display) { xform_printf(OF, "%-16s %8s %8s %15s %s\n", "ADDRESS", "PLAYERS", "MAP", "RESPONSE TIME", "NAME"); } } void display_server_rules(struct qserver *server) { struct rule *rule; int printed = 0; rule = server->rules; for (; rule != NULL; rule = rule->next) { if ((server->type->id != Q_SERVER && server->type->id != H2_SERVER) || !is_default_rule(rule)) { xform_printf(OF, "%c%s=%s", (printed) ? ',' : '\t', rule->name, rule->value); printed++; } } if (printed) { fputs("\n", OF); } } void display_q_player_info(struct qserver *server) { char fmt[128]; struct player *player; strcpy(fmt, "\t#%-2d %3d frags %9s "); if (color_names) { strcat(fmt, "%9s:%-9s "); } else { strcat(fmt, "%2s:%-2s "); } if (player_address) { strcat(fmt, "%22s "); } else { strcat(fmt, "%s"); } strcat(fmt, "%s\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, player->number, player->frags, play_time(player->connect_time, 1), quake_color(player->shirt_color), quake_color(player->pants_color), (player_address) ? player->address: "", xform_name(player->name, server) ); } } void display_qw_player_info(struct qserver *server) { char fmt[128]; struct player *player; strcpy(fmt, "\t#%-6d %5d frags %6s@%-5s %8s"); if (color_names) { strcat(fmt, "%9s:%-9s "); } else { strcat(fmt, "%2s:%-2s "); } strcat(fmt, "%12s %s\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, player->number, player->frags, play_time(player->connect_time, 0), ping_time(player->ping), player->skin ? player->skin: "", quake_color(player->shirt_color), quake_color(player->pants_color), xform_name(player->name, server), xform_name(player->team_name, server) ); } } void display_q2_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (server->flags &FLAG_PLAYER_TEAMS) { xform_printf(OF, "\t%3d frags team#%d %8s %s\n", player->frags, player->team, ping_time(player->ping), xform_name(player->name, server)); } else { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, ping_time(player->ping), xform_name(player->name, server)); } } } void display_unreal_player_info(struct qserver *server) { struct player *player; static const char *fmt_team_number = "\t%3d frags team#%-3d %7s %s\n"; static const char *fmt_team_name = "\t%3d frags %8s %7s %s\n"; static const char *fmt_no_team = "\t%3d frags %8s %s\n"; player = server->players; for (; player != NULL; player = player->next) { if (server->flags &FLAG_PLAYER_TEAMS) { // we use (player->score) ? player->score : player->frags, // so we get details from halo if (player->team_name) { xform_printf(OF, fmt_team_name, (player->score && NA_INT != player->score) ? player->score: player->frags, player->team_name, ping_time(player->ping), xform_name(player->name, server) ); } else { xform_printf(OF, fmt_team_number, (player->score && NA_INT != player->score) ? player->score: player->frags, player->team, ping_time(player->ping), xform_name(player->name, server) ); } } else { xform_printf(OF, fmt_no_team, player->frags, ping_time(player->ping), xform_name(player->name, server)); } } } void display_shogo_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, ping_time(player->ping), xform_name(player->name, server)); } } void display_halflife_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server)); } } void display_fl_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %8s %s\n", player->frags, ping_time(player->ping), play_time(player->connect_time, 1), xform_name(player->name, server)); } } void display_tribes_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%4d score team#%d %8s %s\n", player->frags, player->team, ping_time(player->ping), xform_name(player->name, server) ); } } void display_tribes2_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\tscore %4d %14s %s\n", player->frags, player->team_name ? player->team_name: (player->number == TRIBES_TEAM ? "TEAM" : "?"), xform_name(player->name, server) ); } } void display_bfris_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\ttid: %d, ship: %d, team: %s, ping: %d, score: %d, kills: %d, name: %s\n", player->number, player->ship, player->team_name, player->ping, player->score, player->frags, xform_name(player->name, server) ); } } void display_descent3_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %3d deaths team#%-3d %7s %s\n", player->frags, player->deaths, player->team, ping_time(player->ping), xform_name(player->name, server) ); } } void display_ghostrecon_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\tdead=%3d team#%-3d %s\n", player->deaths, player->team, xform_name(player->name, server)); } } void display_eye_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { xform_printf(OF, "\tscore %4d %6s team %12s %s\n", player->score, ping_time(player->ping), player->team_name, xform_name(player->name,server) ); } else { xform_printf(OF, "\tscore %4d %6s team#%d %s\n", player->score, ping_time(player->ping), player->team, xform_name(player->name,server) ); } } } int calculate_armyops_score(struct player *player) { /* Calculates a player's score for ArmyOps from the basic components */ int score = 0; int kill_score = 0; struct info *info; for (info = player->info; info; info = info->next) { if (0 == strcmp(info->name, "leader") || 0 == strcmp(info->name, "goal") || 0 == strcmp(info->name, "roe")) { score += atoi(info->value); } else if (0 == strcmp(info->name, "kia") || 0 == strcmp(info->name, "enemy")) { kill_score += atoi(info->value); } } if (kill_score > 0) { score += kill_score; } return score; } void display_gs2_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { xform_printf(OF, "\tscore %4d %6s team %12s %s\n", player->score, ping_time(player->ping), player->team_name, xform_name(player->name,server) ); } else { xform_printf(OF, "\tscore %4d %6s team#%d %s\n", player->score, ping_time(player->ping), player->team, xform_name(player->name, server) ); } } } void display_armyops_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { player->score = calculate_armyops_score(player); } display_gs2_player_info(server); } void display_ts2_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%6s %s\n", ping_time(player->ping), xform_name(player->name, server)); } } void display_ts3_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%s\n", xform_name(player->name, server)); } } void display_starmade_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%s\n", xform_name(player->name, server)); } } void display_bfbc2_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%s\n", xform_name(player->name, server)); } } void display_wic_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t#%-4d score %4d team %12s role %12s %s\n", player->number, player->score, player->team_name, player->tribe_tag ? player->tribe_tag : "", xform_name(player->name, server) ); } } void display_ventrilo_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t# %d ping %s time %d cid %i ch %s name %s\n", player->number, ping_time(player->ping), player->connect_time, player->team, player->team_name, xform_name(player->name, server) ); } } void display_tm_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%6s %s\n", ping_time(player->ping), xform_name(player->name, server)); } } void display_doom3_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->tribe_tag) { xform_printf(OF, "\t#%-4d score %4d %6s team %12s %s\n", player->number, player->score, ping_time(player->ping), player->tribe_tag, xform_name(player->name, server) ); } else { xform_printf(OF, "\t#%-4d score %4d %6s team#%d %s\n", player->number, player->score, ping_time(player->ping), player->team, xform_name(player->name, server) ); } } } void display_ravenshield_player_info(struct qserver *server) { struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server)); } } void display_savage_player_info(struct qserver *server) { struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server)); } } void display_farcry_player_info(struct qserver *server) { struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%3d frags %8s %s\n", player->frags, play_time(player->connect_time, 1), xform_name(player->name, server)); } } void display_tee_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t%4d score %s\n", player->score, xform_name(player->name, server)); } } char *get_qw_game(struct qserver *server) { struct rule *rule; char *game_rule = server->type->game_rule; if (game_rule == NULL || *game_rule == '\0') { return ""; } rule = server->rules; for (; rule != NULL; rule = rule->next) { if (strcmp(rule->name, game_rule) == 0) { if (server->type->id == Q3_SERVER && strcmp(rule->value, "baseq3") == 0) { return ""; } return rule->value; } } rule = server->rules; for (; rule != NULL; rule = rule->next) { if (0 == strcmp(rule->name, "game") || 0 == strcmp(rule->name, "fs_game")) { return rule->value; } } return ""; } /* Raw output for web master types */ #define RD raw_delimiter void raw_display_server(struct qserver *server) { char *prefix; int ping_time; prefix = server->type->type_prefix; if (server->n_requests) { ping_time = server->ping_total / server->n_requests; } else { ping_time = 999; } if (server->server_name == DOWN || server->server_name == SYSERROR) { if (!up_servers_only) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s\n\n", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name : server->arg, RD, server->server_name ); } return ; } if (server->server_name == TIMEOUT) { if (server->flags &FLAG_BROADCAST && server->n_servers) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%d\n", prefix, raw_arg, RD, raw_arg, server->arg, RD, server->arg, RD, server->n_servers); } else if (!up_servers_only) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s\n\n", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name : server->arg, RD, TIMEOUT); } return ; } if (server->error != NULL) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s""%s%s", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, "ERROR", RD, server->error ); } else if (server->type->flags &TF_RAW_STYLE_QUAKE) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s""%s%s""%s%d""%s%s""%s%d""%s%d""%s%d""%s%d""%s%d""%s%d""%s%s", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, xform_name(server->server_name, server), RD, server->address, RD, server->protocol_version, RD, server->map_name, RD, server->max_players, RD, server->num_players, RD, server->max_spectators, RD, server->num_spectators, RD, ping_time, RD, server->n_retries, show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server): "" ); } else if (server->type->flags &TF_RAW_STYLE_TRIBES) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s""%s%s""%s%d""%s%d", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, xform_name(server->server_name, server), RD, (server->map_name) ? server->map_name: "?", RD, server->num_players, RD, server->max_players ); } else if (server->type->flags &TF_RAW_STYLE_GHOSTRECON) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s""%s%s""%s%d""%s%d", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, xform_name(server->server_name, server), RD, (server->map_name) ? server->map_name: "?", RD, server->num_players, RD, server->max_players ); } else if (server->type->master) { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%d", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, server->n_servers ); } else { xform_printf(OF, "%s""%.*s%.*s""%s%s""%s%s""%s%s""%s%d""%s%d""%s%d""%s%d""%s%s", prefix, raw_arg, RD, raw_arg, server->arg, RD, (hostname_lookup) ? server->host_name: server->arg, RD, xform_name(server->server_name, server), RD, (server->map_name) ? xform_name(server->map_name, server): "?", RD, server->max_players, RD, server->num_players, RD, ping_time, RD, server->n_retries, show_game_in_raw ? RD : "", show_game_in_raw ? get_qw_game(server): "" ); } fputs("\n", OF); if (server->type->master || server->error != NULL) { fputs("\n", OF); return ; } if (get_server_rules && NULL != server->type->display_raw_rule_func ) { server->type->display_raw_rule_func(server); } if (get_player_info && NULL != server->type->display_raw_player_func) { server->type->display_raw_player_func(server); } fputs("\n", OF); } void raw_display_server_rules(struct qserver *server) { struct rule *rule; int printed = 0; rule = server->rules; for (; rule != NULL; rule = rule->next) { if (server->type->id == TRIBES2_SERVER) { char *v; for (v = rule->value; *v; v++) if (*v == '\n') { *v = ' '; } } xform_printf(OF, "%s%s=%s", (printed) ? RD : "", rule->name, rule->value); printed++; } if (server->missing_rules) { xform_printf(OF, "%s?", (printed) ? RD : ""); } fputs("\n", OF); } void raw_display_q_player_info(struct qserver *server) { char fmt[] = "%d""%s%s""%s%s""%s%d""%s%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, player->number, RD, xform_name(player->name, server), RD, player->address, RD, player->frags, RD, play_time(player->connect_time, 1), RD, quake_color(player->shirt_color), RD, quake_color(player->pants_color) ); fputs("\n", OF); } } void raw_display_qw_player_info(struct qserver *server) { char fmt[128]; struct player *player; strcpy(fmt, "%d""%s%s""%s%d""%s%s""%s%s""%s%s"); strcat(fmt, "%s%d""%s%s""%s%s"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, player->number, RD, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1), RD, quake_color(player->shirt_color), RD, quake_color(player->pants_color), RD, player->ping, RD, player->skin ? player->skin: "", RD, player->team_name ? player->team_name: "" ); fputs("\n", OF); } } void raw_display_q2_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%d"; static const char *fmt_team = "%s""%s%d""%s%d""%s%d"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (server->flags &FLAG_PLAYER_TEAMS) { xform_printf(OF, fmt_team, xform_name(player->name, server), RD, player->frags, RD, player->ping, RD, player->team); } else { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->ping); } fputs("\n", OF); } } void raw_display_unreal_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%d""%s%d""%s%s""%s%s""%s%s"; static const char *fmt_team_name = "%s""%s%d""%s%d""%s%s""%s%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { xform_printf(OF, fmt_team_name, xform_name(player->name,server), RD, player->frags, RD, player->ping, RD, player->team_name, RD, player->skin ? player->skin: "", RD, player->mesh ? player->mesh: "", RD, player->face ? player->face: "" ); } else { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->ping, RD, player->team, RD, player->skin ? player->skin: "", RD, player->mesh ? player->mesh: "", RD, player->face ? player->face: "" ); } fputs("\n", OF); } } void raw_display_halflife_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1)); fputs("\n", OF); } } void raw_display_fl_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%s""%s%d""%s%d"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { fprintf( OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1), RD, player->ping, RD, player->team ); fputs("\n", OF); } } void raw_display_tribes_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%d""%s%d""%s%d"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->ping, RD, player->team, RD, player->packet_loss); fputs("\n", OF); } } void raw_display_tribes2_player_info(struct qserver *server) { static char fmt[] = "%s""%s%d""%s%d""%s%s""%s%s""%s%s"; struct player *player; char *type; player = server->players; for (; player != NULL; player = player->next) { switch (player->type_flag) { case PLAYER_TYPE_BOT: type = "Bot"; break; case PLAYER_TYPE_ALIAS: type = "Alias"; break; default: type = ""; break; } xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->team, RD, player->team_name ? player->team_name : "TEAM", RD, type, RD, player->tribe_tag ? xform_name(player->tribe_tag, server): "" ); fputs("\n", OF); } } void raw_display_bfris_player_info(struct qserver *server) { static char fmt[] = "%d""%s%d""%s%s""%s%d""%s%d""%s%d""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, player->number, RD, player->ship, RD, player->team_name, RD, player->ping, RD, player->score, RD, player->frags, RD, xform_name(player->name, server) ); fputs("\n", OF); } } void raw_display_descent3_player_info(struct qserver *server) { static char fmt[] = "%s""%s%d""%s%d""%s%d""%s%d"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, player->deaths, RD, player->ping, RD, player->team); fputs("\n", OF); } } void raw_display_ghostrecon_player_info(struct qserver *server) { static char fmt[28] = "%s""%s%d""%s%d"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->deaths, RD, player->team); fputs("\n", OF); } } void raw_display_eye_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%d""%s%d""%s%s""%s%s"; static const char *fmt_team_name = "%s""%s%d""%s%d""%s%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { xform_printf(OF, fmt_team_name, xform_name(player->name,server), RD, player->score, RD, player->ping, RD, player->team_name, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time,1) ); } else { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->team, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time, 1) ); } fputs("\n", OF); } } void raw_display_doom3_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%d""%s%d""%s%u"; static const char *fmt_team_name = "%s""%s%d""%s%d""%s%s""%s%u"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->tribe_tag) { xform_printf(OF, fmt_team_name, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->tribe_tag, RD, player->number); } else { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->team, RD, player->number); } fputs("\n", OF); } } void raw_display_gs2_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%d""%s%d""%s%s""%s%s"; static const char *fmt_team_name = "%s""%s%d""%s%d""%s%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { xform_printf(OF, fmt_team_name, xform_name(player->name, server), RD, player->score, RD, player->ping, RD, player->team_name, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time,1) ); } else { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->score, RD, player->ping, RD, player->team, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time,1) ); } fputs("\n", OF); } } void raw_display_armyops_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { player->score = calculate_armyops_score(player); } raw_display_gs2_player_info(server); } void raw_display_ts2_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->ping, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time, 1) ); fputs("\n", OF); } } void raw_display_ts3_player_info(struct qserver *server) { static const char *fmt = "%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->skin ? player->skin: "", RD, play_time(player->connect_time, 1) ); fputs("\n", OF); } } void raw_display_starmade_player_info(struct qserver *server) { static const char *fmt = "%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->skin ? player->skin: "", RD, play_time(player->connect_time, 1) ); fputs("\n", OF); } } void raw_display_bfbc2_player_info(struct qserver *server) { static const char *fmt = "%s""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->skin ? player->skin: "", RD, play_time(player->connect_time, 1) ); fputs("\n", OF); } } void raw_display_wic_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->score, RD, player->team_name, RD, player->tribe_tag ? player->tribe_tag : "" ); fputs("\n", OF); } } void raw_display_ventrilo_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { fprintf( OF, fmt, xform_name(player->name, server), RD, player->team, RD, player->team_name, RD, play_time(player->connect_time, 1) ); fputs("\n", OF); } } void raw_display_tm_player_info(struct qserver *server) { static const char *fmt = "%s""%s%d""%s%s""%s%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server), RD, player->ping, RD, player->skin ? player->skin: "", RD, play_time(player->connect_time,1) ); fputs("\n", OF); } } void raw_display_tee_player_info(struct qserver *server) { static const char *fmt = "%s"; struct player *player; player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name,server) ); fputs("\n", OF); } } void raw_display_ravenshield_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%s"; struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1)); fputs("\n", OF); } } void raw_display_savage_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%s"; struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1)); fputs("\n", OF); } } void raw_display_farcry_player_info(struct qserver *server) { static char fmt[24] = "%s""%s%d""%s%s"; struct player *player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, fmt, xform_name(player->name, server), RD, player->frags, RD, play_time(player->connect_time, 1)); fputs("\n", OF); } } /* XML output * Contributed by :-) */ void xml_display_server(struct qserver *server) { char *prefix; prefix = server->type->type_prefix; if (server->server_name == DOWN) { if (!up_servers_only) { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), xml_escape(DOWN)); xform_printf(OF, "\t\t%s\n", xml_escape((hostname_lookup) ? server->host_name: server->arg)); xform_printf(OF, "\t\n"); } return; } if (server->server_name == TIMEOUT) { if (server->flags &FLAG_BROADCAST && server->n_servers) { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), xml_escape(TIMEOUT), server->n_servers ); xform_printf(OF, "\t\n"); } else if (!up_servers_only) { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), xml_escape(TIMEOUT)); xform_printf(OF, "\t\t%s\n", xml_escape((hostname_lookup) ? server->host_name: server->arg)); xform_printf(OF, "\t\n"); } return ; } if (server->error != NULL) { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), "ERROR"); xform_printf(OF, "\t\t%s\n", xml_escape((hostname_lookup) ? server->host_name: server->arg)); xform_printf(OF, "\t\t%s\n", xml_escape(server->error)); } else if (server->type->master) { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), "UP", server->n_servers); } else { xform_printf(OF, "\t\n", xml_escape(prefix), xml_escape(server->arg), "UP"); xform_printf(OF, "\t\t%s\n", xml_escape((hostname_lookup) ? server->host_name: server->arg)); xform_printf(OF, "\t\t%s\n", xml_escape(xform_name(server->server_name, server))); xform_printf(OF, "\t\t%s\n", xml_escape(get_qw_game(server))); xform_printf(OF, "\t\t%s\n", xml_escape(xform_name(server->map_name, server))); xform_printf(OF, "\t\t%d\n", server->num_players); xform_printf(OF, "\t\t%d\n", server->max_players); xform_printf(OF, "\t\t%d\n", server->num_spectators); xform_printf(OF, "\t\t%d\n", server->max_spectators); if (!(server->type->flags &TF_RAW_STYLE_TRIBES)) { xform_printf(OF, "\t\t%d\n", server->n_requests ? server->ping_total / server->n_requests: 999); xform_printf(OF, "\t\t%d\n", server->n_retries); } if (server->type->flags &TF_RAW_STYLE_QUAKE) { xform_printf(OF, "\t\t

%s
\n", xml_escape(server->address)); xform_printf(OF, "\t\t%d\n", server->protocol_version); } } if (!server->type->master && server->error == NULL) { if (get_server_rules && NULL != server->type->display_xml_rule_func ) { server->type->display_xml_rule_func(server); } if (get_player_info && NULL != server->type->display_xml_player_func ) { server->type->display_xml_player_func(server); } } xform_printf(OF, "\t\n"); } void xml_header() { if (xml_encoding == ENCODING_LATIN_1) { xform_printf(OF, "\n\n"); } else if (output_bom) { xform_printf(OF, "%c%c%c\n\n", 0xEF, 0xBB, 0xBF); } else { xform_printf(OF, "\n\n"); } } void xml_footer() { xform_printf(OF, "\n"); } void xml_display_server_rules(struct qserver *server) { struct rule *rule; rule = server->rules; xform_printf(OF, "\t\t\n"); for (; rule != NULL; rule = rule->next) { xform_printf(OF, "\t\t\t%s\n", xml_escape(rule->name), xml_escape(rule->value)); } xform_printf(OF, "\t\t\n"); } void xml_display_q_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n", player->number); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t
%s
\n", xml_escape(player->address)); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); if (color_names) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(quake_color(player->shirt_color))); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(quake_color(player->pants_color))); } else { xform_printf(OF, "\t\t\t\t%s\n", quake_color(player->shirt_color)); xform_printf(OF, "\t\t\t\t%s\n", quake_color(player->pants_color)); } xform_printf(OF, "\t\t\t
\n"); } xform_printf(OF, "\t\t
\n"); } void xml_display_qw_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n", player->number); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); if (color_names) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(quake_color(player->shirt_color))); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(quake_color(player->pants_color))); } else { xform_printf(OF, "\t\t\t\t%s\n", quake_color(player->shirt_color)); xform_printf(OF, "\t\t\t\t%s\n", quake_color(player->pants_color)); } xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%s\n", player->skin ? xml_escape(player->skin): ""); xform_printf(OF, "\t\t\t\t%s\n", player->team_name ? xml_escape(player->team_name): ""); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_q2_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); if (server->flags &FLAG_PLAYER_TEAMS) { xform_printf(OF, "\t\t\t\t%d\n", player->team); } xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_player_info_info(struct player *player) { struct info *info; for (info = player->info; info; info = info->next) { if (info->name) { char *name = xml_escape(info->name); char *value = xml_escape(info->value); xform_printf(OF, "\t\t\t\t<%s>%s\n", name, value, name); } } } void xml_display_unreal_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); if ( - 999 != player->deaths) { xform_printf(OF, "\t\t\t\t%d\n", player->deaths); } xform_printf(OF, "\t\t\t\t%d\n", player->ping); if (player->team_name) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->team_name)); } else if ( - 1 != player->team) { xform_printf(OF, "\t\t\t\t%d\n", player->team); } // Some games dont provide // so only display if they do if (player->skin) { xform_printf(OF, "\t\t\t\t%s\n", player->skin ? xml_escape(player->skin): ""); } if (player->mesh) { xform_printf(OF, "\t\t\t\t%s\n", player->mesh ? xml_escape(player->mesh): ""); } if (player->face) { xform_printf(OF, "\t\t\t\t%s\n", player->face ? xml_escape(player->face): ""); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_halflife_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_fl_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%d\n", player->team); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_tribes_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t%d\n", player->team); xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%d\n", player->packet_loss); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_tribes2_player_info(struct qserver *server) { struct player *player; char *type; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { if (player->team_name) { switch (player->type_flag) { case PLAYER_TYPE_BOT: type = "Bot"; break; case PLAYER_TYPE_ALIAS: type = "Alias"; break; default: type = ""; break; } xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t%s\n", player->team, xml_escape(player->team_name)); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(type)); xform_printf(OF, "\t\t\t\t%s\n", player->tribe_tag ? xml_escape(xform_name(player->tribe_tag, server)): ""); xform_printf(OF, "\t\t\t\n"); } } xform_printf(OF, "\t\t\n"); } void xml_display_bfris_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n", player->number); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->score); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->team_name)); xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%d\n", player->ship); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_descent3_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t%d\n", player->deaths); xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%d\n", player->team); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_ravenshield_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_ghostrecon_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->deaths); xform_printf(OF, "\t\t\t\t%d\n", player->team); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_eye_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->score); xform_printf(OF, "\t\t\t\t%d\n", player->ping); if (player->team_name) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->team_name)); } else { xform_printf(OF, "\t\t\t\t%d\n", player->team); } if (player->skin) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->skin)); } if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 1))); } xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_doom3_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%u\n", player->number); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->score); xform_printf(OF, "\t\t\t\t%d\n", player->ping); if (player->tribe_tag) { xform_printf(OF, "\t\t\t\t%s\n", player->tribe_tag ? xml_escape(xform_name(player->tribe_tag, server)): ""); } else { xform_printf(OF, "\t\t\t\t%d\n", player->team); } if (player->skin) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->skin)); } if (player->type_flag) { xform_printf(OF, "\t\t\t\tbot\n"); } else { xform_printf(OF, "\t\t\t\tplayer\n"); } if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); if (NA_INT != player->ping) { xform_printf(OF, "\t\t\t\t%d\n", player->ping); } if (NA_INT != player->score) { xform_printf(OF, "\t\t\t\t%d\n", player->score); } if (NA_INT != player->deaths) { xform_printf(OF, "\t\t\t\t%d\n", player->deaths); } if (NA_INT != player->frags) { xform_printf(OF, "\t\t\t\t%d\n", player->frags); } if (player->team_name) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->team_name)); } else if (NA_INT != player->team) { xform_printf(OF, "\t\t\t\t%d\n", player->team); } if (player->skin) { xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->skin)); } if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 1))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_armyops_player_info(struct qserver *server) { struct player *player; player = server->players; for (; player != NULL; player = player->next) { player->score = calculate_armyops_score(player); } xml_display_player_info(server); } void xml_display_ts2_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->ping); if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_ts3_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_starmade_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_bfbc2_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_wic_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->score); xform_printf(OF, "\t\t\t\t%s\n", player->team_name); xform_printf(OF, "\t\t\t\t%d\n", player->type_flag ); if ( player->tribe_tag ) { xform_printf(OF, "\t\t\t\t%s\n", player->tribe_tag ); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_ventrilo_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->ping); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(player->team_name)); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_tm_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->ping); if (player->connect_time) { xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); } xml_display_player_info_info(player); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_savage_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_farcry_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->frags); xform_printf(OF, "\t\t\t\t\n", xml_escape(play_time(player->connect_time, 2))); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void xml_display_tee_player_info(struct qserver *server) { struct player *player; xform_printf(OF, "\t\t\n"); player = server->players; for (; player != NULL; player = player->next) { xform_printf(OF, "\t\t\t\n"); xform_printf(OF, "\t\t\t\t%s\n", xml_escape(xform_name(player->name, server))); xform_printf(OF, "\t\t\t\t%d\n", player->score); xform_printf(OF, "\t\t\t\n"); } xform_printf(OF, "\t\t\n"); } void display_progress() { static struct timeval rate_start = { 0, 0 }; char rate[32]; struct timeval now; gettimeofday(&now, NULL); if (!rate_start.tv_sec) { rate_start = now; rate[0] = '\0'; } else { int delta = time_delta(&now, &rate_start); if (delta > 1500) { sprintf(rate, " %d servers/sec ", (num_servers_returned + num_servers_timed_out) *1000 / delta); } else { rate[0] = '\0'; } } // only print out every 'progress' number of servers. if (0 != num_servers_returned + num_servers_timed_out && (progress == 1 || (num_servers_returned + num_servers_timed_out) % progress == 0)) { fprintf(stderr, "\r%d/%d (%d timed out, %d down)%s", num_servers_returned + num_servers_timed_out, num_servers_total, num_servers_timed_out, num_servers_down, rate); } } /* ----- END MODIFICATION ----- Don't need to change anything below here. */ void set_non_blocking(int fd); int set_fds(fd_set *fds); void get_next_timeout(struct timeval *timeout); void set_file_descriptors(); int wait_for_file_descriptors(struct timeval *timeout); struct qserver *get_next_ready_server(); /* Misc flags */ struct timeval packet_recv_time; int one_server_type_id = ~MASTER_SERVER; static int one = 1; static int little_endian; static int big_endian; unsigned int swap_long(void*); unsigned short swap_short(void*); float swap_float_from_little(void *f); char *strndup(const char *string, size_t len); #define FORCE 1 /* Print an error message and the program usage notes */ void usage(char *msg, char **argv, char *a1) { int i; server_type *type; server_type **sorted_types; if (msg) { fprintf(stderr, msg, a1); } printf("Usage: %s [options ...]\n", argv[0]); printf("\t[-default server-type] [-cfg file] [-f file] [host[:port]] ...\n"); printf("Where host is an IP address or host name\n"); sorted_types = (server_type **)malloc(sizeof(server_type*) * n_server_types); type = &types[0]; for (i = 0; type->id != Q_UNKNOWN_TYPE; type++, i++) { sorted_types[i] = type; } quicksort((void **)sorted_types, 0, n_server_types - 1, (int(*)(void *, void*))type_option_compare); for (i = 0; i < n_server_types; i++) { type = sorted_types[i]; printf("%s\t\tquery %s server\n", type->type_option, type->game_name); } quicksort((void **)sorted_types, 0, n_server_types - 1, (int(*)(void *, void*))type_string_compare); printf("-default\tset default server type:"); for (i = 0; i < n_server_types; type++, i++) { type = sorted_types[i]; printf(" %s", type->type_string); } puts(""); printf("-nocfg\t\tIgnore qstat configuration loaded from any default location. Must be the first option on the command-line.\n"); printf("-cfg\t\tread the extended types from given file not the default one\n"); printf("-f\t\tread hosts from file\n"); printf("-R\t\tfetch and display server rules\n"); printf("-P\t\tfetch and display player info\n"); printf("-sort\t\tsort servers and/or players\n"); printf("-u\t\tonly display servers that are up\n"); printf("-nf\t\tdo not display full servers\n"); printf("-ne\t\tdo not display empty servers\n"); printf("-nh\t\tdo not display header line.\n"); printf("-cn\t\tdisplay color names instead of numbers\n"); printf("-ncn\t\tdisplay color numbers instead of names\n"); printf("-hc\t\tdisplay colors in #rrggbb format\n"); printf("-tc\t\tdisplay time in clock format (DhDDmDDs)\n"); printf("-tsw\t\tdisplay time in stop-watch format (DD:DD:DD)\n"); printf("-ts\t\tdisplay time in seconds\n"); printf("-pa\t\tdisplay player address\n"); printf("-hpn\t\tdisplay player names in hex\n"); printf("-hsn\t\tdisplay server names in hex\n"); printf("-nh\t\tdo not display header\n"); printf("-old\t\told style display\n"); printf("-progress\tdisplay progress meter (text only)\n"); printf("-retry\t\tnumber of retries, default is %d\n", DEFAULT_RETRIES); printf("-interval\tinterval between retries, default is %.2f seconds\n", DEFAULT_RETRY_INTERVAL / 1000.0); printf("-mi\t\tinterval between master server retries, default is %.2f seconds\n", (DEFAULT_RETRY_INTERVAL *4) / 1000.0); printf("-timeout\ttotal time in seconds before giving up\n"); printf("-maxsim\t\tset maximum simultaneous queries\n"); printf("-sendinterval\t\tset time in ms between sending packets, default %u\n", sendinterval); printf("-errors\t\tdisplay errors\n"); printf("-allowserverdups\t\tallow adding multiple servers with same ip:port (needed for ts2)\n"); printf("-of\t\toutput file\n"); printf("-af\t\tLike -of, but append to the file\n"); printf("-raw \toutput in raw format using as delimiter\n"); printf("-mdelim \tFor rules with multi values use as delimiter\n"); printf("-xml\t\toutput status data as an XML document\n"); printf("-Th,-Ts,-Tpt\toutput templates: header, server and player\n"); printf("-Tr,-Tt\t\toutput templates: rule, and trailer\n"); printf("-srcport \tSend packets from these network ports\n"); printf("-srcip \tSend packets using this IP address\n"); printf("-H\t\tresolve host names\n"); printf("-Hcache\t\thost name cache file\n"); printf("-carets\t\tDisplay carets in Quake 3 player names\n"); printf("-d\t\tEnable debug options. Specify multiple times to increase debug level.\n"); #ifdef ENABLE_DUMP printf("-dump\t\twrite received raw packets to dumpNNN files which must not exist before\n"); printf("-pkt \tuse file as server reply instead of quering the server. Works only with TF_SINGLE_QUERY servers\n"); #endif printf("-htmlmode\tConvert <, >, and & to the equivalent HTML entities\n"); printf("-htmlnames\tColorize Quake 3 and Tribes 2 player names using html font tags\n"); printf("-nohtmlnames\tDo not colorize Quake 3 and Tribes 2 player names even if $HTML is used in an output template.\n"); printf("-syncconnect\tProcess connect initialisation synchronously.\n"); printf("-stripunprintable\tDisable stripping of unprintable characters.\n"); printf("-showgameport\tAlways display the game port in QStat output.\n"); printf("-noportoffset\tDont use builtin status port offsets ( assume query port was specified ).\n"); printf("-raw-arg\tWhen used with -raw, always display the server address as it appeared in a file or on the command-line.\n"); printf("-utf8\t\tUse the UTF-8 character encoding for XML output.\n"); printf("-bom\t\tOutput Byte-Order-Mark for XML output.\n"); #ifdef _WIN32 printf("-noconsole\t\tFree the console\n"); #endif printf("\n"); printf("Sort keys:\n"); printf(" servers: p=by-ping, g=by-game, i=by-IP-address, h=by-hostname, n=by-#-players, l=by-list-order\n"); printf(" players: P=by-ping, F=by-frags, T=by-team, N=by-name\n"); printf("\nqstat version %s\n", VERSION); exit(0); } struct server_arg { int type_id; server_type *type; char *arg; char *outfilename; char *query_arg; }; server_type *find_server_type_id(int type_id) { server_type *type = &types[0]; for (; type->id != Q_UNKNOWN_TYPE; type++) if (type->id == type_id) { return type; } return NULL; } server_type *find_server_type_string(char *type_string) { server_type *type = &types[0]; char *t = type_string; for (; *t; t++) { *t = tolower(*t); } for (; type->id != Q_UNKNOWN_TYPE; type++) if (strcmp(type->type_string, type_string) == 0) { return type; } return NULL; } server_type *find_server_type_option(char *option) { server_type *type = &types[0]; for (; type->id != Q_UNKNOWN_TYPE; type++) if (strcmp(type->type_option, option) == 0) { return type; } return NULL; } server_type *parse_server_type_option(char *option, int *outfile, char **query_arg) { server_type *type = &types[0]; char *comma, *arg; int len; *outfile = 0; *query_arg = 0; comma = strchr(option, ','); if (comma) { *comma++ = '\0'; } for (; type->id != Q_UNKNOWN_TYPE; type++) if (strcmp(type->type_option, option) == 0) { break; } if (type->id == Q_UNKNOWN_TYPE) { return NULL; } if (!comma) { return type; } if (strcmp(comma, "outfile") == 0) { *outfile = 1; comma = strchr(comma, ','); if (!comma) { return type; } *comma++ = '\0'; } *query_arg = strdup(comma); arg = comma; do { comma = strchr(arg, ','); if (comma) { len = comma - arg; } else { len = strlen(arg); } if (strncmp(arg, "outfile", len) == 0) { *outfile = 1; } arg = comma + 1; } while (comma); return type; } void add_server_arg(char *arg, int type, char *outfilename, char *query_arg, struct server_arg **args, int *n, int *max) { if (*n == *max) { if (*max == 0) { *max = 4; *args = (struct server_arg*)malloc(sizeof(struct server_arg)*(*max)); } else { (*max) *= 2; *args = (struct server_arg*)realloc(*args, sizeof(struct server_arg)*(*max)); } } (*args)[ *n].type_id = type; /* (*args)[*n].type= find_server_type_id( type); */ (*args)[ *n].type = NULL; (*args)[ *n].arg = arg; (*args)[ *n].outfilename = outfilename; (*args)[ *n].query_arg = query_arg; (*n)++; } void add_query_param(struct qserver *server, char *arg) { char *equal; struct query_param *param; equal = strchr(arg, '='); *equal++ = '\0'; param = (struct query_param*)malloc(sizeof(struct query_param)); param->key = arg; param->value = equal; sscanf(equal, "%i", ¶m->i_value); sscanf(equal, "%i", ¶m->ui_value); param->next = server->params; server->params = param; } char *get_param_value(struct qserver *server, const char *key, char *default_value) { struct query_param *p = server->params; for (; p; p = p->next) if (strcasecmp(key, p->key) == 0) { return p->value; } return default_value; } int get_param_i_value(struct qserver *server, char *key, int default_value) { struct query_param *p = server->params; for (; p; p = p->next) if (strcasecmp(key, p->key) == 0) { return p->i_value; } return default_value; } unsigned int get_param_ui_value(struct qserver *server, char *key, unsigned int default_value) { struct query_param *p = server->params; for (; p; p = p->next) if (strcasecmp(key, p->key) == 0) { return p->ui_value; } return default_value; } int parse_source_address(char *addr, unsigned int *ip, unsigned short *port) { char *colon; colon = strchr(addr, ':'); if (colon) { *colon = '\0'; *port = atoi(colon + 1); if (colon == addr) { return 0; } } else { *port = 0; } *ip = inet_addr(addr); if (*ip == INADDR_NONE && !isdigit((unsigned char) *ip)) { *ip = hcache_lookup_hostname(addr); } if (*ip == INADDR_NONE) { fprintf(stderr, "%s: Not an IP address or unknown host name\n", addr); return -1; } *ip = ntohl(*ip); return 0; } int parse_source_port(char *port, unsigned short *low, unsigned short *high) { char *dash; *low = atoi(port); dash = strchr(port, '-'); *high = 0; if (dash) { *high = atoi(dash + 1); } if (*high == 0) { *high = *low; } if (*high < *low) { fprintf(stderr, "%s: Invalid port range\n", port); return -1; } return 0; } void add_config_server_types() { int n_config_types, n_builtin_types, i; server_type **config_types; server_type *new_types, *type; config_types = qsc_get_config_server_types(&n_config_types); if (n_config_types == 0) { return ; } n_builtin_types = (sizeof(builtin_types) / sizeof(server_type)) - 1; new_types = (server_type*)malloc(sizeof(server_type)*(n_builtin_types + n_config_types + 1)); memcpy(new_types, &builtin_types[0], n_builtin_types *sizeof(server_type)); type = &new_types[n_builtin_types]; for (i = n_config_types; i; i--, config_types++, type++) { *type = **config_types; } n_server_types = n_builtin_types + n_config_types; new_types[n_server_types].id = Q_UNKNOWN_TYPE; if (types != &builtin_types[0]) { free(types); } types = new_types; } void revert_server_types() { if (types != &builtin_types[0]) { free(types); } n_server_types = (sizeof(builtin_types) / sizeof(server_type)) - 1; types = &builtin_types[0]; } #ifdef ENABLE_DUMP unsigned pkt_dump_pos = 0; const char *pkt_dumps[64] = { 0 }; static void add_pkt_from_file(const char *file) { if (pkt_dump_pos >= sizeof(pkt_dumps) / sizeof(pkt_dumps[0])) { return ; } pkt_dumps[pkt_dump_pos++] = file; } static void replay_pkt_dumps() { struct qserver *server = servers; char *pkt = NULL; int fd; int bytes_read = 0; // should be ssize_t but for ease with win32 int i; struct stat statbuf; gettimeofday(&packet_recv_time, NULL); for (i = 0; i < pkt_dump_pos; i++) { if ((fd = open(pkt_dumps[i], O_RDONLY)) == -1) { goto err; } if (fstat(fd, &statbuf) == -1) { goto err; } pkt = malloc(statbuf.st_size); if (NULL == pkt) { goto err; } bytes_read = read(fd, pkt, statbuf.st_size); if (bytes_read != statbuf.st_size) { fprintf(stderr, "Failed to read entire packet from disk got %d of %ld bytes\n", bytes_read, (long)statbuf.st_size); goto err; } close(fd); fd = 0; debug(2, "replay, pre-packet_func"); process_func_ret( server, server->type->packet_func( server, pkt, statbuf.st_size ) ); debug(2, "replay, post-packet_func"); } goto out; err: perror(__FUNCTION__); close(fd); out: fd = 0; // NOP } #endif // ENABLE_DUMP struct rcv_pkt { struct qserver *server; struct sockaddr_in addr; struct timeval recv_time; char data[PACKET_LEN]; int len; int _errno; }; void do_work(void) { int pktlen, rc, fd; char *pkt = NULL; int bind_retry = 0; struct timeval timeout; struct rcv_pkt *buffer; unsigned buffill = 0, i = 0; unsigned bufsize = max_simultaneous * 2; struct timeval t, ts; gettimeofday(&t, NULL); ts = t; buffer = malloc(sizeof(struct rcv_pkt) *bufsize); if (!buffer) { return ; } #ifdef ENABLE_DUMP if (pkt_dump_pos) { replay_pkt_dumps(); } else #endif { bind_retry = bind_sockets(); } send_packets(); debug(2, "connected: %d", connected); while (connected || (!connected && bind_retry == -2)) { if (!connected && bind_retry == -2) { rc = wait_for_timeout(60); bind_retry = bind_sockets(); continue; } bind_retry = 0; set_file_descriptors(); if (progress) { display_progress(); } get_next_timeout(&timeout); rc = wait_for_file_descriptors(&timeout); debug(2, "rc %d", rc); if (rc == SOCKET_ERROR) { #ifndef _WIN32 if (errno == EINTR) { continue; } #endif perror("select"); break; } fd = 0; for (; rc && buffill < bufsize; rc--) { int addrlen = sizeof(buffer[buffill].addr); struct qserver *server = get_next_ready_server(); if (server == NULL) { break; } gettimeofday(&buffer[buffill].recv_time, NULL); pktlen = recvfrom(server->fd, buffer[buffill].data, sizeof(buffer[buffill].data), 0, (struct sockaddr*) &buffer[buffill].addr, (void*) &addrlen); debug( 2, "recvfrom: %d", pktlen ); // pktlen == 0 is no error condition! happens on remote tcp socket close if (pktlen == SOCKET_ERROR) { if (connection_would_block()) { malformed_packet(server, "EAGAIN on UDP socket, probably incorrect checksum"); } else if (connection_refused() || connection_reset()) { server->server_name = DOWN; num_servers_down++; cleanup_qserver( server, FORCE ); } continue; } debug(1, "recv %3d %3d %d.%d.%d.%d:%hu\n", time_delta(&buffer[buffill].recv_time, &ts), time_delta(&buffer[buffill].recv_time, &t), server->ipaddr &0xff, (server->ipaddr >> 8) &0xff, (server->ipaddr >> 16) &0xff, (server->ipaddr >> 24) &0xff, server->port ); t = buffer[buffill].recv_time; buffer[buffill].server = server; buffer[buffill].len = pktlen; ++buffill; } debug( 2, "fill: %d < %d", buffill, bufsize) ; for (i = 0; i < buffill; ++i) { struct qserver *server = buffer[i].server; pkt = buffer[i].data; pktlen = buffer[i].len; memcpy(&packet_recv_time, &buffer[i].recv_time, sizeof(packet_recv_time)); if (get_debug_level() > 2) { print_packet(server, pkt, pktlen); } #ifdef ENABLE_DUMP if (do_dump) { dump_packet(pkt, pktlen); } #endif if (server->flags &FLAG_BROADCAST) { struct qserver *broadcast = server; unsigned short port = ntohs(buffer[i].addr.sin_port); /* create new server and init */ if (!(no_port_offset || server->flags &TF_NO_PORT_OFFSET)) { port -= server->type->port_offset; } server = add_qserver_byaddr(ntohl(buffer[i].addr.sin_addr.s_addr), port, server->type, NULL); if (server == NULL) { server = find_server_by_address(buffer[i].addr.sin_addr.s_addr, ntohs(buffer[i].addr.sin_port)); if (server == NULL) { continue; } /* if ( show_errors) { fprintf(stderr, "duplicate or invalid packet received from 0x%08x:%hu\n", ntohl(buffer[i].addr.sin_addr.s_addr), ntohs(buffer[i].addr.sin_port)); print_packet( NULL, pkt, pktlen); } continue; */ } else { server->packet_time1 = broadcast->packet_time1; server->packet_time2 = broadcast->packet_time2; server->ping_total = broadcast->ping_total; server->n_requests = broadcast->n_requests; server->n_packets = broadcast->n_packets; broadcast->n_servers++; } } debug(2, "connected, pre-packet_func: %d", connected); process_func_ret( server, server->type->packet_func(server, pkt, pktlen) ); debug(2, "connected, post-packet_func: %d", connected); } buffill = 0; if (run_timeout && time(0) - start_time >= run_timeout) { debug(2, "run timeout reached"); break; } send_packets(); if (connected < max_simultaneous) { bind_retry = bind_sockets(); } debug(2, "connected: %d", connected); } free(buffer); } int main(int argc, char *argv[]) { int arg, n_files, i; char **files, *outfilename, *query_arg; struct server_arg *server_args = NULL; int n_server_args = 0, max_server_args = 0; int default_server_type_id; #ifdef _WIN32 WORD version = MAKEWORD(1, 1); WSADATA wsa_data; if (WSAStartup(version, &wsa_data) != 0) { fprintf(stderr, "Could not open winsock\n"); exit(1); } #else signal(SIGPIPE, SIG_IGN); #endif types = &builtin_types[0]; n_server_types = (sizeof(builtin_types) / sizeof(server_type)) - 1; i = qsc_load_default_config_files(); if (i == -1) { return 1; } else if (i == 0) { add_config_server_types(); } if (argc == 1) { usage(NULL, argv, NULL); } OF = stdout; files = (char **)malloc(sizeof(char*)*(argc / 2)); n_files = 0; default_server_type_id = Q_SERVER; little_endian = ((char*) &one)[0]; big_endian = !little_endian; for (arg = 1; arg < argc; arg++) { if (argv[arg][0] != '-') { break; } outfilename = NULL; if (strcmp(argv[arg], "-nocfg") == 0 && arg == 1) { revert_server_types(); } else if (strcmp(argv[arg], "--help") == 0) { usage(NULL, argv, NULL); } else if (strcmp(argv[arg], "-f") == 0) { arg++; if (arg >= argc) { usage("missing argument for -f\n", argv, NULL); } files[n_files++] = argv[arg]; } else if (strcmp(argv[arg], "-retry") == 0) { arg++; if (arg >= argc) { usage("missing argument for -retry\n", argv, NULL); } n_retries = atoi(argv[arg]); if (n_retries <= 0) { fprintf(stderr, "retries must be greater than zero\n"); exit(1); } } else if (strcmp(argv[arg], "-interval") == 0) { double value = 0.0; arg++; if (arg >= argc) { usage("missing argument for -interval\n", argv, NULL); } sscanf(argv[arg], "%lf", &value); if (value < 0.1) { fprintf(stderr, "retry interval must be greater than 0.1\n"); exit(1); } retry_interval = (int)(value *1000); } else if (strcmp(argv[arg], "-mi") == 0) { double value = 0.0; arg++; if (arg >= argc) { usage("missing argument for -mi\n", argv, NULL); } sscanf(argv[arg], "%lf", &value); if (value < 0.1) { fprintf(stderr, "interval must be greater than 0.1\n"); exit(1); } master_retry_interval = (int)(value *1000); } else if (strcmp(argv[arg], "-H") == 0) { hostname_lookup = 1; } else if (strcmp(argv[arg], "-u") == 0) { up_servers_only = 1; } else if (strcmp(argv[arg], "-nf") == 0) { no_full_servers = 1; } else if (strcmp(argv[arg], "-ne") == 0) { no_empty_servers = 1; } else if (strcmp(argv[arg], "-nh") == 0) { no_header_display = 1; } else if (strcmp(argv[arg], "-old") == 0) { new_style = 0; } else if (strcmp(argv[arg], "-P") == 0) { get_player_info = 1; } else if (strcmp(argv[arg], "-R") == 0) { get_server_rules = 1; } else if (strncmp(argv[arg], "-raw", 4) == 0) { if (argv[arg][4] == ',') { if (strcmp(&argv[arg][5], "game") == 0) { show_game_in_raw = 1; } else { usage("Unknown -raw option\n", argv, NULL); } } arg++; if (arg >= argc) { usage("missing argument for -raw\n", argv, NULL); } raw_delimiter = argv[arg]; // Check the multi rule delimiter isnt the same // If it is fix to maintain backwards compatibility if (0 == strcmp(raw_delimiter, multi_delimiter) && 0 == strcmp(raw_delimiter, "|")) { multi_delimiter = ":"; } raw_display = 1; } else if (strcmp(argv[arg], "-mdelim") == 0) { arg++; if (arg >= argc) { usage("missing argument for -mdelim\n", argv, NULL); } multi_delimiter = argv[arg]; } else if (strcmp(argv[arg], "-xml") == 0) { xml_display = 1; if (raw_display == 1) { usage("cannot specify both -raw and -xml\n", argv, NULL); } } else if (strcmp(argv[arg], "-utf8") == 0) { xml_encoding = ENCODING_UTF_8; xform_names = 0; } else if (strcmp(argv[arg], "-ncn") == 0) { color_names = 0; } else if (strcmp(argv[arg], "-cn") == 0) { color_names = 1; } else if (strcmp(argv[arg], "-hc") == 0) { color_names = 2; } else if (strcmp(argv[arg], "-nx") == 0) { xform_names = 1; } else if (strcmp(argv[arg], "-nnx") == 0) { xform_names = 0; } else if (strcmp(argv[arg], "-tc") == 0) { time_format = CLOCK_TIME; } else if (strcmp(argv[arg], "-tsw") == 0) { time_format = STOPWATCH_TIME; } else if (strcmp(argv[arg], "-ts") == 0) { time_format = SECONDS; } else if (strcmp(argv[arg], "-pa") == 0) { player_address = 1; } else if (strcmp(argv[arg], "-hpn") == 0) { xform_hex_player_names = 1; } else if (strcmp(argv[arg], "-hsn") == 0) { xform_hex_server_names = 1; } else if (strncmp(argv[arg], "-maxsimultaneous", 7) == 0) { arg++; if (arg >= argc) { usage("missing argument for -maxsimultaneous\n", argv, NULL); } max_simultaneous = atoi(argv[arg]); if (max_simultaneous <= 0) { usage("value for -maxsimultaneous must be > 0\n", argv, NULL); } if (max_simultaneous > FD_SETSIZE) { max_simultaneous = FD_SETSIZE; } } else if (strcmp(argv[arg], "-sendinterval") == 0) { arg++; if (arg >= argc) { usage("missing argument for -sendinterval\n", argv, NULL); } sendinterval = atoi(argv[arg]); if (sendinterval < 0) { usage("value for -sendinterval must be >= 0\n", argv, NULL); } } else if (strcmp(argv[arg], "-raw-arg") == 0) { raw_arg = 1000; } else if (strcmp(argv[arg], "-timeout") == 0) { arg++; if (arg >= argc) { usage("missing argument for -timeout\n", argv, NULL); } run_timeout = atoi(argv[arg]); if (run_timeout <= 0) { usage("value for -timeout must be > 0\n", argv, NULL); } } else if (strncmp(argv[arg], "-progress", sizeof("-progress") - 1) == 0) { char *p = argv[arg] + sizeof("-progress") - 1; progress = 1; if (*p == ',') { progress = atoi(p + 1); } } else if (strcmp(argv[arg], "-Hcache") == 0) { arg++; if (arg >= argc) { usage("missing argument for -Hcache\n", argv, NULL); } if (hcache_open(argv[arg], 0) == -1) { return 1; } } else if (strcmp(argv[arg], "-default") == 0) { arg++; if (arg >= argc) { usage("missing argument for -default\n", argv, NULL); } default_server_type = find_server_type_string(argv[arg]); if (default_server_type == NULL) { char opt[256], *o = &opt[0]; sprintf(opt, "-%s", argv[arg]); for (; *o; o++) { *o = tolower(*o); } default_server_type = find_server_type_option(opt); } if (default_server_type == NULL) { fprintf(stderr, "unknown server type \"%s\"\n", argv[arg]); usage(NULL, argv, NULL); } default_server_type_id = default_server_type->id; default_server_type = NULL; } else if (strncmp(argv[arg], "-Tserver", 3) == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (read_qserver_template(argv[arg]) == -1) { return 1; } } else if (strncmp(argv[arg], "-Trule", 3) == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (read_rule_template(argv[arg]) == -1) { return 1; } } else if (strncmp(argv[arg], "-Theader", 3) == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (read_header_template(argv[arg]) == -1) { return 1; } } else if (strncmp(argv[arg], "-Ttrailer", 3) == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (read_trailer_template(argv[arg]) == -1) { return 1; } } else if (strncmp(argv[arg], "-Tplayer", 3) == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (read_player_template(argv[arg]) == -1) { return 1; } } else if (strcmp(argv[arg], "-sort") == 0) { size_t pos; arg++; if (arg >= argc) { usage("missing argument for -sort\n", argv, NULL); } strncpy(sort_keys, argv[arg], sizeof(sort_keys) - 1); pos = strspn(sort_keys, SUPPORTED_SORT_KEYS); if (pos != strlen(sort_keys)) { fprintf(stderr, "Unknown sort key \"%c\", valid keys are \"%s\"\n", sort_keys[pos], SUPPORTED_SORT_KEYS); return 1; } server_sort = strpbrk(sort_keys, SUPPORTED_SERVER_SORT) != NULL; if (strchr(sort_keys, 'l')) { server_sort = 1; } player_sort = strpbrk(sort_keys, SUPPORTED_PLAYER_SORT) != NULL; } else if (strcmp(argv[arg], "-errors") == 0) { show_errors++; } else if (strcmp(argv[arg], "-of") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (argv[arg][0] == '-' && argv[arg][1] == '\0') { OF = stdout; } else { OF = fopen(argv[arg], "w"); } if (OF == NULL) { perror(argv[arg]); return 1; } } else if (strcmp(argv[arg], "-af") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (argv[arg][0] == '-' && argv[arg][1] == '\0') { OF = stdout; } else { OF = fopen(argv[arg], "a"); } if (OF == NULL) { perror(argv[arg]); return 1; } } else if (strcmp(argv[arg], "-htmlnames") == 0) { xform_html_names = 1; } else if (strcmp(argv[arg], "-nohtmlnames") == 0) { xform_html_names = 0; } else if (strcmp(argv[arg], "-htmlmode") == 0) { html_mode = 1; } else if (strcmp(argv[arg], "-carets") == 0) { xform_strip_carets = 0; } else if (strcmp(argv[arg], "-d") == 0) { set_debug_level(get_debug_level() + 1); } else if (strcmp(argv[arg], "-showgameport") == 0) { show_game_port = 1; } else if (strcmp(argv[arg], "-noportoffset") == 0) { no_port_offset = 1; } else if (strcmp(argv[arg], "-srcip") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (parse_source_address(argv[arg], &source_ip, &source_port) == -1) { return 1; } if (source_port) { source_port_low = source_port; source_port_high = source_port; } } else if (strcmp(argv[arg], "-syncconnect") == 0) { syncconnect = 1; } else if (strcmp(argv[arg], "-stripunprintable") == 0) { xform_strip_unprintable = 1; } else if (strcmp(argv[arg], "-srcport") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (parse_source_port(argv[arg], &source_port_low, &source_port_high) == -1) { return 1; } source_port = source_port_low; } else if (strcmp(argv[arg], "-cfg") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } if (qsc_load_config_file(argv[arg]) == -1) { return 1; } add_config_server_types(); } else if (strcmp(argv[arg], "-allowserverdups") == 0) { noserverdups = 0; } else if (strcmp(argv[arg], "-bom") == 0) { output_bom = 1; } #ifdef ENABLE_DUMP else if (strcmp(argv[arg], "-dump") == 0) { do_dump = 1; } else if (strcmp(argv[arg], "-pkt") == 0) { arg++; if (arg >= argc) { usage("missing argument for %s\n", argv, argv[arg - 1]); } add_pkt_from_file(argv[arg]); } #endif #ifdef _WIN32 else if (strcmp(argv[arg], "-noconsole") == 0) { FreeConsole(); } #endif else { int outfile; server_type *type; arg++; if (arg >= argc) { fprintf(stderr, "missing argument for \"%s\"\n", argv[arg - 1]); return 1; } type = parse_server_type_option(argv[arg - 1], &outfile, &query_arg); if (type == NULL) { fprintf(stderr, "unknown option \"%s\"\n", argv[arg - 1]); return 1; } outfilename = NULL; if (outfile) { outfilename = strchr(argv[arg], ','); if (outfilename == NULL) { fprintf(stderr, "missing file name for \"%s,outfile\"\n", argv[arg - 1]); return 1; } *outfilename++ = '\0'; } /* if ( query_arg && !(type->flags & TF_QUERY_ARG)) { fprintf( stderr, "option flag \"%s\" not allowed for this server type\n", query_arg); return 1; } */ if (type->flags &TF_QUERY_ARG_REQUIRED && !query_arg ) { fprintf(stderr, "option flag missing for server type \"%s\"\n", argv[arg - 1]); return 1; } add_server_arg(argv[arg], type->id, outfilename, query_arg, &server_args, &n_server_args, &max_server_args); } } start_time = time(0); default_server_type = find_server_type_id(default_server_type_id); for (i = 0; i < n_files; i++) { add_file(files[i]); } for (; arg < argc; arg++) { add_qserver(argv[arg], default_server_type, NULL, NULL); } for (i = 0; i < n_server_args; i++) { server_type *server_type = find_server_type_id(server_args[i].type_id); add_qserver(server_args[i].arg, server_type, server_args[i].outfilename, server_args[i].query_arg); } free(server_args); if (servers == NULL) { exit(1); } max_connmap = max_simultaneous + 10; connmap = (struct qserver **)calloc(1, sizeof(struct qserver*) * max_connmap); if (color_names == -1) { color_names = (raw_display) ? DEFAULT_COLOR_NAMES_RAW : DEFAULT_COLOR_NAMES_DISPLAY; } if (time_format == -1) { time_format = (raw_display) ? DEFAULT_TIME_FMT_RAW : DEFAULT_TIME_FMT_DISPLAY; } if ((one_server_type_id &MASTER_SERVER) || one_server_type_id == 0) { display_prefix = 1; } if (xml_display) { xml_header(); } else if (new_style && !raw_display && !have_server_template()) { display_header(); } else if (have_header_template()) { template_display_header(); } q_serverinfo.length = htons(q_serverinfo.length); h2_serverinfo.length = htons(h2_serverinfo.length); q_player.length = htons(q_player.length); do_work(); finish_output(); free_server_hash(); free(files); free(connmap); return 0; } void finish_output() { int i; hcache_update_file(); if (progress) { display_progress(); fputs("\n", stderr); } if (server_sort) { struct qserver **array, *server, *next_server; if (strchr(sort_keys, 'l') && strpbrk(sort_keys, SUPPORTED_SERVER_SORT) == NULL) { server = servers; for (; server; server = next_server) { next_server = server->next; display_server(server); } } else { array = (struct qserver **)malloc(sizeof(struct qserver*) * num_servers_total); server = servers; for (i = 0; server != NULL; i++) { array[i] = server; server = server->next; } sort_servers(array, num_servers_total); if (progress) { fprintf(stderr, "\n"); } for (i = 0; i < num_servers_total; i++) { display_server(array[i]); } free(array); } } else { struct qserver *server, *next_server; server = servers; for (; server; server = next_server) { next_server = server->next; if (server->server_name == HOSTNOTFOUND) { display_server(server); } } } if (xml_display) { xml_footer(); } else if (have_trailer_template()) { template_display_trailer(); } if (OF != stdout) { fclose(OF); } } void add_file(char *filename) { FILE *file; char name[200], *comma, *query_arg = NULL; server_type *type; debug(4, "Loading servers from '%s'...\n", filename); if (strcmp(filename, "-") == 0) { file = stdin; current_filename = NULL; } else { file = fopen(filename, "r"); current_filename = filename; } current_fileline = 1; if (file == NULL) { perror(filename); return ; } for (; fscanf(file, "%s", name) == 1; current_fileline++) { comma = strchr(name, ','); if (comma) { *comma++ = '\0'; query_arg = strdup(comma); } type = find_server_type_string(name); if (type == NULL) { add_qserver(name, default_server_type, NULL, NULL); } else if (fscanf(file, "%s", name) == 1) { if (type->flags &TF_QUERY_ARG && comma && *query_arg) { add_qserver(name, type, NULL, query_arg); } else { add_qserver(name, type, NULL, NULL); } } } if (file != stdin) { fclose(file); } debug(4, "Loaded servers from '%s'\n", filename); current_fileline = 0; } void print_file_location() { if (current_fileline != 0) { fprintf(stderr, "%s:%d: ", current_filename ? current_filename : "", current_fileline); } } void parse_query_params(struct qserver *server, char *params) { char *comma, *arg = params; do { comma = strchr(arg, ','); if (comma) { *comma = '\0'; } if (strchr(arg, '=')) { add_query_param(server, arg); } else if (strcmp(arg, "noportoffset") == 0 || strcmp(arg, "qp") == 0) { server->flags |= TF_NO_PORT_OFFSET; } else if (strcmp(arg, "showgameport") == 0 || strcmp(arg, "gp") == 0) { server->flags |= TF_SHOW_GAME_PORT; } arg = comma + 1; } while (comma); } int add_qserver(char *arg, server_type *type, char *outfilename, char *query_arg) { struct qserver *server, *prev_server; int flags = 0; char *colon = NULL, *arg_copy, *hostname = NULL; unsigned int ipaddr; unsigned short port, port_max; int portrange = 0; unsigned colonpos = 0; debug(4, "%s, %s, %s, %s\n", arg, (NULL != type) ? type->type_string : "unknown", outfilename, query_arg); if (run_timeout && time(0) - start_time >= run_timeout) { finish_output(); exit(0); } port = port_max = type->default_port; if (outfilename && strcmp(outfilename, "-") != 0) { FILE *outfile = fopen(outfilename, "r+"); if (outfile == NULL && (errno == EACCES || errno == EISDIR || errno == ENOSPC || errno == ENOTDIR)) { perror(outfilename); return -1; } if (outfile) { fclose(outfile); } } arg_copy = strdup(arg); colon = strchr(arg, ':'); if (colon != NULL) { if (sscanf(colon + 1, "%hu-%hu", &port, &port_max) == 2) { portrange = 1; } else { port_max = port; } *colon = '\0'; colonpos = colon - arg; } if (*arg == '+') { flags |= FLAG_BROADCAST; arg++; } ipaddr = inet_addr(arg); if (ipaddr == INADDR_NONE) { if (strcmp(arg, "255.255.255.255") != 0) { ipaddr = htonl(hcache_lookup_hostname(arg)); } } else if (hostname_lookup && !(flags &FLAG_BROADCAST)) { hostname = hcache_lookup_ipaddr(ntohl(ipaddr)); } if ((ipaddr == INADDR_NONE || ipaddr == 0) && strcmp(arg, "255.255.255.255") != 0) { if (show_errors) { print_file_location(); fprintf(stderr, "%s: %s\n", arg, strherror(h_errno)); } server = (struct qserver*)calloc(1, sizeof(struct qserver)); // NOTE: 0 != port to prevent infinite loop due to lack of range on unsigned short for (; port <= port_max && 0 != port; ++port) { init_qserver(server, type); if (portrange) { server->arg = (port == port_max) ? arg_copy : strdup(arg_copy); // NOTE: arg_copy and therefore server->arg will always have enough space as it was a port range sprintf(server->arg + colonpos + 1, "%hu", port); } else { server->arg = arg_copy; } server->server_name = HOSTNOTFOUND; server->error = strdup(strherror(h_errno)); server->orig_port = server->query_port = server->port = port; if (last_server != &servers) { prev_server = (struct qserver*)((char*)last_server - ((char*) &server->next - (char*)server)); server->prev = prev_server; } *last_server = server; last_server = &server->next; if (one_server_type_id == ~MASTER_SERVER) { one_server_type_id = type->id; } else if (one_server_type_id != type->id) { one_server_type_id = 0; } } return -1; } // NOTE: 0 != port to prevent infinite loop due to lack of range on unsigned short for (; port <= port_max && 0 != port; ++port) { if (noserverdups && find_server_by_address(ipaddr, port) != NULL) { continue; } server = (struct qserver*)calloc(1, sizeof(struct qserver)); server->arg = port == port_max ? arg_copy : strdup(arg_copy); if (portrange) { sprintf(server->arg + colonpos + 1, "%hu", port); } if (hostname && colon) { server->host_name = (char*)malloc(strlen(hostname) + 5+2); sprintf(server->host_name, "%s:%hu", hostname, port); } else { server->host_name = strdup((hostname) ? hostname : arg); } server->ipaddr = ipaddr; server->orig_port = server->query_port = server->port = port; server->type = type; server->outfilename = outfilename; server->flags = flags; server->state = STATE_INIT; if (query_arg) { server->query_arg = (port == port_max) ? query_arg : strdup(query_arg); parse_query_params(server, server->query_arg); } else { server->query_arg = NULL; } init_qserver(server, type); if (server->type->master) { waiting_for_masters++; } if (num_servers_total % 10 == 0) { hcache_update_file(); } if (last_server != &servers) { prev_server = (struct qserver*)((char*)last_server - ((char*) &server->next - (char*)server)); server->prev = prev_server; } *last_server = server; last_server = &server->next; add_server_to_hash(server); if (one_server_type_id == ~MASTER_SERVER) { one_server_type_id = type->id; } else if (one_server_type_id != type->id) { one_server_type_id = 0; } ++num_servers; } return 0; } struct qserver *add_qserver_byaddr(unsigned int ipaddr, unsigned short port, server_type *type, int *new_server) { char arg[36]; struct qserver *server, *prev_server; char *hostname = NULL; if (run_timeout && time(0) - start_time >= run_timeout) { finish_output(); exit(0); } if (new_server) { *new_server = 0; } ipaddr = htonl(ipaddr); if (ipaddr == 0) { return 0; } // TODO: this prevents servers with the same ip:port being queried // and hence breaks virtual servers support e.g. Teamspeak 2 if (find_server_by_address(ipaddr, port) != NULL) { return 0; } if (new_server) { *new_server = 1; } server = (struct qserver*)calloc(1, sizeof(struct qserver)); server->ipaddr = ipaddr; ipaddr = ntohl(ipaddr); sprintf(arg, "%d.%d.%d.%d:%hu", ipaddr >> 24, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, port); server->arg = strdup(arg); if (hostname_lookup) { hostname = hcache_lookup_ipaddr(ipaddr); } if (hostname) { server->host_name = (char*)malloc(strlen(hostname) + 6+2); sprintf(server->host_name, "%s:%hu", hostname, port); } else { server->host_name = strdup(arg); } server->orig_port = server->query_port = server->port = port; init_qserver(server, type); if (num_servers_total % 10 == 0) { hcache_update_file(); } if (last_server != &servers) { prev_server = (struct qserver*)((char*)last_server - ((char*) &server->next - (char*)server)); server->prev = prev_server; } *last_server = server; last_server = &server->next; add_server_to_hash(server); ++num_servers; return server; } void add_servers_from_masters() { struct qserver *server; unsigned int ipaddr, i; unsigned short port; int n_servers, new_server, port_adjust = 0; char *pkt; server_type *server_type; FILE *outfile; for (server = servers; server != NULL; server = server->next) { if (!server->type->master || server->master_pkt == NULL) { continue; } pkt = server->master_pkt; if (server->query_arg && server->type->id == GAMESPY_MASTER) { server_type = find_server_type_string(server->query_arg); if (server_type == NULL) { server_type = find_server_type_id(server->type->master); } } else { server_type = find_server_type_id(server->type->master); } if (server->type->id == GAMESPY_MASTER && server_type) { if (server_type->id == UN_SERVER) { port_adjust = - 1; } else if (server_type->id == KINGPIN_SERVER) { port_adjust = 10; } } outfile = NULL; if (server->outfilename) { if (strcmp(server->outfilename, "-") == 0) { outfile = stdout; } else { outfile = fopen(server->outfilename, "w"); } if (outfile == NULL) { perror(server->outfilename); continue; } } n_servers = 0; for (i = 0; i < server->master_pkt_len; i += 6) { memcpy(&ipaddr, &pkt[i], 4); memcpy(&port, &pkt[i + 4], 2); ipaddr = ntohl(ipaddr); port = ntohs(port) + port_adjust; new_server = 1; if (outfile) { fprintf(outfile, "%s %d.%d.%d.%d:%hu\n", server_type ? server_type->type_string: "", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, port ); } else if (server_type == NULL) { xform_printf(OF, "%d.%d.%d.%d:%hu\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, port); } else { add_qserver_byaddr(ipaddr, port, server_type, &new_server); } n_servers += new_server; } free(server->master_pkt); server->master_pkt = NULL; server->master_pkt_len = 0; server->n_servers = n_servers; if (outfile) { fclose(outfile); } } if (hostname_lookup) { hcache_update_file(); } bind_sockets(); } void init_qserver(struct qserver *server, server_type *type) { server->server_name = NULL; server->map_name = NULL; server->game = NULL; server->num_players = 0; server->num_spectators = 0; server->fd = -1; server->state = STATE_INIT; if (server->flags &FLAG_BROADCAST) { server->retry1 = 1; server->retry2 = 1; } else { server->retry1 = n_retries; server->retry2 = n_retries; } server->n_retries = 0; server->ping_total = 0; server->n_packets = 0; server->n_requests = 0; server->n_servers = 0; server->master_pkt_len = 0; server->master_pkt = NULL; server->error = NULL; server->saved_data.data = NULL; server->saved_data.datalen = 0; server->saved_data.pkt_index = -1; server->saved_data.pkt_max = 0; server->saved_data.next = NULL; server->type = type; server->next_rule = (get_server_rules) ? "" : NO_SERVER_RULES; server->next_player_info = (get_player_info && type->player_packet) ? 0 : NO_PLAYER_INFO; server->n_player_info = 0; server->players = NULL; server->n_rules = 0; server->rules = NULL; server->last_rule = &server->rules; server->missing_rules = 0; num_servers_total++; } // ipaddr should be network byte-order // port should be host byte-order // NOTE: This will return the first matching server, which is not nessacarily correct // depending on if duplicate ports are allowed struct qserver *find_server_by_address(unsigned int ipaddr, unsigned short port) { struct qserver **hashed; unsigned int hash, i; if ( ! noserverdups && show_errors ) { fprintf( stderr, "error: find_server_by_address while duplicates are allowed, this is unsafe!" ); } hash = (ipaddr + port) % ADDRESS_HASH_LENGTH; if (ipaddr == 0) { for (hash = 0; hash < ADDRESS_HASH_LENGTH; hash++) { printf("%3d %d\n", hash, server_hash_len[hash]); } return NULL; } hashed = server_hash[hash]; for (i = server_hash_len[hash]; i; i--, hashed++) { if (*hashed && (*hashed)->ipaddr == ipaddr && (*hashed)->port == port) { return *hashed; } } return NULL; } void add_server_to_hash(struct qserver *server) { unsigned int hash; hash = (server->ipaddr + server->port) % ADDRESS_HASH_LENGTH; if (server_hash_len[hash] % 16 == 0) { server_hash[hash] = (struct qserver **)realloc(server_hash[hash], sizeof(struct qserver **)*(server_hash_len[hash] + 16)); memset(&server_hash[hash][server_hash_len[hash]], 0, sizeof(struct qserver **) * 16); } server_hash[hash][server_hash_len[hash]] = server; server_hash_len[hash]++; } void remove_server_from_hash(struct qserver *server) { struct qserver **hashed; unsigned int hash, i, ipaddr = server->ipaddr; unsigned short port = server->orig_port; hash = ( ipaddr + port ) % ADDRESS_HASH_LENGTH; hashed = server_hash[hash]; for (i = server_hash_len[hash]; i; i--, hashed++) { // NOTE: we use direct pointer checks here to prevent issues with duplicate port servers e.g. teamspeak 2 and 3 if ( *hashed == server ) { *hashed = NULL; break; } } } void free_server_hash() { int i; for (i = 0; i < ADDRESS_HASH_LENGTH; i++) { if (server_hash[i]) { free(server_hash[i]); } } } /* * Functions for binding sockets to Quake servers */ int bind_qserver_post(struct qserver *server) { server->state = STATE_CONNECTED; if (server->type->flags &TF_TCP_CONNECT) { int one = 1; if ( -1 == setsockopt(server->fd, IPPROTO_TCP, TCP_NODELAY, (char*) &one, sizeof(one)) ) { perror( "Failed to set TCP no delay" ); } } if ( server->type->id & MASTER_SERVER ) { // Use a large buffer so we dont miss packets int sockbuf = RECV_BUF; if ( -1 == setsockopt(server->fd, SOL_SOCKET, SO_RCVBUF, (void*)&sockbuf, sizeof(sockbuf)) ) { perror( "Failed to set socket buffer" ); } } #ifndef _WIN32 if (server->fd >= max_connmap) { int old_max = max_connmap; max_connmap = server->fd + 32; connmap = (struct qserver **)realloc(connmap, max_connmap *sizeof(struct qserver*)); memset(&connmap[old_max], 0, (max_connmap - old_max) *sizeof(struct qserver*)); } connmap[server->fd] = server; #endif #ifdef _WIN32 { int i; for (i = 0; i < max_connmap; i++) { if (connmap[i] == NULL) { connmap[i] = server; break; } } if (i >= max_connmap) { printf("could not put server in connmap\n"); } } #endif return 0; } void add_ms_to_timeval(struct timeval *a, unsigned long interval_ms, struct timeval *result) { result->tv_sec = a->tv_sec + (interval_ms / 1000); result->tv_usec = a->tv_usec + ((interval_ms % 1000) * 1000); if (result->tv_usec > 1000000) { result->tv_usec -= 1000000; result->tv_sec++; } } void qserver_sockaddr(struct qserver *server, struct sockaddr_in *addr) { addr->sin_family = AF_INET; addr->sin_port = (no_port_offset || server->flags &TF_NO_PORT_OFFSET) ? htons(server->port) : htons((unsigned short)(server->port + server->type->port_offset)); addr->sin_addr.s_addr = server->ipaddr; memset(&(addr->sin_zero), 0, sizeof(addr->sin_zero)); } int connected_qserver(struct qserver *server, int polling) { struct sockaddr_in addr; char error[50]; int ret; struct timeval tv, now, to; fd_set connect_set; error[0] = '\0'; gettimeofday(&now, NULL); add_ms_to_timeval(&server->packet_time1, retry_interval * server->retry1, &to); if (polling) { // No delay tv.tv_sec = 0; tv.tv_usec = 0; } else { // Wait until the server would timeout tv.tv_sec = to.tv_sec; tv.tv_usec = to.tv_usec; } while( 1 ) { FD_ZERO( &connect_set ); FD_SET( server->fd, &connect_set ); // NOTE: We may need to check exceptfds here on windows instead of writefds ret = select( server->fd + 1, NULL, &connect_set, NULL, &tv ); if ( 0 == ret ) { // Time limit expired if (polling) { // Check if we have run out of time to connect gettimeofday(&now, NULL); if (0 < time_delta(&to, &now)) { // We still have time to connect return -2; } } qserver_sockaddr(server, &addr); sprintf(error, "connect:%s:%u - timeout", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); server->server_name = TIMEOUT; server->state = STATE_TIMEOUT; goto connect_error; } else if ( 0 < ret ) { // Socket selected for write so either connected or error int sockerr, orig_errno; unsigned int lon = sizeof(int); orig_errno = errno; if ( 0 != getsockopt( server->fd, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &lon) ) { // Restore the original error errno = orig_errno; goto connect_error; } if (sockerr) { // set the real error errno = sockerr; goto connect_error; } // Connection success break; } else { // select failed if ( errno != EINTR ) { goto connect_error; } } } return bind_qserver_post(server); connect_error: if (STATE_CONNECTING == server->state) { // Default error case if (0 == strlen(error)) { qserver_sockaddr(server, &addr); sprintf(error, "connect: %s:%u", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); } server->server_name = SYSERROR; server->state = STATE_SYS_ERROR; } if ( show_errors ) { perror(error); } close(server->fd); server->fd = -1; connected--; return -1; } int bind_qserver2(struct qserver *server, int wait) { struct sockaddr_in addr; static int one = 1; debug(1, "start %p @ %d.%d.%d.%d:%hu\n", server, server->ipaddr &0xff, (server->ipaddr >> 8) &0xff, (server->ipaddr >> 16) &0xff, (server->ipaddr >> 24) &0xff, server->port ); if (server->type->flags &TF_TCP_CONNECT) { server->fd = socket(AF_INET, SOCK_STREAM, 0); } else { server->fd = socket(AF_INET, SOCK_DGRAM, 0); } if (server->fd == INVALID_SOCKET) { if (sockerr() == EMFILE) { // Per process descriptor table is full - retry server->fd = -1; return -2; } perror("socket"); server->server_name = SYSERROR; server->state = STATE_SYS_ERROR; return -1; } addr.sin_family = AF_INET; addr.sin_addr.s_addr = htonl(source_ip); if (server->type->id == Q2_MASTER) { addr.sin_port = htons(26500); } else if (source_port == 0) { addr.sin_port = 0; } else { addr.sin_port = htons(source_port); source_port++; if (source_port > source_port_high) { source_port = source_port_low; } } memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero)); if (bind(server->fd, (struct sockaddr*) &addr, sizeof(struct sockaddr)) == SOCKET_ERROR) { perror("bind"); server->server_name = SYSERROR; server->state = STATE_SYS_ERROR; close(server->fd); server->fd = -1; return -1; } if (server->flags &FLAG_BROADCAST) { if ( -1 == setsockopt(server->fd, SOL_SOCKET, SO_BROADCAST, (char*) &one, sizeof(one)) ) { perror( "Failed to set broadcast" ); server->server_name = SYSERROR; server->state = STATE_SYS_ERROR; close(server->fd); server->fd = -1; return -1; } } // we need nonblocking always. poll on an udp socket would wake // up and recv blocks if a packet with incorrect checksum is // received set_non_blocking(server->fd); if (server->type->id != Q2_MASTER && !(server->flags &FLAG_BROADCAST)) { if ( server->type->flags & TF_TCP_CONNECT ) { // TCP set packet_time1 so it can be used for ping calculations for protocols with an initial response gettimeofday( &server->packet_time1, NULL ); } qserver_sockaddr(server, &addr); server->state = STATE_CONNECTING; if (connect(server->fd, (struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR) { if ( connection_inprogress() ) { int ret; // Ensure we don't detect the same error twice, specifically on a different server clear_socketerror(); if ( ! wait ) { debug(2, "connect:%s:%u - in progress", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); return -3; } ret = connected_qserver( server, 0 ); if (0 != ret) { return ret; } } else { if ( show_errors ) { char error[50]; sprintf(error, "connect:%s:%u", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); perror(error); } server->server_name = SYSERROR; server->state = STATE_SYS_ERROR; close(server->fd); server->fd = -1; return -1; } } } return bind_qserver_post(server); } int bind_qserver(struct qserver *server) { return bind_qserver2(server, 1); } static struct timeval t_lastsend = { 0, 0 }; int bind_sockets() { struct qserver *server, *next_server, *first_server, *last_server; struct timeval now; int rc, retry_count = 0, inprogress = 0; gettimeofday(&now, NULL); if (connected && sendinterval && time_delta(&now, &t_lastsend) < sendinterval) { server = NULL; } else if (!waiting_for_masters) { if (last_server_bind == NULL) { last_server_bind = servers; } server = last_server_bind; } else { server = servers; } first_server = server; for (; server != NULL && connected < max_simultaneous; ) { // note the next server for use as process_func can free the server next_server = server->next; if (server->server_name == NULL && server->fd == -1) { if (waiting_for_masters && !server->type->master) { server = next_server; continue; } if ((rc = bind_qserver2(server, syncconnect ? 1 : 0)) == 0) { debug(1, "send %d.%d.%d.%d:%hu\n", server->ipaddr &0xff, (server->ipaddr >> 8) &0xff, (server->ipaddr >> 16) &0xff, (server->ipaddr >> 24) &0xff, server->port ); gettimeofday(&t_lastsend, NULL); debug(2, "calling status_query_func for %p - connect", server); process_func_ret( server, server->type->status_query_func(server) ); connected++; if (!waiting_for_masters) { last_server_bind = server; } break; } else if (rc == -3) { // Connect in progress // We add to increment connected as we need to know the total // amount of connections in progress not just those that have // successfuly completed their connection otherwise we could // blow FD_SETSIZE connected++; inprogress++; } else if (rc == -2 && ++retry_count > 2) { return -2; } else if (-1 == rc) { cleanup_qserver(server, FORCE); } } server = next_server; } // Wait for all connections to succeed or fail last_server = server; while (inprogress) { inprogress = 0; server = first_server; for (; server != last_server;) { next_server = server->next; if (STATE_CONNECTING == server->state) { rc = connected_qserver(server, 1); switch(rc) { case 0: // Connected gettimeofday(&t_lastsend, NULL); debug(2, "calling status_query_func for %p - in progress", server); process_func_ret( server, server->type->status_query_func(server) ); // NOTE: connected is already incremented if (!waiting_for_masters) { last_server_bind = server; } break; case -2: // In progress inprogress++; break; case -1: cleanup_qserver(server, FORCE); break; } } server = next_server; } } if (NULL != last_server || (!connected && retry_count)) { // Retry later, more to process return -2; } return 0; } int process_func_ret( struct qserver *server, int ret ) { debug( 3, "%p, %d", server, ret ); switch ( ret ) { case INPROGRESS: return ret; case DONE_AUTO: cleanup_qserver( server, NO_FORCE ); return ret; case DONE_FORCE: case SYS_ERROR: case MEM_ERROR: case PKT_ERROR: case ORD_ERROR: case REQ_ERROR: cleanup_qserver( server, FORCE ); return ret; } debug(0, "unhandled return code %d, please report!", ret); return ret; } /* * Functions for sending packets */ // this is so broken, someone please rewrite the timeout handling void send_packets() { struct qserver *server; struct timeval now; int interval, n_sent = 0, prev_n_sent; unsigned i; debug(3, "processing..."); gettimeofday(&now, NULL); if (!t_lastsend.tv_sec) { // nothing } else if (connected && sendinterval && time_delta(&now, &t_lastsend) < sendinterval) { return ; } for (i = 0; i < max_connmap; ++i) { server = connmap[i]; if (!server) { continue; } if (server->fd == -1) { debug(0, "invalid entry in connmap\n"); } if (server->type->id &MASTER_SERVER) { interval = master_retry_interval; } else { interval = retry_interval; } debug(2, "server %p, name %s, retry1 %d, next_rule %p, next_player_info %d, num_players %d, n_retries %d", server, server->server_name, server->retry1, server->next_rule, server->next_player_info, server->num_players, n_retries ); prev_n_sent = n_sent; if (server->server_name == NULL) { // We havent seen the server yet? if (server->retry1 != n_retries && time_delta(&now, &server->packet_time1) < (interval *(n_retries - server->retry1 + 1))) { continue; } if (server->retry1 < 1) { // No more retries cleanup_qserver( server, FORCE ); continue; } if ( qserver_get_timeout(server, &now) <= 0 && ! ( server->type->flags & TF_TCP_CONNECT ) ) { // Query status debug(2, "calling status_query_func for %p", server); process_func_ret( server, server->type->status_query_func(server) ); gettimeofday(&t_lastsend, NULL); n_sent++; continue; } } if (server->next_rule != NO_SERVER_RULES) { // We want server rules if (server->retry1 != n_retries && time_delta(&now, &server->packet_time1) < (interval *(n_retries - server->retry1 + 1))) { continue; } if (server->retry1 < 1) { // no more retries server->next_rule = NULL; server->missing_rules = 1; cleanup_qserver( server, NO_FORCE ); continue; } debug(3, "send_rule_request_packet1"); send_rule_request_packet(server); gettimeofday(&t_lastsend, NULL); n_sent++; } if (server->next_player_info < server->num_players) { // Expecting player details if (server->retry2 != n_retries && time_delta(&now, &server->packet_time2) < (interval *(n_retries - server->retry2 + 1))) { continue; } if (!server->retry2) { server->next_player_info++; if (server->next_player_info >= server->num_players) { // no more retries cleanup_qserver( server, FORCE ); continue; } server->retry2 = n_retries; } send_player_request_packet(server); gettimeofday(&t_lastsend, NULL); n_sent++; } if (prev_n_sent == n_sent) { // we didnt send any additional queries debug(2, "no queries sent: %d %d", time_delta(&now, &server->packet_time1), (interval *(n_retries + 1))); if (server->retry1 < 1) { // no retries left if (time_delta(&now, &server->packet_time1) > (interval *(n_retries + 1))) { cleanup_qserver( server, FORCE ); } } else { // decrement as we didnt send any packets server->retry1--; } } } debug(3, "done"); } /* server starts sending data immediately, so we need not do anything */ query_status_t send_bfris_request_packet(struct qserver *server) { return register_send(server); } /* First packet for a normal Quake server */ query_status_t send_qserver_request_packet(struct qserver *server) { return send_packet(server, server->type->status_packet, server->type->status_len); } /* First packet for a QuakeWorld server */ query_status_t send_qwserver_request_packet(struct qserver *server) { int rc; if (server->flags &FLAG_BROADCAST) { rc = send_broadcast(server, server->type->status_packet, server->type->status_len); } else if (server->server_name == NULL) { rc = send(server->fd, server->type->status_packet, server->type->status_len, 0); } else if (server->server_name != NULL && server->type->rule_packet) { rc = send(server->fd, server->type->rule_packet, server->type->rule_len, 0); } else { rc = SOCKET_ERROR; } if (rc == SOCKET_ERROR) { return send_error( server, rc ); } if (server->retry1 == n_retries || server->flags &FLAG_BROADCAST) { gettimeofday(&server->packet_time1, NULL); server->n_requests++; } else if (server->server_name == NULL) { server->n_retries++; } server->retry1--; if (server->server_name == NULL) { server->n_packets++; } server->next_player_info = NO_PLAYER_INFO; // we don't have a player packet return INPROGRESS; } // First packet for an Unreal Tournament 2003 server query_status_t send_ut2003_request_packet(struct qserver *server) { int ret = send_packet(server, server->type->status_packet, server->type->status_len); server->next_player_info = NO_PLAYER_INFO; return ret; } // First packet for an Half-Life 2 server query_status_t send_hl2_request_packet(struct qserver *server) { return send_packet(server, server->type->status_packet, server->type->status_len); } /* First packet for an Unreal master */ query_status_t send_unrealmaster_request_packet(struct qserver *server) { return send_packet(server, server->type->status_packet, server->type->status_len); } static const char *steam_region[] = { "US East Coast", "US West Coast", "South America", "Europe", "Asia", "Australia", "Middle East", "Africa", NULL }; char *build_hlmaster_packet(struct qserver *server, int *len) { static char packet[1600]; char *pkt, *r, *sep = ""; char *gamedir, *map, *flags; int flen; pkt = &packet[0]; memcpy(pkt, server->type->master_packet, *len); if (server->type->flags &TF_MASTER_STEAM) { // default the region to 0xff const char *regionstring = get_param_value(server, "region", NULL); int region = 0xFF; if (regionstring) { char *tmp = NULL; region = strtol(regionstring, &tmp, 10); if (tmp == regionstring) { int i = 0; region = 0xFF; for (; steam_region[i]; ++i) { if (!strcmp(regionstring, steam_region[i])) { region = i; break; } } } } *(pkt + 1) = region; } pkt += *len; gamedir = get_param_value(server, "game", NULL); if (gamedir) { pkt += sprintf(pkt, "\\gamedir\\%s", gamedir); } // not valid for steam? map = get_param_value(server, "map", NULL); if (map) { pkt += sprintf(pkt, "\\map\\%s", map); } // steam flags = get_param_value(server, "napp", NULL); if ( flags ) { pkt += sprintf( pkt, "\\napp\\%s", flags ); } // not valid for steam? flags = get_param_value(server, "status", NULL); r = flags; while (flags && sep) { sep = strchr(r, ':'); if (sep) { flen = sep - r; } else { flen = strlen(r); } if (strncmp(r, "notempty", flen) == 0) { pkt += sprintf(pkt, "\\empty\\1"); } else if (strncmp(r, "notfull", flen) == 0) { pkt += sprintf(pkt, "\\full\\1"); } else if (strncmp(r, "dedicated", flen) == 0) { if (server->type->flags &TF_MASTER_STEAM) { pkt += sprintf(pkt, "\\type\\d"); } else { pkt += sprintf(pkt, "\\dedicated\\1"); } } else if (strncmp(r, "linux", flen) == 0) { pkt += sprintf(pkt, "\\linux\\1"); } else if (strncmp(r, "proxy", flen) == 0) // steam { pkt += sprintf(pkt, "\\proxy\\1"); } else if (strncmp(r, "secure", flen) == 0) // steam { pkt += sprintf(pkt, "\\secure\\1"); } r = sep + 1; } // always need null terminator *pkt = 0x00; pkt++; *len = pkt - packet; return packet; } /* First packet for a QuakeWorld master server */ query_status_t send_qwmaster_request_packet(struct qserver *server) { int rc = 0; server->next_player_info = NO_PLAYER_INFO; if (server->type->id == Q2_MASTER) { struct sockaddr_in addr; addr.sin_family = AF_INET; if (no_port_offset || server->flags &TF_NO_PORT_OFFSET) { addr.sin_port = htons(server->port); } else { addr.sin_port = htons((unsigned short)(server->port + server->type->port_offset)); } addr.sin_addr.s_addr = server->ipaddr; memset(&(addr.sin_zero), 0, sizeof(addr.sin_zero)); rc = sendto(server->fd, server->type->master_packet, server->type->master_len, 0, (struct sockaddr*) &addr, sizeof(addr)); } else { char *packet; int packet_len; char query_buf[4096] = { 0 }; packet = server->type->master_packet; packet_len = server->type->master_len; if (server->type->id == HL_MASTER) { memcpy(server->type->master_packet + 1, server->master_query_tag, 3); if (server->query_arg) { packet_len = server->type->master_len; packet = build_hlmaster_packet(server, &packet_len); } } else if (server->type->flags &TF_MASTER_STEAM) { // region int tag_len = strlen(server->master_query_tag); if (tag_len < 9) { // initial case tag_len = 9; strcpy(server->master_query_tag, "0.0.0.0:0"); } // 1 byte packet id // 1 byte region // ip:port // 1 byte null packet_len = 2+tag_len + 1; if (server->query_arg) { // build_hlmaster_packet uses server->type->master_packet // as the basis so copy from server->master_query_tag strcpy(server->type->master_packet + 2, server->master_query_tag); packet = build_hlmaster_packet(server, &packet_len); } else { // default region *(packet + 1) = 0xff; memcpy(packet + 2, server->master_query_tag, tag_len); // filter null *(packet + packet_len) = 0x00; packet_len++; } } else if (server->type->flags &TF_QUERY_ARG) { // fill in the master protocol details char *master_protocol = server->query_arg; if (master_protocol == NULL) { master_protocol = server->type->master_protocol; } packet_len = sprintf(query_buf, server->type->master_packet, master_protocol ? master_protocol : "", server->type->master_query ? server->type->master_query: "" ); packet = query_buf; } rc = send(server->fd, packet, packet_len, 0); } if (rc == SOCKET_ERROR) { return send_error( server, rc ); } if (server->retry1 == n_retries) { gettimeofday(&server->packet_time1, NULL); server->n_requests++; } else { server->n_retries++; } server->retry1--; server->n_packets++; return INPROGRESS; } query_status_t send_tribes_request_packet(struct qserver *server) { return send_packet(server, server->type->player_packet, server->type->player_len); } query_status_t send_tribes2_request_packet(struct qserver *server) { int rc; if (server->flags &FLAG_BROADCAST && server->server_name == NULL) { rc = send_broadcast(server, server->type->status_packet, server->type->status_len); } else if (server->server_name == NULL) { rc = send(server->fd, server->type->status_packet, server->type->status_len, 0); } else { rc = send(server->fd, server->type->player_packet, server->type->player_len, 0); } if (rc == SOCKET_ERROR) { return send_error( server, rc ); } register_send(server); return rc; } 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 send_farcry_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 send_tribes2master_request_packet(struct qserver *server) { int rc; unsigned char packet[1600], *pkt; unsigned int len, min_players, max_players, region_mask = 0; unsigned int build_version, max_bots, min_cpu, status; char *game, *mission, *buddies; static char *region_list[] = { "naeast", "nawest", "sa", "aus", "asia", "eur", NULL }; static char *status_list[] = { "dedicated", "nopassword", "linux" }; if (strcmp(get_param_value(server, "query", ""), "types") == 0) { rc = send(server->fd, tribes2_game_types_request, sizeof(tribes2_game_types_request), 0); goto send_done; } memcpy(packet, server->type->master_packet, server->type->master_len); pkt = packet + 7; game = get_param_value(server, "game", "any"); len = strlen(game); if (len > 255) { len = 255; } *pkt++ = len; memcpy(pkt, game, len); pkt += len; mission = get_param_value(server, "mission", "any"); len = strlen(mission); if (len > 255) { len = 255; } *pkt++ = len; memcpy(pkt, mission, len); pkt += len; min_players = get_param_ui_value(server, "minplayers", 0); max_players = get_param_ui_value(server, "maxplayers", 255); *pkt++ = min_players; *pkt++ = max_players; region_mask = get_param_ui_value(server, "regions", 0xffffffff); if (region_mask == 0) { char *regions = get_param_value(server, "regions", ""); char *r = regions; char **list, *sep; do { sep = strchr(r, ':'); if (sep) { len = sep - r; } else { len = strlen(r); } for (list = region_list; *list; list++) if (strncasecmp(r, *list, len) == 0) { break; } if (*list) { region_mask |= 1 << (list - region_list); } r = sep + 1; } while (sep); } if (little_endian) { memcpy(pkt, ®ion_mask, 4); } else { pkt[0] = region_mask &0xff; pkt[1] = (region_mask >> 8) &0xff; pkt[2] = (region_mask >> 16) &0xff; pkt[3] = (region_mask >> 24) &0xff; } pkt += 4; build_version = get_param_ui_value(server, "build", 0); /* if ( build_version && build_version < 22337) { packet[1]= 0; build_version= 0; } */ if (little_endian) { memcpy(pkt, &build_version, 4); } else { pkt[0] = build_version &0xff; pkt[1] = (build_version >> 8) &0xff; pkt[2] = (build_version >> 16) &0xff; pkt[3] = (build_version >> 24) &0xff; } pkt += 4; status = get_param_ui_value(server, "status", - 1); if (status == 0) { char *flags = get_param_value(server, "status", ""); char *r = flags; char **list, *sep; do { sep = strchr(r, ':'); if (sep) { len = sep - r; } else { len = strlen(r); } for (list = status_list; *list; list++) if (strncasecmp(r, *list, len) == 0) { break; } if (*list) { status |= 1 << (list - status_list); } r = sep + 1; } while (sep); } else if (status == -1) { status = 0; } *pkt++ = status; max_bots = get_param_ui_value(server, "maxbots", 255); *pkt++ = max_bots; min_cpu = get_param_ui_value(server, "mincpu", 0); if (little_endian) { memcpy(pkt, &min_cpu, 2); } else { pkt[0] = min_cpu &0xff; pkt[1] = (min_cpu >> 8) &0xff; } pkt += 2; buddies = get_param_value(server, "buddies", NULL); if (buddies) { char *b = buddies, *sep; unsigned int buddy, n_buddies = 0; unsigned char *n_loc = pkt++; do { sep = strchr(b, ':'); if (sscanf(b, "%u", &buddy)) { n_buddies++; if (little_endian) { memcpy(pkt, &buddy, 4); } else { pkt[0] = buddy &0xff; pkt[1] = (buddy >> 8) &0xff; pkt[2] = (buddy >> 16) &0xff; pkt[3] = (buddy >> 24) &0xff; } pkt += 4; } b = sep + 1; } while (sep && n_buddies < 255); *n_loc = n_buddies; } else { *pkt++ = 0; } rc = send(server->fd, (char*)packet, pkt - packet, 0); send_done: if (rc == SOCKET_ERROR) { return send_error( server, rc ); } if (server->retry1 == n_retries) { gettimeofday(&server->packet_time1, NULL); server->n_requests++; } else { server->n_retries++; } server->retry1--; server->n_packets++; return INPROGRESS; } static struct _gamespy_query_map { char *qstat_type; char *gamespy_type; } gamespy_query_map[] = { { "qws", "quakeworld" }, { "q2s", "quake2" }, { "q3s", "quake3" }, { "tbs", "tribes" }, { "uns", "ut" }, { "sgs", "shogo" }, { "hls", "halflife" }, { "kps", "kingpin" }, { "hrs", "heretic2" }, { "sfs", "sofretail" }, { NULL, NULL } }; query_status_t send_gamespy_master_request(struct qserver *server) { int rc, i; char request[1024]; if (server->n_packets) { return DONE_AUTO; } // WARNING: This only works for masters which don't check the value of validate // e.g. unreal.epicgames.com // // What we should be doing here is recieving the challenge from the master // processing the secure key and then using that as the value for validate. // // The details of this can be seen in gslist: // http://aluigi.altervista.org/papers.htm#gslist rc = send(server->fd, server->type->master_packet, server->type->master_len, 0); if (rc != server->type->master_len) { return send_error( server, rc ); } strcpy(request, server->type->status_packet); for (i = 0; gamespy_query_map[i].qstat_type; i++) { if (strcasecmp(server->query_arg, gamespy_query_map[i].qstat_type) == 0) { break; } } if (gamespy_query_map[i].gamespy_type == NULL) { strcat(request, server->query_arg); } else { strcat(request, gamespy_query_map[i].gamespy_type); } strcat(request, "\\final\\"); assert(strlen(request) < sizeof(request)); rc = send(server->fd, request, strlen(request), 0); if (rc != strlen(request)) { return send_error( server, rc ); } if (server->retry1 == n_retries) { gettimeofday(&server->packet_time1, NULL); server->n_requests++; } server->n_packets++; return INPROGRESS; } query_status_t send_rule_request_packet(struct qserver *server) { int rc, len; debug(3, "send_rule_request_packet: %p", server); /* Server created via broadcast, so bind it */ if (server->fd == -1) { if (bind_qserver(server) < 0) { goto setup_retry; } } if (server->type->rule_query_func && server->type->rule_query_func != send_rule_request_packet) { return server->type->rule_query_func(server); } if (server->type->id == Q_SERVER) { strcpy((char*)q_rule.data, server->next_rule); len = Q_HEADER_LEN + strlen((char*)q_rule.data) + 1; q_rule.length = htons((short)len); } else { len = server->type->rule_len; } rc = send(server->fd, (const char*)server->type->rule_packet, len, 0); if (rc == SOCKET_ERROR) { return send_error( server, rc ); } setup_retry: if (server->retry1 == n_retries) { gettimeofday(&server->packet_time1, NULL); server->n_requests++; } else if (server->server_name == NULL) { server->n_retries++; } server->retry1--; if (server->server_name == NULL) { server->n_packets++; } return DONE_AUTO; } query_status_t send_player_request_packet(struct qserver *server) { int rc; debug( 3, "send_player_request_packet %p", server ); if (!server->type->player_packet) { return 0; } /* Server created via broadcast, so bind it */ if (server->fd == -1) { if (bind_qserver(server) < 0) { goto setup_retry; } } if (server->type->player_query_func && server->type->player_query_func != send_player_request_packet) { return server->type->player_query_func(server); } if (!server->type->player_packet) { debug(0, "error: server %p has no player_packet", server); return 0; } if (server->type->id == Q_SERVER) { q_player.data[0] = server->next_player_info; } rc = send(server->fd, (const char*)server->type->player_packet, server->type->player_len, 0); if (rc == SOCKET_ERROR) { return send_error( server, rc ); } setup_retry: if (server->retry2 == n_retries) { gettimeofday(&server->packet_time2, NULL); server->n_requests++; } else { server->n_retries++; } server->retry2--; server->n_packets++; return 1; } void qserver_disconnect(struct qserver *server) { #ifdef _WIN32 int i; #endif if (server->fd != - 1) { close(server->fd); #ifndef _WIN32 connmap[server->fd] = NULL; #else for (i = 0; i < max_connmap; i++) { if (connmap[i] == server) { connmap[i] = NULL; break; } } #endif server->fd = - 1; connected--; } } /* Functions for figuring timeouts and when to give up * Returns 1 if the query is done (server may be freed) and 0 if not. */ int cleanup_qserver(struct qserver *server, int force) { int close_it = force; debug( 3, "cleanup_qserver %p, %d", server, force ); if ( server->server_name == NULL ) { debug(3, "server has no name, forcing close"); close_it = 1; if (server->type->id &MASTER_SERVER && server->master_pkt != NULL) { server->server_name = MASTER; } else { server->server_name = TIMEOUT; num_servers_timed_out++; } } else if (server->type->flags &TF_SINGLE_QUERY) { debug(3, "TF_SINGLE_QUERY, forcing close"); close_it = 1; } else if (server->next_rule == NO_SERVER_RULES && server->next_player_info >= server->num_players) { debug(3, "no server rules and next_player_info >= num_players, forcing close"); close_it = 1; } debug(3, "close_it %d", close_it); if (close_it) { if (server->saved_data.data) { SavedData *sdata = server->saved_data.next; free(server->saved_data.data); server->saved_data.data = NULL; while (sdata != NULL) { SavedData *next; free(sdata->data); next = sdata->next; free(sdata); sdata = next; } server->saved_data.next = NULL; } qserver_disconnect(server); if (server->server_name != TIMEOUT) { num_servers_returned++; if (server->server_name != DOWN) { num_players_total += server->num_players; max_players_total += server->max_players; } } if (server->server_name == TIMEOUT || server->server_name == DOWN) { server->ping_total = 999999; } if (server->type->master) { waiting_for_masters--; if (waiting_for_masters == 0) { add_servers_from_masters(); } } if (!server_sort) { display_server(server); } return 1; } return 0; } /** must be called only on connected servers * @returns time in ms until server needs timeout handling. timeout handling is needed if <= zero */ static int qserver_get_timeout(struct qserver *server, struct timeval *now) { int diff, diff1, diff2, interval; if (server->type->id &MASTER_SERVER) { interval = master_retry_interval; } else { interval = retry_interval; } diff2 = 0xffff; diff1 = interval *(n_retries - server->retry1 + 1) - time_delta(now, &server->packet_time1); if (server->next_player_info < server->num_players) { diff2 = interval *(n_retries - server->retry2 + 1) - time_delta(now, &server->packet_time2); } debug(2, "timeout for %p is diff1 %d diff2 %d", server, diff1, diff2); diff = (diff1 < diff2) ? diff1 : diff2; return diff; } void get_next_timeout(struct timeval *timeout) { struct qserver *server = servers; struct timeval now; int diff, smallest = retry_interval + master_retry_interval; int bind_count = 0; if (first_server_bind == NULL) { first_server_bind = servers; } server = first_server_bind; for (; server != NULL && server->fd == -1; server = server->next) ; /* if there are unconnected servers and slots left we retry in 10ms */ if (server == NULL || (num_servers > connected && connected < max_simultaneous)) { timeout->tv_sec = 0; timeout->tv_usec = 10 * 1000; return ; } first_server_bind = server; gettimeofday(&now, NULL); for (; server != NULL && bind_count < connected; server = server->next) { if (server->fd == -1) { continue; } diff = qserver_get_timeout(server, &now); if (diff < smallest) { smallest = diff; } bind_count++; } if (smallest < 10) { smallest = 10; } timeout->tv_sec = smallest / 1000; timeout->tv_usec = (smallest % 1000) *1000; } #ifdef USE_SELECT static fd_set select_read_fds; static int select_maxfd; static int select_cursor; int set_fds(fd_set *fds) { int maxfd = - 1, i; for (i = 0; i < max_connmap; i++) { if (connmap[i] != NULL) { FD_SET(connmap[i]->fd, fds); if (connmap[i]->fd > maxfd) { maxfd = connmap[i]->fd; } } } return maxfd; } void set_file_descriptors() { FD_ZERO(&select_read_fds); select_maxfd = set_fds(&select_read_fds); } int wait_for_file_descriptors(struct timeval *timeout) { select_cursor = 0; return select(select_maxfd + 1, &select_read_fds, NULL, NULL, timeout); } struct qserver *get_next_ready_server() { while (select_cursor < max_connmap && (connmap[select_cursor] == NULL || !FD_ISSET(connmap[select_cursor]->fd, &select_read_fds))) { select_cursor++; } if (select_cursor >= max_connmap) { return NULL; } return connmap[select_cursor++]; } int wait_for_timeout(unsigned int ms) { struct timeval timeout; timeout.tv_sec = ms / 1000; timeout.tv_usec = (ms % 1000) *1000; return select(0, 0, NULL, NULL, &timeout); } #endif /* USE_SELECT */ #ifdef USE_POLL static struct pollfd *pollfds; static int n_pollfds; static int max_pollfds = 0; static int poll_cursor; void set_file_descriptors() { struct pollfd *p; int i; if (max_connmap > max_pollfds) { max_pollfds = max_connmap; pollfds = (struct pollfd*)realloc(pollfds, max_pollfds *sizeof(struct pollfd)); } p = pollfds; for (i = 0; i < max_connmap; i++) if (connmap[i] != NULL) { p->fd = connmap[i]->fd; p->events = POLLIN; p->revents = 0; p++; } n_pollfds = p - pollfds; } int wait_for_file_descriptors(struct timeval *timeout) { poll_cursor = 0; return poll(pollfds, n_pollfds, timeout->tv_sec *1000+timeout->tv_usec / 1000); } struct qserver *get_next_ready_server() { for (; poll_cursor < n_pollfds; poll_cursor++) { if (pollfds[poll_cursor].revents) { break; } } if (poll_cursor >= n_pollfds) { return NULL; } return connmap[pollfds[poll_cursor++].fd]; } int wait_for_timeout(unsigned int ms) { return poll(0, 0, ms); } #endif /* USE_POLL */ void free_server(struct qserver *server) { struct player *player, *next_player; struct rule *rule, *next_rule; /* remove from servers list */ if (server == servers) { servers = server->next; if (servers) { servers->prev = NULL; } } if ((void*) &server->next == (void*)last_server) { if (server->prev) { last_server = &server->prev->next; } else { last_server = &servers; } } if (server == first_server_bind) { first_server_bind = server->next; } if (server == last_server_bind) { last_server_bind = server->next; } if (server->prev) { server->prev->next = server->next; } if (server->next) { server->next->prev = server->prev; } /* remove from server hash table */ remove_server_from_hash(server); /* free all the data */ for (player = server->players; player; player = next_player) { next_player = player->next; free_player(player); } for (rule = server->rules; rule; rule = next_rule) { next_rule = rule->next; free_rule(rule); } if (server->arg) { free(server->arg); } if (server->host_name) { free(server->host_name); } if (server->error) { free(server->error); } if (server->address) { free(server->address); } if (server->map_name) { free(server->map_name); } if (!(server->flags &FLAG_DO_NOT_FREE_GAME) && server->game) { free(server->game); } if (server->master_pkt) { free(server->master_pkt); } if ( server->query_arg ) { free(server->query_arg); } if ( server->challenge_string ) { free(server->challenge_string); } /* These fields are never malloc'd: outfilename */ if ( server->server_name != NULL && server->server_name != DOWN && server->server_name != HOSTNOTFOUND && server->server_name != SYSERROR && server->server_name != MASTER && server->server_name != SERVERERROR && server->server_name != TIMEOUT && server->server_name != GAMESPY_MASTER_NAME && server->server_name != BFRIS_SERVER_NAME ) { free(server->server_name); } /* params ... saved_data ... */ free(server); --num_servers; } void free_player(struct player *player) { if (player->name) { free(player->name); } if (!(player->flags &PLAYER_FLAG_DO_NOT_FREE_TEAM) && player->team_name) { free(player->team_name); } if (player->address) { free(player->address); } if (player->tribe_tag) { free(player->tribe_tag); } if (player->skin) { free(player->skin); } if (player->mesh) { free(player->mesh); } if (player->face) { free(player->face); } free(player); } void free_rule(struct rule *rule) { if (rule->name) { free(rule->name); } if (rule->value) { free(rule->value); } free(rule); } /* Functions for handling response packets */ /* Packet from normal Quake server */ query_status_t deal_with_q_packet(struct qserver *server, char *rawpkt, int pktlen) { struct q_packet *pkt = (struct q_packet*)rawpkt; int rc; debug( 2, "deal_with_q_packet %p, %d", server, pktlen ); if (ntohs(pkt->length) != pktlen) { fprintf(stderr, "%s Ignoring bogus packet; length %d != %d\n", server->arg, ntohs(pkt->length), pktlen); return PKT_ERROR; } rawpkt[pktlen] = '\0'; switch (pkt->op_code) { case Q_CCREP_ACCEPT: case Q_CCREP_REJECT: return 0; case Q_CCREP_SERVER_INFO: server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); rc = server_info_packet(server, pkt, pktlen - Q_HEADER_LEN); break; case Q_CCREP_PLAYER_INFO: server->ping_total += time_delta(&packet_recv_time, &server->packet_time2); rc = player_info_packet(server, pkt, pktlen - Q_HEADER_LEN); break; case Q_CCREP_RULE_INFO: server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); rc = rule_info_packet(server, pkt, pktlen - Q_HEADER_LEN); break; case Q_CCREQ_CONNECT: case Q_CCREQ_SERVER_INFO: case Q_CCREQ_PLAYER_INFO: case Q_CCREQ_RULE_INFO: default: return 0; } if ( SOCKET_ERROR == rc ) { fprintf(stderr, "%s error on packet opcode %x\n", server->arg, (int)pkt->op_code); } return rc; } /* Packet from QuakeWorld server */ query_status_t deal_with_qw_packet(struct qserver *server, char *rawpkt, int pktlen) { debug( 2, "deal_with_qw_packet %p, %d", server, pktlen ); if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } if (((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' || rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors) { unsigned int ipaddr = ntohl(server->ipaddr); fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, ntohs(server->port) ); print_packet(server, rawpkt, pktlen); } rawpkt[pktlen] = '\0'; if (rawpkt[4] == 'n') { if (server->type->id != QW_SERVER) { server->type = find_server_type_id(QW_SERVER); } return deal_with_q1qw_packet(server, rawpkt, pktlen); } else if (rawpkt[4] == '\377' && rawpkt[5] == 'n') { if (server->type->id != HW_SERVER) { server->type = find_server_type_id(HW_SERVER); } return deal_with_q1qw_packet(server, rawpkt, pktlen); } else if (strncmp(&rawpkt[4], "print\n\\", 7) == 0) { return deal_with_q2_packet(server, rawpkt + 10, pktlen - 10 ); } else if (strncmp(&rawpkt[4], "print\n", 6) == 0) { /* work-around for occasional bug in Quake II status packets */ char *c, *p; p = c = &rawpkt[10]; while (*p != '\\' && (c = strchr(p, '\n'))) { p = c + 1; } if (*p == '\\' && c != NULL) { return deal_with_q2_packet(server, p, pktlen - (p - rawpkt) ); } } else if (strncmp(&rawpkt[4], "infoResponse", 12) == 0 || (rawpkt[4] == '\001' && strncmp(&rawpkt[5], "infoResponse", 12) == 0)) { /* quake3 info response */ int ret; if (rawpkt[4] == '\001') { rawpkt++; pktlen--; } rawpkt += 12; pktlen -= 12; for (; pktlen && *rawpkt != '\\'; pktlen--, rawpkt++) ; if (!pktlen) { return INPROGRESS; } if (rawpkt[pktlen - 1] == '"') { rawpkt[pktlen - 1] = '\0'; pktlen--; } if (get_player_info || get_server_rules) { server->next_rule = ""; } ret = deal_with_q2_packet(server, rawpkt, pktlen ); if ( DONE_AUTO == ret && ( get_player_info || get_server_rules ) ) { debug(3, "send_rule_request_packet2"); send_rule_request_packet( server); server->retry1= n_retries-1; return INPROGRESS; } return ret; } else if (strncmp(&rawpkt[4], "statusResponse\n", 15) == 0 || (rawpkt[4] == '\001' && strncmp(&rawpkt[5], "statusResponse\n", 15) == 0)) { /* quake3 status response */ server->next_rule = NO_SERVER_RULES; server->retry1 = 0; if (rawpkt[4] == '\001') { rawpkt++; pktlen--; } server->flags |= CHECK_DUPLICATE_RULES; return deal_with_q2_packet(server, rawpkt + 19, pktlen - 19 ); } else if (strncmp(&rawpkt[4], "infostringresponse", 19) == 0) { return deal_with_q2_packet(server, rawpkt + 23, pktlen - 23 ); } if (show_errors) { unsigned int ipaddr = ntohl(server->ipaddr); fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, ignoring ...\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, ntohs(server->port) ); print_packet(server, rawpkt, pktlen); return PKT_ERROR; } return DONE_AUTO; } query_status_t deal_with_q1qw_packet(struct qserver *server, char *rawpkt, int pktlen) { char *key, *value, *end, *users; struct player *player = NULL, **last_player = &server->players; int len, rc, complete = 0; int number, frags, connect_time, ping; char *pkt = &rawpkt[5]; debug( 2, "deal_with_q1qw_packet %p, %d", server, pktlen ); if (server->type->id == HW_SERVER) { pkt = &rawpkt[6]; } *(users = strchr(pkt, '\n')) = '\0'; while (*pkt && pkt - rawpkt < pktlen) { if (*pkt == '\\') { pkt++; end = strchr(pkt, '\\'); if (end == NULL) { break; } *end = '\0'; key = pkt; pkt += strlen(pkt) + 1; end = strchr(pkt, '\\'); if (end == NULL) { end = users; } value = (char*)malloc(end - pkt + 1); memcpy(value, pkt, end - pkt); value[end - pkt] = '\0'; pkt = end; if (strcmp(key, "hostname") == 0) { server->server_name = value; } else if (strcmp(key, "map") == 0) { server->map_name = value; } else if (strcmp(key, "maxclients") == 0) { server->max_players = atoi(value); free(value); } else if (strcmp(key, "maxspectators") == 0) { server->max_spectators = atoi(value); free(value); } else if (get_server_rules || strncmp(key, "*game", 5) == 0) { add_rule(server, key, value, NO_VALUE_COPY); if (strcmp(key, "*gamedir") == 0) { server->game = value; server->flags |= FLAG_DO_NOT_FREE_GAME; } } } else { pkt++; } complete = 1; } *pkt = '\n'; while (*pkt && pkt - rawpkt < pktlen) { if (*pkt == '\n') { pkt++; if (pkt - rawpkt >= pktlen || *pkt == '\0') { break; } rc = sscanf(pkt, "%d %d %d %d %n", &number, &frags, &connect_time, &ping, &len); if (rc != 4) { char *nl; /* assume it's an error packet */ server->error = (char*)malloc(pktlen + 1); nl = strchr(pkt, '\n'); if (nl != NULL) { strncpy(server->error, pkt, nl - pkt); server->error[nl - pkt] = '\0'; } else { strcpy(server->error, pkt); } server->server_name = SERVERERROR; complete = 1; break; } if (get_player_info) { player = (struct player*)calloc(1, sizeof(struct player)); player->number = number; player->frags = frags; player->connect_time = connect_time * 60; player->ping = ping > 0 ? ping : - ping; } else { player = NULL; } pkt += len; if (*pkt != '"') { break; } pkt += ping > 0 ? 1 : 4; // if 4 then no "\s\" in spectators name // protocol "under construction" end = strchr(pkt, '"'); if (end == NULL) { break; } if (player != NULL) { player->name = (char*)malloc(end - pkt + 1); memcpy(player->name, pkt, end - pkt); player->name[end - pkt] = '\0'; } pkt = end + 2; if (*pkt != '"') { break; } pkt++; end = strchr(pkt, '"'); if (end == NULL) { break; } if (player != NULL) { player->skin = (char*)malloc(end - pkt + 1); memcpy(player->skin, pkt, end - pkt); player->skin[end - pkt] = '\0'; } pkt = end + 2; if (player != NULL) { sscanf(pkt, "%d %d%n", &player->shirt_color, &player->pants_color, &len); *last_player = player; last_player = &player->next; } else { sscanf(pkt, "%*d %*d%n", &len); } pkt += len; if (pkt + 3 < rawpkt + pktlen && *pkt == ' ') // mvdsv is at last rev 377, 23.06.2006 { pkt++; if (*pkt != '"') { break; } pkt++; end = strchr(pkt, '"'); if (end == NULL) { break; } if (player != NULL) { player->team_name = (char*)malloc(end - pkt + 1); memcpy(player->team_name, pkt, end - pkt); player->team_name[end - pkt] = '\0'; } pkt = end + 1; } if (ping > 0) { server->num_players++; } else { server->num_spectators++; } } else { pkt++; } complete = 1; } if (!complete) { if (rawpkt[4] != 'n' || rawpkt[5] != '\0') { fprintf(stderr, "Odd packet from QW server %d.%d.%d.%d:%hu ...\n", (server->ipaddr >> 24) &0xff, (server->ipaddr >> 16) &0xff, (server->ipaddr >> 8) &0xff, server->ipaddr &0xff, ntohs(server->port) ); print_packet(server, rawpkt, pktlen); } } else if (server->server_name == NULL) { server->server_name = strdup(""); } return DONE_AUTO; } query_status_t deal_with_q2_packet(struct qserver *server, char *rawpkt, int pktlen ) { char *key, *value, *end; struct player *player = NULL; struct player **last_player = &server->players; int len, rc, complete = 0; int frags = 0, ping = 0, num_players = 0; char *pkt = rawpkt; debug( 2, "deal_with_q2_packet %p, %d", server, pktlen ); while (*pkt && pkt - rawpkt < pktlen) { // we have variable, value pairs seperated by slash if (*pkt == '\\') { pkt++; if (*pkt == '\n' && server->type->id == SOF_SERVER) { goto player_info; } // Find the key end = strchr(pkt, '\\'); if (NULL == end) { break; } *end = '\0'; key = pkt; pkt += strlen(key) + 1; // Find the value end = strpbrk(pkt, "\\\n"); if (NULL == end) { // Last value end = rawpkt + pktlen; } // Make a copy of the value value = (char*)malloc(end - pkt + 1); memcpy(value, pkt, end - pkt); value[end - pkt] = '\0'; pkt = end; debug(3, "%s = %s", key, value); if (server->server_name == NULL && (strcmp(key, "hostname") == 0 || strcmp(key, "sv_hostname") == 0)) { // Server name server->server_name = value; } else if (strcmp(key, "mapname") == 0 || (strcmp(key, "map") == 0 && server->map_name == NULL)) { // Map name if (NULL != server->map_name) { free(server->map_name); } server->map_name = value; } else if (strcmp(key, "maxclients") == 0 || strcmp(key, "sv_maxclients") == 0 || strcmp(key, "max") == 0) { // Max Players server->max_players = atoi(value); // Note: COD 4 infoResponse returns max as sv_maxclients - sv_privateClients where as statusResponse returns the true max // MOHAA Q3 protocol max players is always 0 if (0 == server->max_players) { server->max_players = - 1; } free(value); } else if (strcmp(key, "clients") == 0 || strcmp(key, "players") == 0) { // Num Players server->num_players = atoi(value); free(value); } else if (server->server_name == NULL && strcmp(key, "pure") == 0) { add_rule(server, key, value, NO_VALUE_COPY); } else if (get_server_rules || strncmp(key, "game", 4) == 0) { int dofree = 0; int flags = ( server->flags & CHECK_DUPLICATE_RULES ) ? CHECK_DUPLICATE_RULES | NO_VALUE_COPY : NO_VALUE_COPY; if (add_rule(server, key, value, flags ) == NULL) { // duplicate, so free value dofree = 1; } if (server->game == NULL && strcmp(key, server->type->game_rule) == 0) { server->game = value; if (0 == dofree) { server->flags |= FLAG_DO_NOT_FREE_GAME; } } else if (1 == dofree) { free(value); } } else { free(value); } } else if (*pkt == '\n') { player_info: debug(3, "player info"); pkt++; if (*pkt == '\0') { break; } if (0 == strncmp(pkt, "\\challenge\\", 11)) { // qfusion // This doesnt support getstatus looking at warsow source: // server/sv_main.c: SV_ConnectionlessPacket server->next_rule = NO_SERVER_RULES; debug(3, "no more server rules"); break; } rc = sscanf(pkt, "%d %n", &frags, &len); if (rc == 1 && pkt[len] != '"') { pkt += len; rc = sscanf(pkt, "%d %n", &ping, &len); } else if (rc == 1) { /* MOHAA Q3 protocol only provides player ping */ ping = frags; frags = 0; } if (rc != 1) { char *nl; /* assume it's an error packet */ server->error = (char*)malloc(pktlen + 1); nl = strchr(pkt, '\n'); if (nl != NULL) { strncpy(server->error, pkt, nl - pkt); } else { strcpy(server->error, pkt); } server->server_name = SERVERERROR; complete = 1; break; } if (get_player_info) { player = (struct player*)calloc(1, sizeof(struct player)); player->number = 0; player->connect_time = - 1; player->frags = frags; player->ping = ping; } else { player = NULL; } pkt += len; if (isdigit((unsigned char) *pkt)) { /* probably an SOF2 1.01 server, includes team # */ int team; rc = sscanf(pkt, "%d %n", &team, &len); if (rc == 1) { pkt += len; if (player) { player->team = team; server->flags |= FLAG_PLAYER_TEAMS; } } } if (*pkt != '"') { break; } pkt++; end = strchr(pkt, '"'); if (end == NULL) { break; } if (player != NULL) { player->name = (char*)malloc(end - pkt + 1); memcpy(player->name, pkt, end - pkt); player->name[end - pkt] = '\0'; } pkt = end + 1; //WarSoW team number if (*pkt != '\n') { int team; rc = sscanf(pkt, "%d%n", &team, &len); if (rc == 1) { pkt += len; if (player) { player->team = team; server->flags |= FLAG_PLAYER_TEAMS; } } } if (player != NULL) { player->skin = NULL; player->shirt_color = - 1; player->pants_color = - 1; *last_player = player; last_player = &player->next; } num_players++; } else { pkt++; } complete = 1; } if (server->num_players == 0 || num_players > server->num_players) { server->num_players = num_players; } if (!complete) { return PKT_ERROR; } else if (server->server_name == NULL) { server->server_name = strdup(""); } return DONE_AUTO; } int ack_descent3master_packet(struct qserver *server, char *curtok) { int rc; char packet[0x1e]; memcpy(packet, descent3_masterquery, 0x1a); packet[1] = 0x1d; packet[0x16] = 1; memcpy(packet + 0x1a, curtok, 4); rc = send(server->fd, packet, sizeof(packet), 0); if (rc == SOCKET_ERROR) { return send_error( server, rc ); } return rc; } /* Packet from Descent3 master server (PXO) */ query_status_t deal_with_descent3master_packet(struct qserver *server, char *rawpkt, int pktlen) { int i = 0, lastpacket = 0; char *names = rawpkt + 0x1f; char *ips = rawpkt + 0x29f; char *ports = rawpkt + 0x2ef; debug( 2, "deal_with_descent3master_packet %p, %d", server, pktlen ); while (i < 20) { if (*names) { char *c; server->master_pkt_len += 6; server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len); c = server->master_pkt + server->master_pkt_len - 6; memcpy(c, ips, 4); memcpy(c + 4, ports, 2); } else if (i > 0) { lastpacket = 1; } names += 0x20; ips += 4; ports += 2; i++; } ack_descent3master_packet(server, rawpkt + 0x1a); server->n_servers = server->master_pkt_len / 6; server->next_player_info = - 1; server->retry1 = 0; if (lastpacket) { return DONE_AUTO; } return INPROGRESS; } /* Packet from QuakeWorld master server */ query_status_t deal_with_qwmaster_packet(struct qserver *server, char *rawpkt, int pktlen) { int ret = 0; debug( 2, "deal_with_qwmaster_packet %p, %d", server, pktlen ); server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); if (rawpkt[0] == QW_NACK) { server->error = strdup(&rawpkt[2]); server->server_name = SERVERERROR; return PKT_ERROR; } if (*((unsigned int*)rawpkt) == 0xffffffff) { rawpkt += 4; /* QW 1.5 */ pktlen -= 4; if (rawpkt[0] == '\377' && rawpkt[1] == QW_SERVERS) { rawpkt++; /* hwmaster */ pktlen--; } } if (rawpkt[0] == QW_SERVERS && rawpkt[1] == QW_NEWLINE) { rawpkt += 2; pktlen -= 2; } else if (rawpkt[0] == HL_SERVERS && rawpkt[1] == 0x0d) { // 2 byte id + 4 byte sequence memcpy(server->master_query_tag, rawpkt + 2, 3); rawpkt += 6; pktlen -= 6; } else if (rawpkt[0] == HL_SERVERS && rawpkt[1] == 0x0a) { // no sequence id for steam // instead we use the ip:port of the last recieved server struct in_addr *sin_addr = (struct in_addr*)(rawpkt + pktlen - 6); char *ip = inet_ntoa(*sin_addr); unsigned short port = htons(*((unsigned short*)(rawpkt + pktlen - 2))); //fprintf( stderr, "NEXT IP=%s:%u\n", ip, port ); sprintf(server->master_query_tag, "%s:%u", ip, port); // skip over the 2 byte id rawpkt += 2; pktlen -= 2; } else if (strncmp(rawpkt, "servers", 7) == 0) { rawpkt += 8; pktlen -= 8; } else if (strncmp(rawpkt, "getserversResponse", 18) == 0) { rawpkt += 18; pktlen -= 18; for (; *rawpkt != '\\' && pktlen; pktlen--, rawpkt++){} if (!pktlen) { return 1; } rawpkt++; pktlen--; debug( 2, "q3m pktlen %d lastchar %x\n", pktlen, (unsigned int)rawpkt[pktlen - 1]); server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len + pktlen + 1); if (server->type->id == STEF_MASTER) { ret = decode_stefmaster_packet(server, rawpkt, pktlen); } else { ret = decode_q3master_packet(server, rawpkt, pktlen); } debug( 2, "q3m %d servers\n", server->n_servers); return ret; } else if (show_errors) { unsigned int ipaddr = ntohl(server->ipaddr); fprintf(stderr, "Odd packet from QW master %d.%d.%d.%d, processing ...\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff ); print_packet(server, rawpkt, pktlen); } server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len + pktlen + 1); rawpkt[pktlen] = '\0'; memcpy(server->master_pkt + server->master_pkt_len, rawpkt, pktlen + 1); server->master_pkt_len += pktlen; server->n_servers = server->master_pkt_len / 6; if (server->type->flags &TF_MASTER_MULTI_RESPONSE) { server->next_player_info = - 1; server->retry1 = 0; } else if (server->type->id == HL_MASTER) { if (server->master_query_tag[0] == 0 && server->master_query_tag[1] == 0 && server->master_query_tag[2] == 0) { // all done server->server_name = MASTER; bind_sockets(); ret = DONE_FORCE; } else { // more to come server->retry1++; send_qwmaster_request_packet(server); } } else if (server->type->flags &TF_MASTER_STEAM) { // should the HL_MASTER be the same as this? int i; for (i = pktlen - 6; i < pktlen && 0x00 == rawpkt[i]; i++){} if (i == pktlen) { // last 6 bytes where 0x00 so we have reached the last packet server->n_servers--; server->master_pkt_len -= 6; server->server_name = MASTER; bind_sockets(); ret = DONE_FORCE; } else { // more to come server->retry1++; send_qwmaster_request_packet(server); } } else { server->server_name = MASTER; ret = DONE_AUTO; bind_sockets(); } return ret; } int decode_q3master_packet(struct qserver *server, char *pkt, int pktlen) { char *p; char *end = pkt + pktlen; char *last = end - 6; pkt[pktlen] = 0; p = pkt; while ( p < last ) { // IP & Port memcpy(server->master_pkt + server->master_pkt_len, &p[0], 6); server->master_pkt_len += 6; p += 6; // Sometimes we get some bad IP's so we search for the entry terminator '\' to avoid issues with this while ( p < end && *p != '\\' ) { p++; } if ( p < end ) { // Skip over the '\' p++; } if ( *p && p + 3 == end && 0 == strncmp( "EOF", p, 3 ) ) { // Last packet ID ( seen in COD4 ) server->n_servers = server->master_pkt_len / 6; server->retry1 = 0; // received at least one packet so no need to retry return DONE_FORCE; } } server->n_servers = server->master_pkt_len / 6; // server->next_player_info= -1; evil, causes busy loop! server->retry1 = 0; // received at least one packet so no need to retry return INPROGRESS; } int decode_stefmaster_packet(struct qserver *server, char *pkt, int pktlen) { unsigned char *p, *m, *end; unsigned int i, b; pkt[pktlen] = 0; p = (unsigned char*)pkt; m = (unsigned char*)server->master_pkt + server->master_pkt_len; end = (unsigned char*) &pkt[pktlen - 12]; while (*p && p < end) { for (i = 6; i; i--) { sscanf((char*)p, "%2x", &b); p += 2; *m++ = b; } server->master_pkt_len += 6; while (*p && *p == '\\') { p++; } } server->n_servers = server->master_pkt_len / 6; server->next_player_info = - 1; server->retry1 = 0; return 1; } /* Packet from Tribes master server */ query_status_t deal_with_tribesmaster_packet(struct qserver *server, char *rawpkt, int pktlen) { unsigned char *upkt = (unsigned char*)rawpkt; int packet_number = upkt[2]; int n_packets = upkt[3]; unsigned char *p; char *mpkt; int len; unsigned int ipaddr; debug( 2, "deal_with_tribesmaster_packet %p, %d", server, pktlen ); if (memcmp(rawpkt, tribes_master_response, sizeof(tribes_master_response)) != 0) { fprintf(stderr, "Odd packet from Tribes master server\n"); print_packet(server, rawpkt, pktlen); } /* 0x1006 01 packet number 08 # packets 02 0000 66 0d length of following string "Tribes Master" 3c length of following string "Check out the Starsiege demo now! www.starsiegeplayers.com" 0035 06 d143 4764 812c 06 d1e2 8df3 616d 06 1804 6d50 616d 06 d81c 6dc0 616d */ /* 0x1006 02 08 02 0000 66 00 3f 06 cf88 344c 1227 */ /* printf( "packet_number %d n_packets %d\n", packet_number, n_packets); */ len = upkt[8]; if (len > 0) { p = (unsigned char*)rawpkt + 9; // printf( "%.*s\n", len, p); p += len; len = upkt[8+len + 1]; // printf( "%.*s\n", len, p+1); p += len + 1; p += 2; } else { p = (unsigned char*)rawpkt + 10; } if (server->master_pkt == NULL) { server->master_pkt = (char*)malloc(n_packets *64 * 6); mpkt = server->master_pkt; } else { mpkt = server->master_pkt + server->n_servers *6; } while ((char*)p < rawpkt + pktlen) { if (*p != 0x6) { printf("*p %u\n", (unsigned) *p); } memcpy(mpkt, p + 1, sizeof(ipaddr)); if (0) { mpkt[4] = p[5]; mpkt[5] = p[6]; } else { mpkt[5] = p[5]; mpkt[4] = p[6]; } //printf( "%08x:%hu %u.%u.%u.%u:%hu\n", ipaddr, port, ipaddr>>24, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff, port); p += 7; mpkt += 6; } /* if ( (char*)p != rawpkt+pktlen) printf( "%x %x\n", p, rawpkt+pktlen); */ server->master_pkt_len = mpkt - server->master_pkt; server->n_servers = server->master_pkt_len / 6; server->server_name = MASTER; server->next_player_info = - 1; if (packet_number >= n_packets) { return DONE_FORCE; } else { return DONE_AUTO; } } char *display_tribes2_string_list(unsigned char *pkt) { char *delim = ""; unsigned int count, len; count = *pkt; pkt++; for (; count; count--) { len = *pkt; pkt++; if (len > 0) { if (raw_display) { xform_printf(OF, "%s%.*s", delim, (int)len, pkt); delim = raw_delimiter; } else { xform_printf(OF, "%.*s\n", (int)len, pkt); } } pkt += len; } if (raw_display) { fputs("\n", OF); } return (char*)pkt; } query_status_t deal_with_tribes2master_packet(struct qserver *server, char *pkt, int pktlen) { unsigned int n_servers, index, total, server_limit; char *p, *mpkt; debug( 2, "deal_with_tribes2master_packet %p, %d", server, pktlen ); if (pkt[0] == TRIBES2_RESPONSE_GAME_TYPES) { pkt += 6; if (raw_display) { xform_printf(OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter, server->arg, raw_delimiter); } else { xform_printf(OF, "Game Types\n"); xform_printf(OF, "----------\n"); } pkt = display_tribes2_string_list((unsigned char*)pkt); if (raw_display) { xform_printf(OF, "%s%s%s%s", server->type->type_prefix, raw_delimiter, server->arg, raw_delimiter); } else { xform_printf(OF, "\nMission Types\n"); xform_printf(OF, "-------------\n"); } display_tribes2_string_list((unsigned char*)pkt); server->master_pkt_len = 0; server->n_servers = 0; server->server_name = MASTER; server->next_player_info = - 1; return DONE_FORCE; } if (pkt[0] != TRIBES2_RESPONSE_MASTER) { /* error */ return PKT_ERROR; } server_limit = get_param_ui_value(server, "limit", ~0); n_servers = little_endian ? *(unsigned short*)(pkt + 8): swap_short(pkt + 8); index = *(unsigned char*)(pkt + 6); total = *(unsigned char*)(pkt + 7); if (server->master_pkt == NULL) { server->master_pkt = (char*)malloc(total *n_servers * 6); mpkt = server->master_pkt; } else { mpkt = server->master_pkt + server->n_servers *6; } p = pkt + 10; for (; n_servers && ((char*)mpkt - server->master_pkt) / 6 < server_limit; n_servers--, p += 6, mpkt += 6) { memcpy(mpkt, p, 4); mpkt[4] = p[5]; mpkt[5] = p[4]; } server->master_pkt_len = (char*)mpkt - server->master_pkt; server->n_servers = server->master_pkt_len / 6; server->server_name = MASTER; server->next_player_info = - 1; if (index >= total - 1 || server->n_servers >= server_limit) { return PKT_ERROR; } return DONE_AUTO; } int server_info_packet(struct qserver *server, struct q_packet *pkt, int datalen) { int off = 0; /* ignore duplicate packets */ if (server->server_name != NULL) { return 0; } server->address = strdup((char*) &pkt->data[off]); off += strlen(server->address) + 1; if (off >= datalen) { return -1; } server->server_name = strdup((char*) &pkt->data[off]); off += strlen(server->server_name) + 1; if (off >= datalen) { return -1; } server->map_name = strdup((char*) &pkt->data[off]); off += strlen(server->map_name) + 1; if (off > datalen) { return -1; } server->num_players = pkt->data[off++]; server->max_players = pkt->data[off++]; server->protocol_version = pkt->data[off++]; server->retry1 = n_retries; if (get_server_rules) { debug(3, "send_rule_request_packet3"); send_rule_request_packet(server); } if (get_player_info) { send_player_request_packet(server); } return 0; } int player_info_packet(struct qserver *server, struct q_packet *pkt, int datalen) { char *name, *address; int off, colors, frags, connect_time, player_number; struct player *player, *last; off = 0; player_number = pkt->data[off++]; name = (char*) &pkt->data[off]; off += strlen(name) + 1; if (off >= datalen) { return -1; } colors = pkt->data[off + 3]; colors = (colors << 8) + pkt->data[off + 2]; colors = (colors << 8) + pkt->data[off + 1]; colors = (colors << 8) + pkt->data[off]; off += sizeof(colors); frags = pkt->data[off + 3]; frags = (frags << 8) + pkt->data[off + 2]; frags = (frags << 8) + pkt->data[off + 1]; frags = (frags << 8) + pkt->data[off]; off += sizeof(frags); connect_time = pkt->data[off + 3]; connect_time = (connect_time << 8) + pkt->data[off + 2]; connect_time = (connect_time << 8) + pkt->data[off + 1]; connect_time = (connect_time << 8) + pkt->data[off]; off += sizeof(connect_time); address = (char*) &pkt->data[off]; off += strlen(address) + 1; if (off > datalen) { return -1; } last = server->players; while (last != NULL && last->next != NULL) { if (last->number == player_number) { return 0; } last = last->next; } if (last != NULL && last->number == player_number) { return 0; } player = (struct player*)calloc(1, sizeof(struct player)); player->number = player_number; player->name = strdup(name); player->address = strdup(address); player->connect_time = connect_time; player->frags = frags; player->shirt_color = colors >> 4; player->pants_color = colors &0xf; player->next = NULL; if (last == NULL) { server->players = player; } else { last->next = player; } server->next_player_info++; server->retry2 = n_retries; if (server->next_player_info < server->num_players) { send_player_request_packet(server); } return 0; } int rule_info_packet(struct qserver *server, struct q_packet *pkt, int datalen) { int off = 0; struct rule *rule, *last; char *name, *value; /* Straggler packet after we've already given up fetching rules */ if (server->next_rule == NULL) { return 0; } if (ntohs(pkt->length) == Q_HEADER_LEN) { server->next_rule = NULL; return 0; } name = (char*) &pkt->data[off]; off += strlen(name) + 1; if (off >= datalen) { return -1; } value = (char*) &pkt->data[off]; off += strlen(value) + 1; if (off > datalen) { return -1; } last = server->rules; while (last != NULL && last->next != NULL) { if (strcmp(last->name, name) == 0) { return 0; } last = last->next; } if (last != NULL && strcmp(last->name, name) == 0) { return 0; } rule = (struct rule*)malloc(sizeof(struct rule)); rule->name = strdup(name); rule->value = strdup(value); rule->next = NULL; if (last == NULL) { server->rules = rule; } else { last->next = rule; } server->n_rules++; server->next_rule = rule->name; server->retry1 = n_retries; debug(3, "send_rule_request_packet4"); send_rule_request_packet(server); return 0; } struct info *player_add_info(struct player *player, char *key, char *value, int flags) { struct info *info; if ( flags & OVERWITE_DUPLICATES ) { for (info = player->info; info; info = info->next) { if (0 == strcmp(info->name, key)) { // We should be able to free this free(info->value); if ( flags & NO_VALUE_COPY ) { info->value = value; } else { info->value = strdup(value); } return info; } } } if ( flags & CHECK_DUPLICATE_RULES ) { for (info = player->info; info; info = info->next) { if (0 == strcmp(info->name, key)) { return NULL; } } } if ( flags & COMBINE_VALUES ) { for (info = player->info; info; info = info->next) { if (0 == strcmp(info->name, key)) { char *full_value = (char*)calloc(sizeof(char), strlen(info->value) + strlen(value) + 2); if (NULL == full_value) { fprintf(stderr, "Failed to malloc combined value\n"); exit(1); } sprintf(full_value, "%s%s%s", info->value, multi_delimiter, value); // We should be able to free this free(info->value); info->value = full_value; return info; } } } info = (struct info*)malloc(sizeof(struct info)); if ( flags & NO_KEY_COPY ) { info->name = key; } else { info->name = strdup(key); } if ( flags & NO_VALUE_COPY ) { info->value = value; } else { info->value = strdup(value); } info->next = NULL; if (NULL == player->info) { player->info = info; } else { *player->last_info = info; } player->last_info = &info->next; player->n_info++; return info; } struct rule * add_rule(struct qserver *server, char *key, char *value, int flags) { struct rule *rule; debug(3, "key: %s, value: %s, flags: %d", key, value, flags); if ( flags & OVERWITE_DUPLICATES ) { for (rule = server->rules; rule; rule = rule->next) { if ( 0 == strcmp( rule->name, key) ) { // We should be able to free this free(rule->value); if ( flags & NO_VALUE_COPY ) { rule->value = value; } else { rule->value = strdup(value); } return rule; } } } if ( flags & CHECK_DUPLICATE_RULES ) { for (rule = server->rules; rule; rule = rule->next) { if (0 == strcmp(rule->name, key)) { return NULL; } } } if ( flags & COMBINE_VALUES ) { for (rule = server->rules; rule; rule = rule->next) { if (0 == strcmp(rule->name, key)) { char *full_value = (char*)calloc(sizeof(char), strlen(rule->value) + strlen(value) + strlen(multi_delimiter) + 1); if (NULL == full_value) { fprintf(stderr, "Failed to malloc combined value\n"); exit(1); } sprintf(full_value, "%s%s%s", rule->value, multi_delimiter, value); // We should be able to free this free(rule->value); rule->value = full_value; return rule; } } } rule = (struct rule*)malloc(sizeof(struct rule)); if ( flags & NO_KEY_COPY ) { rule->name = key; } else { rule->name = strdup(key); } if ( flags &NO_VALUE_COPY ) { rule->value = value; } else { rule->value = strdup(value); } rule->next = NULL; *server->last_rule = rule; server->last_rule = &rule->next; server->n_rules++; return rule; } void add_nrule(struct qserver *server, char *key, char *value, int len) { struct rule *rule; for (rule = server->rules; rule; rule = rule->next) if (strcmp(rule->name, key) == 0) { return ; } rule = (struct rule*)malloc(sizeof(struct rule)); rule->name = strdup(key); rule->value = strndup(value, len); rule->next = NULL; *server->last_rule = rule; server->last_rule = &rule->next; server->n_rules++; } struct player *add_player(struct qserver *server, int player_number) { struct player *player; for (player = server->players; player; player = player->next) { if (player->number == player_number) { return NULL; } } player = (struct player*)calloc(1, sizeof(struct player)); player->number = player_number; player->next = server->players; player->n_info = 0; player->ping = NA_INT; player->team = NA_INT; player->score = NA_INT; player->deaths = NA_INT; player->frags = NA_INT; player->last_info = NULL; server->players = player; server->n_player_info++; return player; } STATIC struct player *get_player_by_number(struct qserver *server, int player_number) { struct player *player; for (player = server->players; player; player = player->next) if (player->number == player_number) { return player; } return NULL; } // Updates a servers port information. // Sets the rules: // _queryport // hostport void change_server_port(struct qserver *server, unsigned short port, int force) { if (port > 0 && port != server->port) { // valid port and changing char arg[64]; unsigned int ipaddr = ntohl(server->ipaddr); // Update the servers hostname as required sprintf(arg, "%d.%d.%d.%d:%hu", ipaddr >> 24, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, port); if (show_game_port || force || server->flags &TF_SHOW_GAME_PORT) { // Update the server arg free(server->arg); server->arg = strdup(arg); // Add a rule noting the previous query port sprintf(arg, "%hu", server->port); add_rule(server, "_queryport", arg, NO_FLAGS); // Update the servers port server->port = port; } if ( 0 != strcmp(server->arg, server->host_name) ) { // hostname isnt the query arg char *colon = strchr(server->host_name, ':'); // dns hostname or hostname:port char *hostname = malloc( strlen(server->host_name) + 7 ); if ( NULL == hostname ) { fprintf(stderr, "Failed to malloc hostname memory\n"); } else { if (colon) { *colon = '\0'; } sprintf(hostname, "%s:%hu", server->host_name, port); free(server->host_name); server->host_name = hostname; } } // Add a rule noting the servers hostport sprintf(arg, "%hu", port); add_rule(server, "hostport", arg, OVERWITE_DUPLICATES); } } STATIC void players_set_teamname(struct qserver *server, int teamid, char *teamname) { struct player *player; for (player = server->players; player; player = player->next) { if (player->team == teamid) { player->team_name = strdup(teamname); } } } STATIC char *dup_nstring(const char *pkt, const char *end, char **next) { char *pt = (char*)pkt; int len = ((unsigned char*)pkt)[0]; pt++; if (*pt == '\1') { len++; } if (pt + len > end) { return NULL; } *next = pt + len; return strndup(pt, len); } STATIC char *dup_n1string(char *pkt, char *end, char **next) { unsigned len; if (!pkt || pkt >= end) { return NULL; } len = (unsigned char)pkt[0] - 1; pkt++; if (pkt + len > end) { return NULL; } *next = pkt + len; return strndup(pkt, len); } STATIC int pariah_basic_packet(struct qserver *server, char *rawpkt, char *end) { char *next; char *string; change_server_port(server, swap_short_from_little(&rawpkt[14]), 0); if (NULL == (string = ut2003_strdup(&rawpkt[18], end, &next))) { return -1; } if (server->server_name == NULL) { server->server_name = string; } else { free(string); } if (NULL == (string = ut2003_strdup(next, end, &next))) { return -1; } if (server->map_name == NULL) { server->map_name = string; } else { free(string); } if (NULL == (string = ut2003_strdup(next, end, &next))) { return -1; } if (server->game == NULL) { server->game = string; add_rule(server, "gametype", server->game, NO_FLAGS | CHECK_DUPLICATE_RULES); } else { free(string); } server->num_players = (unsigned char)next[0]; server->max_players = (unsigned char)next[1]; return 0; } STATIC int ut2003_basic_packet(struct qserver *server, char *rawpkt, char *end) { char *next; char *string; change_server_port(server, swap_short_from_little(&rawpkt[6]), 0); if (NULL == (string = ut2003_strdup(&rawpkt[14], end, &next))) { return -1; } if (server->server_name == NULL) { server->server_name = string; } else { free(string); } if (NULL == (string = ut2003_strdup(next, end, &next))) { return -1; } if (server->map_name == NULL) { server->map_name = string; } else { free(string); } if (NULL == (string = ut2003_strdup(next, end, &next))) { return -1; } if (server->game == NULL) { server->game = string; add_rule(server, "gametype", server->game, NO_FLAGS | CHECK_DUPLICATE_RULES); } else { free(string); } server->num_players = swap_long_from_little(next); next += 4; server->max_players = swap_long_from_little(next); return 0; } STATIC int pariah_rule_packet(struct qserver *server, char *rawpkt, char *end) { char *key, *value; unsigned char no_rules = (unsigned char)rawpkt[1]; unsigned char seen = 0; // type + no_rules rawpkt += 2; // we get size encoded key = value pairs while (rawpkt < end && no_rules > seen) { // first byte is the rule count seen = (unsigned char)rawpkt[0]; rawpkt++; if (NULL == (key = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } if ('\0' == rawpkt[0]) { value = strdup(""); rawpkt++; } else if (NULL == (value = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } if (NULL == add_rule(server, key, value, NO_KEY_COPY | NO_VALUE_COPY | COMBINE_VALUES)) { /* duplicate, so free key and value */ free(value); free(key); } seen++; } if (no_rules == seen) { // all done server->next_rule = NULL; return 1; } return 0; } STATIC int ut2003_rule_packet(struct qserver *server, char *rawpkt, char *end) { char *key, *value; int result = 0; // Packet Type rawpkt++; // we get size encoded key = value pairs while (rawpkt < end) { if (NULL == (key = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } if (NULL == (value = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } if (strcmp(key, "minplayers") == 0) { result = atoi(value); } if (NULL == add_rule(server, key, value, NO_KEY_COPY | NO_VALUE_COPY | COMBINE_VALUES)) { /* duplicate, so free key and value */ free(value); free(key); } } return result; } char *ut2003_strdup(const char *string, const char *end, char **next) { unsigned char len = string[0]; char *result = NULL; if (len < 128) { // type 1 string //fprintf( stderr, "Type 1:" ); result = dup_nstring(string, end, next); } else { // type 2 string //fprintf( stderr, "Type 2:\n" ); const char *last; char *resp, *pos; // minus indicator len -= 128; // double byte chars so * 2 len = len * 2; last = string + len; if (last > end) { *next = (char*)end; fprintf(stderr, "Type 2 string format error ( too short )\n"); return NULL; } *next = (char*)last + 1; if (NULL == (result = (char*)calloc(last - string, sizeof(char)))) { fprintf(stderr, "Failed to malloc string memory\n"); return NULL; } resp = result; pos = (char*)string + 1; while (pos <= last) { // check for a color code if (pos + 6 <= last && 0 == memcmp(pos, "^\0#\0", 4)) { // we have a color code //fprintf( stderr, "color:%02hhx%02hhx\n", pos[4], pos[5] ); // indicator transformed to ^\1 *resp = *pos; resp++; pos++; *resp = '\1'; resp++; pos += 3; // color byte *resp = *pos; resp++; pos += 2; //pos += 6; } // standard char //fprintf( stderr, "char: %02hhx\n", *pos ); *resp = *pos; resp++; pos += 2; } } //fprintf( stderr, "'%s'\n", result ); return result; } STATIC int pariah_player_packet(struct qserver *server, char *rawpkt, char *end) { unsigned char no_players = rawpkt[1]; unsigned char seen = 0; /* XXX: cannot work this way, it takes only this packet into consideration. What if player info is spread across multiple packets? */ // type + no_players + some unknown preamble rawpkt += 3; while (rawpkt < end && seen < no_players) { struct player *player; // Player Number rawpkt += 4; // Create a player if (NULL == (player = add_player(server, server->n_player_info))) { return 0; } // Name ( min 3 bytes ) player->name = ut2003_strdup(rawpkt, end, &rawpkt); // Ping player->ping = swap_long_from_little(rawpkt); rawpkt += 4; // Frags player->frags = (unsigned char)rawpkt[0]; rawpkt++; // unknown rawpkt++; seen++; } if (no_players == seen) { // all done server->num_players = server->n_player_info; return 1; } // possibly more to come return 0; } STATIC int ut2003_player_packet(struct qserver *server, char *rawpkt, char *end) { // skip type rawpkt++; switch (server->protocol_version) { case 0x7e: // XMP packet //fprintf( stderr, "XMP packet\n" ); while (rawpkt < end) { struct player *player; char *var, *val; unsigned char no_props; if (rawpkt + 24 > end) { malformed_packet(server, "player info too short"); rawpkt = end; return 1; } // Player Number never set rawpkt += 4; // Player ID never set rawpkt += 4; if (NULL == (player = add_player(server, server->n_player_info))) { return 0; } // Name ( min 3 bytes ) player->name = ut2003_strdup(rawpkt, end, &rawpkt); // Ping player->ping = swap_long_from_little(rawpkt); rawpkt += 4; // Frags player->frags = swap_long_from_little(rawpkt); rawpkt += 4; // Stat ID never set rawpkt += 4; // Player properties no_props = rawpkt[0]; //fprintf( stderr, "noprops %d\n", no_props ); rawpkt++; while (rawpkt < end && no_props > 0) { if (NULL == (var = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } if (NULL == (val = ut2003_strdup(rawpkt, end, &rawpkt))) { break; } //fprintf( stderr, "attrib: %s = %s\n", var, val ); // Things we can use if (0 == strcmp(var, "team")) { player->team_name = val; } else if (0 == strcmp(var, "class")) { player->skin = val; } else { free(val); } free(var); no_props--; } } break; default: while (rawpkt < end) { struct player *player; if (rawpkt + 4 > end) { malformed_packet(server, "player packet too short"); return 1; } if (NULL == (player = add_player(server, swap_long_from_little(rawpkt)))) { return 0; } player->name = ut2003_strdup(rawpkt + 4, end, &rawpkt); if (rawpkt + 8 > end) { malformed_packet(server, "player packet too short"); return 1; } player->ping = swap_long_from_little(rawpkt); rawpkt += 4; player->frags = swap_long_from_little(rawpkt); rawpkt += 4; { unsigned team = swap_long_from_little(rawpkt); rawpkt += 4; player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; if (team &1 << 29) { player->team_name = "red"; } else if (team &1 << 30) { player->team_name = "blue"; } } } } return 0; } char *get_rule(struct qserver *server, char *name) { struct rule *rule; rule = server->rules; for (; rule != NULL; rule = rule->next) { if (strcmp(name, rule->name) == 0) { return rule->value; } } return NULL; } query_status_t deal_with_ut2003_packet(struct qserver *server, char *rawpkt, int pktlen) { // For protocol spec see: // http://unreal.student.utwente.nl/UT2003-queryspec.html char *end; int error = 0, before; unsigned int packet_header; debug( 2, "deal_with_ut2003_packet %p, %d", server, pktlen ); rawpkt[pktlen] = '\0'; end = &rawpkt[pktlen]; packet_header = swap_long_from_little(&rawpkt[0]); rawpkt += 4; server->protocol_version = packet_header; if ( packet_header != 0x77 // Pariah Demo? && packet_header != 0x78 // UT2003 Demo && packet_header != 0x79 // UT2003 Retail && packet_header != 0x7e // Unreal2 XMP && packet_header != 0x7f // UT2004 Demo && packet_header != 0x80 // UT2004 Retail ) { malformed_packet(server, "Unknown type 0x%x", packet_header); } switch (rawpkt[0]) { case 0x00: // Server info if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } error = ut2003_basic_packet(server, rawpkt, end); if (!error) { if (get_server_rules || get_player_info) { int requests = server->n_requests; server->next_rule = ""; server->retry1 = n_retries; server->retry2 = 0; // don't wait for player packet debug(3, "send_rule_request_packet5"); send_rule_request_packet(server); server->n_requests = requests; // would produce wrong ping } } break; case 0x01: // Game info ut2003_rule_packet(server, rawpkt, end); server->next_rule = ""; server->retry1 = 0; /* we received at least one rule packet so no need to retry. We'd get double entries otherwise. */ break; case 0x02: // Player info before = server->n_player_info; error = ut2003_player_packet(server, rawpkt, end); if (before == server->n_player_info) { error = 1; } break; case 0x10: // Pariah Server info if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } error = pariah_basic_packet(server, rawpkt, end); if (!error) { // N.B. pariah always sends a rules and players packet int requests = server->n_requests; server->next_rule = ""; server->retry1 = n_retries; server->retry2 = 0; server->n_requests = requests; // would produce wrong ping } break; case 0x11: // Game info pariah_rule_packet(server, rawpkt, end); server->retry1 = 0; /* we received at least one rule packet so no need to retry. We'd get double entries otherwise. */ break; case 0x12: // Player info before = server->n_player_info; pariah_player_packet(server, rawpkt, end); if (before == server->n_player_info) { error = 1; } break; default: malformed_packet(server, "Unknown packet type 0x%x", (unsigned)rawpkt[0]); break; } /* don't cleanup if we fetch server rules. We would lose * rule packets as we don't know how many we get * We do clean up if we don't fetch server rules so we don't * need to wait for timeout. */ if ( error || (!get_server_rules && !get_player_info) || (!get_server_rules && server->num_players == server->n_player_info) || (server->next_rule == NULL && server->num_players == server->n_player_info) ) { return DONE_FORCE; } return INPROGRESS; } int deal_with_unrealmaster_packet(struct qserver *server, char *rawpkt, int pktlen) { debug( 2, "deal_with_unrealmaster_packet %p, %d", server, pktlen ); if (pktlen == 0) { return PKT_ERROR; } print_packet(server, rawpkt, pktlen); puts("--"); return 0; } /* Returns 1 if the query is done (server may be freed) and 0 if not. */ query_status_t deal_with_halflife_packet(struct qserver *server, char *rawpkt, int pktlen) { char *pkt; char *end = &rawpkt[pktlen]; int pkt_index = 0, pkt_max = 0; char number[16]; short pkt_id; debug( 2, "deal_with_halflife_packet %p, %d", server, pktlen ); if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } if (pktlen < 5) { return PKT_ERROR; } if (((rawpkt[0] != '\377' && rawpkt[0] != '\376') || rawpkt[1] != '\377' || rawpkt[2] != '\377' || rawpkt[3] != '\377') && show_errors) { unsigned int ipaddr = ntohl(server->ipaddr); fprintf(stderr, "Odd packet from server %d.%d.%d.%d:%hu, processing ...\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, ntohs(server->port) ); print_packet(server, rawpkt, pktlen); } if (((unsigned char*)rawpkt)[0] == 0xfe) { SavedData *sdata; pkt_index = ((unsigned char*)rawpkt)[8] >> 4; pkt_max = ((unsigned char*)rawpkt)[8] &0xf; memcpy(&pkt_id, &rawpkt[4], 2); 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 - 9; sdata->data = (char*)malloc(pktlen - 9); memcpy(sdata->data, &rawpkt[9], pktlen - 9); /* combine_packets will call us recursively */ return combine_packets(server); /* fprintf( OF, "pkt_index %d pkt_max %d\n", pkt_index, pkt_max); rawpkt+= 9; pktlen-= 9; */ } /* 'info' response */ if (rawpkt[4] == 'C' || rawpkt[4] == 'm') { if (server->server_name != NULL) { return 0; } pkt = &rawpkt[5]; server->address = strdup(pkt); pkt += strlen(pkt) + 1; server->server_name = strdup(pkt); pkt += strlen(pkt) + 1; server->map_name = strdup(pkt); pkt += strlen(pkt) + 1; if (*pkt) { add_rule(server, "gamedir", pkt, NO_FLAGS); } if (*pkt && strcmp(pkt, "valve") != 0) { server->game = add_rule(server, "game", pkt, NO_FLAGS)->value; server->flags |= FLAG_DO_NOT_FREE_GAME; } pkt += strlen(pkt) + 1; if (*pkt) { add_rule(server, "gamename", pkt, NO_FLAGS); } pkt += strlen(pkt) + 1; server->num_players = (unsigned int)pkt[0]; server->max_players = (unsigned int)pkt[1]; pkt += 2; if (pkt < end) { int protocol = *((unsigned char*)pkt); sprintf(number, "%d", protocol); add_rule(server, "protocol", number, NO_FLAGS); pkt++; } if (rawpkt[4] == 'm') { if (*pkt == 'd') { add_rule(server, "sv_type", "dedicated", NO_FLAGS); } else if (*pkt == 'l') { add_rule(server, "sv_type", "listen", NO_FLAGS); } else { add_rule(server, "sv_type", "?", NO_FLAGS); } pkt++; if (*pkt == 'w') { add_rule(server, "sv_os", "windows", NO_FLAGS); } else if (*pkt == 'l') { add_rule(server, "sv_os", "linux", NO_FLAGS); } else { char str[2] = "\0"; str[0] = *pkt; add_rule(server, "sv_os", str, NO_FLAGS); } pkt++; add_rule(server, "sv_password", *pkt ? "1" : "0", NO_FLAGS); pkt++; add_rule(server, "mod", *pkt ? "1" : "0", NO_FLAGS); if (*pkt) { int n; /* pull out the mod infomation */ pkt++; add_rule(server, "mod_info_url", pkt, NO_FLAGS); pkt += strlen(pkt) + 1; if (*pkt) { add_rule(server, "mod_download_url", pkt, NO_FLAGS); } pkt += strlen(pkt) + 1; if (*pkt) { add_rule(server, "mod_detail", pkt, NO_FLAGS); } pkt += strlen(pkt) + 1; n = swap_long_from_little(pkt); sprintf(number, "%d", n); add_rule(server, "modversion", number, NO_FLAGS); pkt += 4; n = swap_long_from_little(pkt); sprintf(number, "%d", n); add_rule(server, "modsize", number, NO_FLAGS); pkt += 4; add_rule(server, "svonly", *pkt ? "1" : "0", NO_FLAGS); pkt++; add_rule(server, "cldll", *pkt ? "1" : "0", NO_FLAGS); pkt++; if (pkt < end) { add_rule(server, "secure", *pkt ? "1" : "0", NO_FLAGS); } } } if (get_player_info && server->num_players) { int requests = server->n_requests; server->next_player_info = server->num_players - 1; send_player_request_packet(server); server->n_requests = requests; // prevent wrong ping } if (get_server_rules) { int requests = server->n_requests; server->next_rule = ""; server->retry1 = n_retries; debug(3, "send_rule_request_packet6"); send_rule_request_packet(server); server->n_requests = requests; // prevent wrong ping } } /* 'players' response */ else if (rawpkt[4] == 'D' && server->players == NULL) { unsigned int n = 0, temp; struct player *player; struct player **last_player = &server->players; if ((unsigned int)rawpkt[5] > server->num_players) { server->num_players = (unsigned int)rawpkt[5]; } pkt = &rawpkt[6]; rawpkt[pktlen] = '\0'; while (1) { if (*pkt != n + 1) { break; } n++; pkt++; player = (struct player*)calloc(1, sizeof(struct player)); player->name = strdup(pkt); pkt += strlen(pkt) + 1; memcpy(&player->frags, pkt, 4); pkt += 4; memcpy(&temp, pkt, 4); pkt += 4; if (big_endian) { player->frags = swap_long(&player->frags); } player->connect_time = swap_float_from_little(&temp); *last_player = player; last_player = &player->next; } if (n > server->num_players) { server->num_players = n; } server->next_player_info = server->num_players; } /* 'rules' response */ else if (rawpkt[4] == 'E' && server->next_rule != NULL) { int n = 0; n = ((unsigned char*)rawpkt)[5] + ((unsigned char*)rawpkt)[6] *256; pkt = &rawpkt[7]; while (n) { char *key = pkt; char *value; pkt += strlen(pkt) + 1; if (pkt > end) { break; } value = pkt; pkt += strlen(pkt) + 1; if (pkt > end) { break; } if (key[0] == 's' && strcmp(key, "sv_password") == 0) { add_rule(server, key, value, CHECK_DUPLICATE_RULES); } else { add_rule(server, key, value, NO_FLAGS); } n--; } server->next_rule = NULL; } else if (rawpkt[4] != 'E' && rawpkt[4] != 'D' && rawpkt[4] != 'm' && rawpkt[4] != 'C' && show_errors) { /* if ( pkt_count) { rawpkt-= 9; pktlen+= 9; } */ fprintf(stderr, "Odd packet from HL server %s (packet len %d)\n", server->arg, pktlen); print_packet(server, rawpkt, pktlen); } return DONE_AUTO; } 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; } void get_tribes2_player_type(struct player *player) { char *name = player->name; for (; *name; name++) { switch (*name) { case 0x8: player->type_flag = PLAYER_TYPE_NORMAL; continue; case 0xc: player->type_flag = PLAYER_TYPE_ALIAS; continue; case 0xe: player->type_flag = PLAYER_TYPE_BOT; continue; case 0xb: break; default: continue; } name++; if (isprint(*name)) { char *n = name; for (; isprint(*n); n++) ; player->tribe_tag = strndup(name, n - name); name = n; } if (! *name) { break; } } } query_status_t deal_with_tribes2_packet(struct qserver *server, char *pkt, int pktlen) { char str[256], *pktstart = pkt, *term, *start; unsigned int minimum_net_protocol, build_version, i, t, len, s, status; unsigned int net_protocol; unsigned short cpu_speed; int n_teams = 0, n_players; struct player **teams = NULL, *player; struct player **last_player = &server->players; int query_version; debug( 2, "deal_with_tribes2_packet %p, %d", server, pktlen ); pkt[pktlen] = '\0'; if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } /* else gettimeofday( &server->packet_time1, NULL); */ if (pkt[0] == TRIBES2_RESPONSE_PING) { if (pkt[6] < 4 || pkt[6] > 12 || strncmp(pkt + 7, "VER", 3) != 0) { return PKT_ERROR; } strncpy(str, pkt + 10, pkt[6] - 3); str[pkt[6] - 3] = '\0'; query_version = atoi(str); add_nrule(server, "queryversion", pkt + 7, pkt[6]); pkt += 7+pkt[6]; server->protocol_version = query_version; if (query_version != 3 && query_version != 5) { server->server_name = strdup("Unknown query version"); return PKT_ERROR; } if (query_version == 5) { net_protocol = swap_long_from_little(pkt); sprintf(str, "%u", net_protocol); add_rule(server, "net_protocol", str, NO_FLAGS); pkt += 4; } minimum_net_protocol = swap_long_from_little(pkt); sprintf(str, "%u", minimum_net_protocol); add_rule(server, "minimum_net_protocol", str, NO_FLAGS); pkt += 4; build_version = swap_long_from_little(pkt); sprintf(str, "%u", build_version); add_rule(server, "build_version", str, NO_FLAGS); pkt += 4; server->server_name = strndup(pkt + 1, *(unsigned char*)(pkt)); /* Always send the player request because the ping packet * contains very little information */ send_player_request_packet(server); return 0; } else if (pkt[0] != TRIBES2_RESPONSE_INFO) { return PKT_ERROR; } pkt += 6; for (i = 0; i < *(unsigned char*)pkt; i++) if (!isprint(pkt[i + 1])) { return PKT_ERROR; } add_nrule(server, server->type->game_rule, pkt + 1, *(unsigned char*)pkt); server->game = strndup(pkt + 1, *(unsigned char*)pkt); pkt += *pkt + 1; add_nrule(server, "mission", pkt + 1, *(unsigned char*)pkt); pkt += *pkt + 1; server->map_name = strndup(pkt + 1, *(unsigned char*)pkt); pkt += *pkt + 1; status = *(unsigned char*)pkt; sprintf(str, "%u", status); add_rule(server, "status", str, NO_FLAGS); if (status &TRIBES2_STATUS_DEDICATED) { add_rule(server, "dedicated", "1", NO_FLAGS); } if (status &TRIBES2_STATUS_PASSWORD) { add_rule(server, "password", "1", NO_FLAGS); } if (status &TRIBES2_STATUS_LINUX) { add_rule(server, "linux", "1", NO_FLAGS); } if (status &TRIBES2_STATUS_TEAMDAMAGE) { add_rule(server, "teamdamage", "1", NO_FLAGS); } if (server->protocol_version == 3) { if (status &TRIBES2_STATUS_TOURNAMENT_VER3) { add_rule(server, "tournament", "1", NO_FLAGS); } if (status &TRIBES2_STATUS_NOALIAS_VER3) { add_rule(server, "no_aliases", "1", NO_FLAGS); } } else { if (status &TRIBES2_STATUS_TOURNAMENT) { add_rule(server, "tournament", "1", NO_FLAGS); } if (status &TRIBES2_STATUS_NOALIAS) { add_rule(server, "no_aliases", "1", NO_FLAGS); } } pkt++; server->num_players = *(unsigned char*)pkt; pkt++; server->max_players = *(unsigned char*)pkt; pkt++; sprintf(str, "%u", *(unsigned char*)pkt); add_rule(server, "bot_count", str, NO_FLAGS); pkt++; cpu_speed = swap_short_from_little(pkt); sprintf(str, "%hu", cpu_speed); add_rule(server, "cpu_speed", str, NO_FLAGS); pkt += 2; if (strcmp(server->server_name, "VER3") == 0) { free(server->server_name); server->server_name = strndup(pkt + 1, *(unsigned char*)pkt); } else { add_nrule(server, "info", pkt + 1, *(unsigned char*)pkt); } pkt += *(unsigned char*)pkt + 1; len = swap_short_from_little(pkt); pkt += 2; start = pkt; if (len + (pkt - pktstart) > pktlen) { len -= (len + (pkt - pktstart)) - pktlen; } if (len == 0 || pkt - pktstart >= pktlen) { goto info_done; } term = strchr(pkt, 0xa); if (!term) { goto info_done; } *term = '\0'; n_teams = atoi(pkt); sprintf(str, "%d", n_teams); add_rule(server, "numteams", str, NO_FLAGS); pkt = term + 1; if (pkt - pktstart >= pktlen) { goto info_done; } 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; /* team name */ term = strchr(pkt, 0x9); if (!term) { n_teams = t; goto info_done; } teams[t]->name = strndup(pkt, term - pkt); pkt = term + 1; term = strchr(pkt, 0xa); if (!term) { n_teams = t; goto info_done; } *term = '\0'; teams[t]->frags = atoi(pkt); pkt = term + 1; if (pkt - pktstart >= pktlen) { goto info_done; } } term = strchr(pkt, 0xa); if (!term || term - start >= len) { goto info_done; } *term = '\0'; n_players = atoi(pkt); pkt = term + 1; for (i = 0; i < n_players && pkt - start < len; i++) { pkt++; /* skip first byte (0x10) */ if (pkt - start >= len) { break; } player = (struct player*)calloc(1, sizeof(struct player)); term = strchr(pkt, 0x11); if (!term || term - start >= len) { free(player); break; } player->name = strndup(pkt, term - pkt); get_tribes2_player_type(player); pkt = term + 1; pkt++; /* skip 0x9 */ if (pkt - start >= len) { break; } term = strchr(pkt, 0x9); if (!term || term - start >= len) { free(player->name); free(player); break; } for (t = 0; t < n_teams; t++) { if (term - pkt == strlen(teams[t]->name) && strncmp(pkt, teams[t]->name, term - pkt) == 0) { break; } } if (t == n_teams) { player->team = - 1; player->team_name = "Unassigned"; } else { player->team = t; player->team_name = teams[t]->name; } player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; pkt = term + 1; for (s = 0; *pkt != 0xa && pkt - start < len; pkt++) { str[s++] = *pkt; } str[s] = '\0'; player->frags = atoi(str); if (*pkt == 0xa) { pkt++; } *last_player = player; last_player = &player->next; } info_done: for (t = n_teams; t;) { t--; teams[t]->next = server->players; server->players = teams[t]; } if (teams) { free(teams); } return DONE_FORCE; } static const char GrPacketHead[] = { '\xc0', '\xde', '\xf1', '\x11' }; static const char PacketStart = '\x42'; static char Dat2Reply1_2_10[] = { '\xf4', '\x03', '\x14', '\x02', '\x0a', '\x41', '\x02', '\x0a', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63' }; static char Dat2Reply1_3[] = { '\xf4', '\x03', '\x14', '\x03', '\x05', '\x41', '\x03', '\x05', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63' }; static char Dat2Reply1_4[] = { '\xf4', '\x03', '\x14', '\x04', '\x00', '\x41', '\x04', '\x00', '\x41', '\x00', '\x00', '\x78', '\x30', '\x63' }; //static char HDat2[]={'\xea','\x03','\x02','\x00','\x14'}; #define SHORT_GR_LEN 75 #define LONG_GR_LEN 500 #define UNKNOWN_VERSION 0 #define VERSION_1_2_10 1 #define VERSION_1_3 2 #define VERSION_1_4 3 query_status_t deal_with_ghostrecon_packet(struct qserver *server, char *pkt, int pktlen) { char str[256], *start, *end, StartFlag, *lpszIgnoreServerPlayer; char *lpszMission; unsigned int iIgnoreServerPlayer, iDedicatedServer, iUseStartTimer; unsigned short GrPayloadLen; int i; struct player *player; int iLen, iTemp; short sLen; int iSecsPlayed; long iSpawnType; int ServerVersion = UNKNOWN_VERSION; float flStartTimerSetPoint; debug( 2, "deal_with_ghostrecon_packet %p, %d", server, pktlen ); start = pkt; end = &pkt[pktlen]; pkt[pktlen] = '\0'; /* This function walks a packet that is recieved from a ghost recon server - default from port 2348. It does quite a few sanity checks along the way as the structure is not documented. The packet is mostly binary in nature with many string fields being variable in length, ie the length is listed foloowed by that many bytes. There are two structure arrays that have an array size followed by structure size * number of elements (player name and player data). This routine walks this packet and increments a pointer "pkt" to extract the info. */ if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } /* sanity check against packet */ if (memcmp(pkt, GrPacketHead, sizeof(GrPacketHead)) != 0) { server->server_name = strdup("Unknown Packet Header"); return PKT_ERROR; } pkt += sizeof(GrPacketHead); StartFlag = pkt[0]; pkt += 1; if (StartFlag != 0x42) { server->server_name = strdup("Unknown Start Flag"); return PKT_ERROR; } /* compare packet length recieved to included size - header info */ sLen = swap_short_from_little(pkt); pkt += 2; GrPayloadLen = pktlen - sizeof(GrPacketHead) - 3; // 3 = size slen + size start flag if (sLen != GrPayloadLen) { server->server_name = strdup("Packet Size Mismatch"); return PKT_ERROR; } /* Will likely need to verify and add to this "if" construct with every patch / add-on. */ if (memcmp(pkt, Dat2Reply1_2_10, sizeof(Dat2Reply1_2_10)) == 0) { ServerVersion = VERSION_1_2_10; } else if (memcmp(pkt, Dat2Reply1_3, sizeof(Dat2Reply1_3)) == 0) { ServerVersion = VERSION_1_3; } else if (memcmp(pkt, Dat2Reply1_4, sizeof(Dat2Reply1_4)) == 0) { ServerVersion = VERSION_1_4; } if (ServerVersion == UNKNOWN_VERSION) { server->server_name = strdup("Unknown GR Version"); return PKT_ERROR; } switch (ServerVersion) { case VERSION_1_2_10: strcpy(str, "1.2.10"); pkt += sizeof(Dat2Reply1_2_10); break; case VERSION_1_3: strcpy(str, "1.3"); pkt += sizeof(Dat2Reply1_3); break; case VERSION_1_4: strcpy(str, "1.4"); pkt += sizeof(Dat2Reply1_4); break; } add_rule(server, "patch", str, NO_FLAGS); /* have player packet */ // Ghost recon has one of the player slots filled up with the server program itself. By default we will // drop the first player listed. This causes a bit of a mess here and below but makes for the best display // a user can specify -grs,ignoreserverplayer=no to override this behaviour. lpszIgnoreServerPlayer = get_param_value(server, "ignoreserverplayer", "yes"); for (i = 0; i < 4; i++) { str[i] = tolower(lpszIgnoreServerPlayer[i]); } if (strcmp(str, "yes") == 0) { iIgnoreServerPlayer = 1; } else { iIgnoreServerPlayer = 0; } pkt += 4; /* unknown */ // this is the first of many variable strings. get the length, // increment pointer over length, check for sanity, // get the string, increment the pointer over string (using length) iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { server->server_name = strdup("Server Name too Long"); return PKT_ERROR; } server->server_name = strndup(pkt, iLen); pkt += iLen; iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Map Name too Long", NO_FLAGS); return PKT_ERROR; } server->map_name = strndup(pkt, iLen); pkt += iLen; iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Mission Name too Long", NO_FLAGS); return PKT_ERROR; } /* mission does not make sense unless a coop game type. Since we dont know that now, we will save the mission and set the rule and free memory below when we know game type */ lpszMission = strndup(pkt, iLen); pkt += iLen; iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Mission Type too Long", NO_FLAGS); return PKT_ERROR; } add_nrule(server, "missiontype", pkt, iLen); pkt += iLen; if (pkt[1]) { add_rule(server, "password", "Yes", NO_FLAGS); } else { add_rule(server, "password", "No", NO_FLAGS); } pkt += 2; server->max_players = swap_long_from_little(pkt); pkt += 4; if (server->max_players > 36) { add_rule(server, "error", "Max players more then 36", NO_FLAGS); return PKT_ERROR; } server->num_players = swap_long_from_little(pkt); pkt += 4; if (server->num_players > server->max_players) { add_rule(server, "error", "More then MAX Players", NO_FLAGS); return PKT_ERROR; } if (iIgnoreServerPlayer) // skip past first player { server->num_players--; server->max_players--; iLen = swap_long_from_little(pkt); pkt += 4; pkt += iLen; } for (i = 0; i < server->num_players; i++) // read each player name { iLen = swap_long_from_little(pkt); pkt += 4; player = (struct player*)calloc(1, sizeof(struct player)); if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Player Name too Long", NO_FLAGS); return PKT_ERROR; } player->name = strndup(pkt, iLen); pkt += iLen; /* player name */ player->team = i; // tag so we can find this record when we have player dat. player->team_name = "Unassigned"; player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->frags = 0; player->next = server->players; server->players = player; } pkt += 17; iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Version too Long", NO_FLAGS); return PKT_ERROR; } strncpy(str, pkt, iLen); add_rule(server, "version", str, NO_FLAGS); pkt += iLen; /* version */ iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > LONG_GR_LEN)) { add_rule(server, "error", "Mods too Long", NO_FLAGS); return PKT_ERROR; } server->game = strndup(pkt, iLen); for (i = 0; i < (int)strlen(server->game) - 5; i++) // clean the "/mods/" part from every entry { if (memcmp(&server->game[i], "\\mods\\", 6) == 0) { server->game[i] = ' '; strcpy(&server->game[i + 1], &server->game[i + 6]); } } add_rule(server, "game", server->game, NO_FLAGS); pkt += iLen; /* mods */ iDedicatedServer = pkt[0]; if (iDedicatedServer) { add_rule(server, "dedicated", "Yes", NO_FLAGS); } else { add_rule(server, "dedicated", "No", NO_FLAGS); } pkt += 1; /* unknown */ iSecsPlayed = swap_float_from_little(pkt); add_rule(server, "timeplayed", play_time(iSecsPlayed, 2), NO_FLAGS); pkt += 4; /* time played */ switch (pkt[0]) { case 3: strcpy(str, "Joining"); break; case 4: strcpy(str, "Playing"); break; case 5: strcpy(str, "Debrief"); break; default: strcpy(str, "Undefined"); } add_rule(server, "status", str, NO_FLAGS); pkt += 1; pkt += 3; /* unknown */ switch (pkt[0]) { case 2: strcpy(str, "COOP"); break; case 3: strcpy(str, "SOLO"); break; case 4: strcpy(str, "TEAM"); break; default: sprintf(str, "UNKOWN %u", pkt[0]); break; } add_rule(server, "gamemode", str, NO_FLAGS); if (pkt[0] == 2) { add_rule(server, "mission", lpszMission, NO_FLAGS); } else { add_rule(server, "mission", "No Mission", NO_FLAGS); } free(lpszMission); pkt += 1; /* Game Mode */ pkt += 3; /* unknown */ iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > LONG_GR_LEN)) { add_rule(server, "error", "MOTD too Long", NO_FLAGS); return PKT_ERROR; } strncpy(str, pkt, sizeof(str)); str[sizeof(str) - 1] = 0; add_rule(server, "motd", str, NO_FLAGS); pkt += iLen; /* MOTD */ iSpawnType = swap_long_from_little(pkt); switch (iSpawnType) { case 0: strcpy(str, "None"); break; case 1: strcpy(str, "Individual"); break; case 2: strcpy(str, "Team"); break; case 3: strcpy(str, "Infinite"); break; default: strcpy(str, "Unknown"); } add_rule(server, "spawntype", str, NO_FLAGS); pkt += 4; /* spawn type */ iTemp = swap_float_from_little(pkt); add_rule(server, "gametime", play_time(iTemp, 2), NO_FLAGS); iTemp = iTemp - iSecsPlayed; if (iTemp <= 0) { iTemp = 0; } add_rule(server, "remainingtime", play_time(iTemp, 2), NO_FLAGS); pkt += 4; /* Game time */ iTemp = swap_long_from_little(pkt); if (iIgnoreServerPlayer) { iTemp--; } if (iTemp != server->num_players) { add_rule(server, "error", "Number of Players Mismatch", NO_FLAGS); } pkt += 4; /* player count 2 */ if (iIgnoreServerPlayer) { pkt += 5; // skip first player data } for (i = 0; i < server->num_players; i++) // for each player get binary data { player = server->players; // first we must find the player - lets look for the tag while (player && (player->team != i)) { player = player->next; } /* get to player - linked list is in reverse order */ if (player) { player->team = pkt[2]; switch (player->team) { case 1: player->team_name = "Red"; break; case 2: player->team_name = "Blue"; break; case 3: player->team_name = "Yellow"; break; case 4: player->team_name = "Green"; break; case 5: player->team_name = "Unassigned"; break; default: player->team_name = "Not Known"; break; } player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->deaths = pkt[1]; } pkt += 5; /* player data*/ } for (i = 0; i < 5; i++) { pkt += 8; /* team data who knows what they have in here */ } pkt += 1; iUseStartTimer = pkt[0]; // UseStartTimer pkt += 1; iTemp = flStartTimerSetPoint = swap_float_from_little(pkt); // Start Timer Set Point pkt += 4; if (iUseStartTimer) { add_rule(server, "usestarttime", "Yes", NO_FLAGS); add_rule(server, "starttimeset", play_time(iTemp, 2), NO_FLAGS); } else { add_rule(server, "usestarttime", "No", NO_FLAGS); add_rule(server, "starttimeset", play_time(0, 2), NO_FLAGS); } if ((ServerVersion == VERSION_1_3) || // stuff added in patch 1.3 (ServerVersion == VERSION_1_4)) { iTemp = swap_float_from_little(pkt); // Debrief Time add_rule(server, "debrieftime", play_time(iTemp, 2), NO_FLAGS); pkt += 4; iTemp = swap_float_from_little(pkt); // Respawn Min add_rule(server, "respawnmin", play_time(iTemp, 2), NO_FLAGS); pkt += 4; iTemp = swap_float_from_little(pkt); // Respawn Max add_rule(server, "respawnmax", play_time(iTemp, 2), NO_FLAGS); pkt += 4; iTemp = swap_float_from_little(pkt); // Respawn Invulnerable add_rule(server, "respawnsafe", play_time(iTemp, 2), NO_FLAGS); pkt += 4; } else { add_rule(server, "debrieftime", "Undefined", NO_FLAGS); add_rule(server, "respawnmin", "Undefined", NO_FLAGS); add_rule(server, "respawnmax", "Undefined", NO_FLAGS); add_rule(server, "respawnsafe", "Undefined", NO_FLAGS); } pkt += 4; // 4 iTemp = pkt[0]; // Spawn Count if ((iSpawnType == 1) || (iSpawnType == 2)) /* Individual or team */ { sprintf(str, "%u", iTemp); } else /* else not used */ { sprintf(str, "%u", 0); } add_rule(server, "spawncount", str, NO_FLAGS); pkt += 1; // 5 pkt += 4; // 9 iTemp = pkt[0]; // Allow Observers if (iTemp) { strcpy(str, "Yes"); } else /* else not used */ { strcpy(str, "No"); } add_rule(server, "allowobservers", str, NO_FLAGS); pkt += 1; // 10 pkt += 3; // 13 // pkt += 13; if (iUseStartTimer) { iTemp = swap_float_from_little(pkt); // Start Timer Count add_rule(server, "startwait", play_time(iTemp, 2), NO_FLAGS); } else { add_rule(server, "startwait", play_time(0, 2), NO_FLAGS); } pkt += 4; //17 iTemp = pkt[0]; // IFF switch (iTemp) { case 0: strcpy(str, "None"); break; case 1: strcpy(str, "Reticule"); break; case 2: strcpy(str, "Names"); break; default: strcpy(str, "Unknown"); break; } add_rule(server, "iff", str, NO_FLAGS); pkt += 1; // 18 iTemp = pkt[0]; // Threat Indicator if (iTemp) { add_rule(server, "ti", "ON ", NO_FLAGS); } else { add_rule(server, "ti", "OFF", NO_FLAGS); } pkt += 1; // 19 pkt += 5; // 24 iLen = swap_long_from_little(pkt); pkt += 4; if ((iLen < 1) || (iLen > SHORT_GR_LEN)) { add_rule(server, "error", "Restrictions too Long", NO_FLAGS); return PKT_ERROR; } add_rule(server, "restrict", pkt, NO_FLAGS); pkt += iLen; /* restrictions */ pkt += 23; /* if ( ghostrecon_debug) print_packet( pkt, GrPayloadLen); */ return DONE_FORCE; } char *find_ravenshield_game(char *gameno) { switch (atoi(gameno)) { case 8: return strdup("Team Deathmatch"); break; case 13: return strdup("Deathmatch"); break; case 14: return strdup("Team Deathmatch"); break; case 15: return strdup("Bomb"); break; case 16: return strdup("Escort Pilot"); break; default: // 1.50 and above actually uses a string so // return that return strdup(gameno); break; } } char *find_savage_game(char *gametype) { if (0 == strcmp("RTSS", gametype)) { return strdup("RTSS"); } else { return strdup("Unknown"); } } query_status_t deal_with_ravenshield_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *key, *value; debug( 2, "deal_with_ravenshield_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'; s = rawpkt; while (*s) { // Find the seperator while (*s && *s != '\xB6') { s++; } if (! *s) { // Hit the end no more break; } // key start key = ++s; while (*s && *s != ' ') { s++; } if (*s != ' ') { // malformed break; } *s++ = '\0'; // key end // value start value = s; while (*s && *s != '\xB6') { s++; } if (*s == '\xB6') { *(s - 1) = '\0'; } // Decode current key par if (0 == strcmp("A1", key)) { // Max players server->max_players = atoi(value); } else if (0 == strcmp("A2", key)) { // TeamKillerPenalty add_rule(server, "TeamKillerPenalty", value, NO_FLAGS); } else if (0 == strcmp("B1", key)) { // Current players server->num_players = atoi(value); } else if (0 == strcmp("B2", key)) { // AllowRadar add_rule(server, "AllowRadar", value, NO_FLAGS); } else if (0 == strcmp("D2", key)) { // Version info add_rule(server, "Version", value, NO_FLAGS); } else if (0 == strcmp("E1", key)) { // Current map server->map_name = strdup(value); } else if (0 == strcmp("E2", key)) { // Unknown } else if (0 == strcmp("F1", key)) { // Game type server->game = find_ravenshield_game(value); add_rule(server, server->type->game_rule, server->game, NO_FLAGS); } else if (0 == strcmp("F2", key)) { // Unknown } else if (0 == strcmp("G1", key)) { // Password add_rule(server, "Password", value, NO_FLAGS); } else if (0 == strcmp("G2", key)) { // Query port } else if (0 == strcmp("H1", key)) { // Unknown } else if (0 == strcmp("H2", key)) { // Number of Terrorists add_rule(server, "nbTerro", value, NO_FLAGS); } else if (0 == strcmp("I1", key)) { // Server name server->server_name = strdup(value); } else if (0 == strcmp("I2", key)) { // Unknown } else if (0 == strcmp("J1", key)) { // Game Type Order // Not pretty ignore for now //add_rule( server, "Game Type Order", value, NO_FLAGS ); } else if (0 == strcmp("J2", key)) { // RotateMap add_rule(server, "RotateMap", value, NO_FLAGS); } else if (0 == strcmp("K1", key)) { // Map Cycle // Not pretty ignore for now //add_rule( server, "Map Cycle", value, NO_FLAGS ); } else if (0 == strcmp("K2", key)) { // Force First Person Weapon add_rule(server, "ForceFPersonWeapon", value, NO_FLAGS); } else if (0 == strcmp("L1", key)) { // Players names int player_number = 0; char *n = value; if (*n == '/') { // atleast 1 player n++; while (*n && *n != '\xB6') { char *player_name = n; while (*n && *n != '/' && *n != '\xB6') { n++; } if (*n == '/') { *n++ = '\0'; } else if (*n == '\xB6') { *(n - 1) = '\0'; } if (0 != strlen(player_name)) { struct player *player = add_player(server, player_number); if (NULL != player) { player->name = strdup(player_name); } player_number++; } } } } else if (0 == strcmp("L3", key)) { // PunkBuster state add_rule(server, "PunkBuster", value, NO_FLAGS); } else if (0 == strcmp("M1", key)) { // Players times int player_number = 0; char *n = value; if (*n == '/') { // atleast 1 player n++; while (*n && *n != '\xB6') { char *time = n; while (*n && *n != '/' && *n != '\xB6') { n++; } if (*n == '/') { *n++ = '\0'; } else if (*n == '\xB6') { *(n - 1) = '\0'; } if (0 != strlen(time)) { int mins, seconds; if (2 == sscanf(time, "%d:%d", &mins, &seconds)) { struct player *player = get_player_by_number(server, player_number); if (NULL != player) { player->connect_time = mins * 60+seconds; } } player_number++; } } } } else if (0 == strcmp("N1", key)) { // Players ping int player_number = 0; char *n = value; if (*n == '/') { // atleast 1 player n++; while (*n && *n != '\xB6') { char *ping = n; while (*n && *n != '/' && *n != '\xB6') { n++; } if (*n == '/') { *n++ = '\0'; } else if (*n == '\xB6') { *(n - 1) = '\0'; } if (0 != strlen(ping)) { struct player *player = get_player_by_number(server, player_number); if (NULL != player) { player->ping = atoi(ping); } player_number++; } } } } else if (0 == strcmp("O1", key)) { // Players fags int player_number = 0; char *n = value; if (*n == '/') { // atleast 1 player n++; while (*n && *n != '\xB6') { char *frags = n; while (*n && *n != '/' && *n != '\xB6') { n++; } if (*n == '/') { *n++ = '\0'; } else if (*n == '\xB6') { *(n - 1) = '\0'; } if (0 != strlen(frags)) { struct player *player = get_player_by_number(server, player_number); if (NULL != player) { player->frags = atoi(frags); } player_number++; } } } } else if (0 == strcmp("P1", key)) { // Game port // Not pretty ignore for now /* change_server_port( server, atoi( value ), 0 ); */ } else if (0 == strcmp("Q1", key)) { // RoundsPerMatch add_rule(server, "RoundsPerMatch", value, NO_FLAGS); } else if (0 == strcmp("R1", key)) { // RoundTime add_rule(server, "RoundTime", value, NO_FLAGS); } else if (0 == strcmp("S1", key)) { // BetweenRoundTime add_rule(server, "BetweenRoundTime", value, NO_FLAGS); } else if (0 == strcmp("T1", key)) { // BombTime add_rule(server, "BombTime", value, NO_FLAGS); } else if (0 == strcmp("W1", key)) { // ShowNames add_rule(server, "ShowNames", value, NO_FLAGS); } else if (0 == strcmp("X1", key)) { // InternetServer add_rule(server, "InternetServer", value, NO_FLAGS); } else if (0 == strcmp("Y1", key)) { // FriendlyFire add_rule(server, "FriendlyFire", value, NO_FLAGS); } else if (0 == strcmp("Z1", key)) { // Autobalance add_rule(server, "Autobalance", value, NO_FLAGS); } } return DONE_FORCE; } 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; } query_status_t deal_with_farcry_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *key, *value, *end; debug( 2, "deal_with_farcry_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; } /* postions of map name, player name (in player substring), zero-based */ #define BFRIS_MAP_POS 18 #define BFRIS_PNAME_POS 11 query_status_t deal_with_bfris_packet(struct qserver *server, char *rawpkt, int pktlen) { int i, player_data_pos, nplayers; SavedData *sdata; unsigned char *saved_data; int saved_data_size; debug( 2, "deal_with_bfris_packet %p, %d", server, pktlen ); server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); /* add to the data previously saved */ sdata = &server->saved_data; if (!sdata->data) { sdata->data = (char*)malloc(pktlen); } else { sdata->data = (char*)realloc(sdata->data, sdata->datalen + pktlen); } memcpy(sdata->data + sdata->datalen, rawpkt, pktlen); sdata->datalen += pktlen; saved_data = (unsigned char*)sdata->data; saved_data_size = sdata->datalen; /* after we get the server portion of the data, server->game != NULL */ if (!server->game) { /* server data goes up to map name */ if (sdata->datalen <= BFRIS_MAP_POS) { return INPROGRESS; } /* see if map name is complete */ player_data_pos = 0; for (i = BFRIS_MAP_POS; i < saved_data_size; i++) { if (saved_data[i] == '\0') { player_data_pos = i + 1; /* data must extend beyond map name */ if (saved_data_size <= player_data_pos) { return INPROGRESS; } break; } } /* did we find beginning of player data? */ if (!player_data_pos) { return INPROGRESS; } /* now we can go ahead and fill in server data */ server->map_name = strdup((char*)saved_data + BFRIS_MAP_POS); server->max_players = saved_data[12]; server->protocol_version = saved_data[11]; /* save game type */ switch (saved_data[13] &15) { case 0: server->game = "FFA"; break; case 5: server->game = "Rover"; break; case 6: server->game = "Occupation"; break; case 7: server->game = "SPAAL"; break; case 8: server->game = "CTF"; break; default: server->game = "unknown"; break; } server->flags |= FLAG_DO_NOT_FREE_GAME; add_rule(server, server->type->game_rule, server->game, NO_FLAGS); if (get_server_rules) { char buf[24]; /* server revision */ sprintf(buf, "%d", (unsigned int)saved_data[11]); add_rule(server, "Revision", buf, NO_FLAGS); /* latency */ sprintf(buf, "%d", (unsigned int)saved_data[10]); add_rule(server, "Latency", buf, NO_FLAGS); /* player allocation */ add_rule(server, "Allocation", saved_data[13] &16 ? "Automatic" : "Manual", NO_FLAGS); } } /* If we got this far, we know the data saved goes at least to the start of the player information, and that the server data is taken care of. */ /* start of player data */ player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1; /* ensure all player data have arrived */ nplayers = 0; while (saved_data[player_data_pos] != '\0') { player_data_pos += BFRIS_PNAME_POS; /* does player data extend to player name? */ if (saved_data_size <= player_data_pos + 1) { return INPROGRESS; } /* does player data extend to end of player name? */ for (i = 0; player_data_pos + i < saved_data_size; i++) { if (saved_data_size == player_data_pos + i + 1) { return INPROGRESS; } if (saved_data[player_data_pos + i] == '\0') { player_data_pos += i + 1; nplayers++; break; } } } /* all player data are complete */ server->num_players = nplayers; if (get_player_info) { /* start of player data */ player_data_pos = BFRIS_MAP_POS + strlen((char*)saved_data + BFRIS_MAP_POS) + 1; for (i = 0; i < nplayers; i++) { struct player *player; player = add_player(server, saved_data[player_data_pos]); player->ship = saved_data[player_data_pos + 1]; player->ping = saved_data[player_data_pos + 2]; player->frags = saved_data[player_data_pos + 3]; player->team = saved_data[player_data_pos + 4]; switch (player->team) { case 0: player->team_name = "silver"; break; case 1: player->team_name = "red"; break; case 2: player->team_name = "blue"; break; case 3: player->team_name = "green"; break; case 4: player->team_name = "purple"; break; case 5: player->team_name = "yellow"; break; case 6: player->team_name = "cyan"; break; default: player->team_name = "unknown"; break; } player->flags |= PLAYER_FLAG_DO_NOT_FREE_TEAM; player->room = saved_data[player_data_pos + 5]; /* score is little-endian integer */ player->score = saved_data[player_data_pos + 7] + (saved_data[player_data_pos + 8] << 8) + (saved_data[player_data_pos + 9] << 16) + (saved_data[player_data_pos + 10] << 24); /* for archs with > 4-byte int */ if (player->score &0x80000000) { player->score = - (~(player->score)) - 1; } player_data_pos += BFRIS_PNAME_POS; player->name = strdup((char*)saved_data + player_data_pos); player_data_pos += strlen(player->name) + 1; } } server->server_name = BFRIS_SERVER_NAME; return DONE_FORCE; } struct rule *add_uchar_rule(struct qserver *server, char *key, unsigned char value) { char buf[24]; sprintf(buf, "%u", (unsigned)value); return add_rule(server, key, buf, NO_FLAGS); } query_status_t deal_with_descent3_packet(struct qserver *server, char *rawpkt, int pktlen) { char *pkt; char buf[24]; debug( 2, "deal_with_descent3_packet %p, %d", server, pktlen ); if (server->server_name == NULL) { server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); } if (pktlen < 4) { fprintf(stderr, "short descent3 packet\n"); print_packet(server, rawpkt, pktlen); return PKT_ERROR; } /* 'info' response */ if (rawpkt[1] == 0x1f) { if (server->server_name != NULL) { return PKT_ERROR; } pkt = &rawpkt[0x15]; server->server_name = strdup(pkt); pkt += strlen(pkt) + 2; server->map_name = strdup(pkt); /* mission name (blah.mn3) */ pkt += strlen(pkt) + 2; add_rule(server, "level_name", pkt, NO_FLAGS); pkt += strlen(pkt) + 2; add_rule(server, "gametype", pkt, NO_FLAGS); pkt += strlen(pkt) + 1; sprintf(buf, "%hu", swap_short_from_little(pkt)); add_rule(server, "level_num", buf, NO_FLAGS); pkt += 2; server->num_players = swap_short_from_little(pkt); pkt += 2; server->max_players = swap_short_from_little(pkt); pkt += 2; /* unknown/undecoded fields.. stuff like permissible, banned items/ships, etc */ add_uchar_rule(server, "u0", pkt[0]); add_uchar_rule(server, "u1", pkt[1]); add_uchar_rule(server, "u2", pkt[2]); add_uchar_rule(server, "u3", pkt[3]); add_uchar_rule(server, "u4", pkt[4]); add_uchar_rule(server, "u5", pkt[5]); add_uchar_rule(server, "u6", pkt[6]); add_uchar_rule(server, "u7", pkt[7]); add_uchar_rule(server, "u8", pkt[8]); add_uchar_rule(server, "randpowerup", (unsigned char)!(pkt[4] &1)); /* randomize powerup spawn */ add_uchar_rule(server, "acccollisions", (unsigned char)((pkt[5] &4) > 0)); /* accurate collision detection */ add_uchar_rule(server, "brightships", (unsigned char)((pkt[5] &16) > 0)); /* bright player ships */ add_uchar_rule(server, "mouselook", (unsigned char)((pkt[6] &1) > 0)); /* mouselook enabled */ sprintf(buf, "%s%s", (pkt[4] &16) ? "PP" : "CS", (pkt[6] &1) ? "-ML" : ""); add_rule(server, "servertype", buf, NO_FLAGS); sprintf(buf, "%hhu", pkt[9]); add_rule(server, "difficulty", buf, NO_FLAGS); /* unknown/undecoded fields after known flags removed */ add_uchar_rule(server, "x4", (unsigned char)(pkt[4] &~(1+16))); add_uchar_rule(server, "x5", (unsigned char)(pkt[5] &~(4+16))); add_uchar_rule(server, "x6", (unsigned char)(pkt[6] &~1)); if (get_player_info && server->num_players) { server->next_player_info = 0; send_player_request_packet(server); return INPROGRESS; } } /* MP_PLAYERLIST_DATA */ else if (rawpkt[1] == 0x73) { struct player *player; struct player **last_player = &server->players; if (server->players != NULL) { return PKT_ERROR; } pkt = &rawpkt[0x4]; while (*pkt) { player = (struct player*)calloc(1, sizeof(struct player)); player->name = strdup(pkt); pkt += strlen(pkt) + 1; *last_player = player; last_player = &player->next; } server->next_player_info = NO_PLAYER_INFO; } else { fprintf(stderr, "unknown d3 packet\n"); print_packet(server, rawpkt, pktlen); } return DONE_FORCE; } #define EYE_NAME_MASK 1 #define EYE_TEAM_MASK 2 #define EYE_SKIN_MASK 4 #define EYE_SCORE_MASK 8 #define EYE_PING_MASK 16 #define EYE_TIME_MASK 32 query_status_t deal_with_eye_packet(struct qserver *server, char *rawpkt, int pktlen) { char *next, *end, *value, *key; struct player **last_player; unsigned char pkt_index, pkt_max; unsigned int pkt_id; debug( 2, "deal_with_eye_packet %p, %d", server, pktlen ); if (pktlen < 4) { return PKT_ERROR; } if (rawpkt[0] != 'E' || rawpkt[1] != 'Y' || rawpkt[2] != 'E') { return PKT_ERROR; } server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); end = rawpkt + pktlen; pkt_index = rawpkt[3] - '0'; if (pktlen == 1364 || pkt_index != 1) { /* fragmented packet */ SavedData *sdata; /* EYE doesn't tell us how many packets to expect. Two packets * is enough for 100+ players on a BF1942 server with standard * server rules. */ pkt_max = 2; memcpy(&pkt_id, &rawpkt[pktlen - 4], 4); 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 - 1; sdata->pkt_max = pkt_max; sdata->pkt_id = pkt_id; if (pkt_index == 1) { sdata->datalen = pktlen - 4; } else { sdata->datalen = pktlen - 8; } sdata->data = (char*)malloc(sdata->datalen); if (NULL == sdata->data) { return MEM_ERROR; } if (pkt_index == 1) { memcpy(sdata->data, &rawpkt[0], sdata->datalen); } else { memcpy(sdata->data, &rawpkt[4], sdata->datalen); } /* combine_packets will call us recursively */ return combine_packets(server); } value = dup_n1string(&rawpkt[4], end, &next); if (value == NULL) { return MEM_ERROR; } add_rule(server, "gamename", value, NO_VALUE_COPY); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } add_rule(server, "hostport", value, NO_VALUE_COPY); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } server->server_name = value; value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } server->game = value; add_rule(server, server->type->game_rule, value, NO_FLAGS); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } server->map_name = value; value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } add_rule(server, "_version", value, NO_VALUE_COPY); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } add_rule(server, "_password", value, NO_VALUE_COPY); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } server->num_players = atoi(value); free(value); value = dup_n1string(next, end, &next); if (value == NULL) { return MEM_ERROR; } server->max_players = atoi(value); free(value); /* rule1,value1,rule2,value2, ... empty string */ do { key = dup_n1string(next, end, &next); if (key == NULL) { break; } else if (key[0] == '\0') { free(key); break; } value = dup_n1string(next, end, &next); if (value == NULL) { free(key); break; } add_rule(server, key, value, NO_VALUE_COPY | NO_KEY_COPY); } while (1); /* [mask1][mask2]... */ last_player = &server->players; while (next && next < end) { struct player *player; unsigned mask = *((unsigned char*)next); next++; if (next >= end) { break; } if (mask == 0) { break; } player = (struct player*)calloc(1, sizeof(struct player)); if (player == NULL) { break; } if (mask &EYE_NAME_MASK) { player->name = dup_n1string(next, end, &next); //fprintf( stderr, "Player '%s'\n", player->name ); if (player->name == NULL) { break; } } if (mask &EYE_TEAM_MASK) { value = dup_n1string(next, end, &next); if (value == NULL) { break; } if (isdigit((unsigned char)value[0])) { player->team = atoi(value); free(value); } else { player->team_name = value; } } if (mask &EYE_SKIN_MASK) { player->skin = dup_n1string(next, end, &next); if (player->skin == NULL) { break; } } if (mask &EYE_SCORE_MASK) { value = dup_n1string(next, end, &next); if (value == NULL) { break; } player->score = atoi(value); player->frags = player->score; free(value); } if (mask &EYE_PING_MASK) { value = dup_n1string(next, end, &next); if (value == NULL) { break; } player->ping = atoi(value); free(value); } if (mask &EYE_TIME_MASK) { value = dup_n1string(next, end, &next); if (value == NULL) { break; } player->connect_time = atoi(value); free(value); } *last_player = player; last_player = &player->next; //fprintf( stderr, "Player '%s'\n", player->name ); } return DONE_FORCE; } static const char hl2_statusresponse[] = "\xFF\xFF\xFF\xFF\x49"; static const char hl2_playersresponse[] = "\xFF\xFF\xFF\xFF\x44"; static const char hl2_rulesresponse[] = "\xFF\xFF\xFF\xFF\x45"; static const int hl2_response_size = sizeof(hl2_statusresponse) - 1; #define HL2_STATUS 1 #define HL2_PLAYERS 2 #define HL2_RULES 3 query_status_t deal_with_hl2_packet(struct qserver *server, char *rawpkt, int pktlen) { char *ptr = rawpkt; char *end = rawpkt + pktlen; char temp[512]; int type = 0; unsigned char protocolver = 0; int n_sent = 0; debug( 2, "deal_with_hl2_packet %p, %d", server, pktlen ); 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); } // Check if correct reply if (pktlen < hl2_response_size) { malformed_packet(server, "short response type"); return PKT_ERROR; } else { if (0 == memcmp(hl2_statusresponse, ptr, hl2_response_size)) { if (pktlen < hl2_response_size + 20) { malformed_packet(server, "short packet"); return PKT_ERROR; } type = HL2_STATUS; } else if (0 == memcmp(hl2_playersresponse, ptr, hl2_response_size)) { type = HL2_PLAYERS; } else if (0 == memcmp(hl2_rulesresponse, ptr, hl2_response_size)) { type = HL2_RULES; } else { malformed_packet(server, "unknown response"); return PKT_ERROR; } } // header ptr += hl2_response_size; switch (type) { case HL2_STATUS: // protocol version protocolver = *ptr; ptr++; debug(2, "protocol: 0x%02X", protocolver); // Commented out till out of beta /* if( '\x02' != protocolver ) { malformed_packet(server, "protocol version != 0x02"); return PKT_ERROR; } */ server->protocol_version = protocolver; sprintf(temp, "%d", protocolver); add_rule(server, "protocol", temp, NO_FLAGS); // server name server->server_name = strdup(ptr); ptr += strlen(ptr) + 1; // map server->map_name = strdup(ptr); ptr += strlen(ptr) + 1; // gamedir server->game = strdup(ptr); add_rule(server, "gamedir", ptr, NO_FLAGS); ptr += strlen(ptr) + 1; // description add_rule(server, "description", ptr, NO_FLAGS); ptr += strlen(ptr) + 1; // appid ptr += 2; // num players server->num_players = *ptr; ptr++; // max players server->max_players = *ptr; ptr++; // bot players sprintf(temp, "%hhu", (*ptr)); add_rule(server, "bot_players", temp, NO_FLAGS); ptr++; // dedicated if ('d' == *ptr) { add_rule(server, "sv_type", "dedicated", NO_FLAGS); } else if ('l' == *ptr) { add_rule(server, "sv_type", "listen", NO_FLAGS); } else { char tmp[2] = { *ptr, '\0' } ; add_rule(server, "sv_type", tmp, NO_FLAGS); } ptr++; // OS if ('l' == *ptr) { add_rule(server, "sv_os", "linux", NO_FLAGS); } else if ('w' == *ptr) { add_rule(server, "sv_os", "windows", NO_FLAGS); } else { char tmp[2] = { *ptr, '\0' } ; add_rule(server, "sv_os", tmp, NO_FLAGS); } ptr++; // passworded add_rule(server, "sv_password", *ptr ? "1" : "0", NO_FLAGS); ptr++; // secure add_rule(server, "secure", *ptr ? "1" : "0", NO_FLAGS); ptr++; // send the other request packets if wanted if (get_server_rules) { int requests = server->n_requests; debug(3, "send_rule_request_packet7"); send_rule_request_packet(server); server->n_requests = requests; // prevent wrong ping n_sent++; } else if (get_player_info) { int requests = server->n_requests; send_player_request_packet(server); server->n_requests = requests; // prevent wrong ping n_sent++; } break; case HL2_RULES: // num_players ptr++; // max_players ptr++; while (ptr < end) { char *var = ptr; char *val; ptr += strlen(var) + 1; val = ptr; ptr += strlen(val) + 1; add_rule(server, var, val, NO_FLAGS); } if (get_player_info) { send_player_request_packet(server); n_sent++; } break; case HL2_PLAYERS: // num_players ptr++; while (ptr < end) { struct player *player = add_player(server, server->n_player_info); // player no ptr++; // name player->name = strdup(ptr); ptr += strlen(ptr) + 1; // frags player->frags = swap_long_from_little(ptr); ptr += 4; // time player->connect_time = swap_float_from_little(ptr); ptr += 4; } break; default: malformed_packet(server, "unknown response"); return PKT_ERROR; } return ( 0 == n_sent ) ? DONE_FORCE : INPROGRESS; } query_status_t deal_with_gamespy_master_response(struct qserver *server, char *rawpkt, int pktlen) { debug( 2, "deal_with_gamespy_master_response %p, %d", server, pktlen ); if ( 0 == pktlen || ( pktlen > 6 && 0 == strncmp( rawpkt + pktlen - 6, "final\\", 6 ) ) ) { int len = server->saved_data.datalen; char *data = server->saved_data.data; char *ip, *portstr; unsigned int ipaddr; unsigned short port; int master_pkt_max; server->server_name = GAMESPY_MASTER_NAME; master_pkt_max = (len / 20) *6; server->master_pkt = (char*)malloc(master_pkt_max); server->master_pkt_len = 0; while (len) { for (; len && *data == '\\'; data++, len--) ; if (len < 3) { break; } if (data[0] == 'i' && data[1] == 'p' && data[2] == '\\') { data += 3; len -= 3; ip = data; portstr = NULL; for (; len && *data != '\\'; data++, len--) { if (*data == ':') { portstr = data + 1; *data = '\0'; } } if (len == 0) { break; } *data++ = '\0'; len--; ipaddr = inet_addr(ip); if (portstr) { port = htons((unsigned short)atoi(portstr)); } else { port = htons(28000); } /* ## default port */ if (server->master_pkt_len >= master_pkt_max) { master_pkt_max += 20 * 6; server->master_pkt = (char*)realloc(server->master_pkt, master_pkt_max); } memcpy(server->master_pkt + server->master_pkt_len, &ipaddr, 4); memcpy(server->master_pkt + server->master_pkt_len + 4, &port, 2); server->master_pkt_len += 6; } else { for (; len && *data != '\\'; data++, len--) ; } } server->n_servers = server->master_pkt_len / 6; server->next_player_info = - 1; server->retry1 = 0; return DONE_FORCE; } if (!server->saved_data.data) { server->saved_data.data = (char*)malloc(pktlen); } else { server->saved_data.data = (char*)realloc(server->saved_data.data, server->saved_data.datalen + pktlen); } memcpy(server->saved_data.data + server->saved_data.datalen, rawpkt, pktlen); server->saved_data.datalen += pktlen; return INPROGRESS; } /* Misc utility functions */ char *strndup(const char *string, size_t len) { char *result; result = (char*)malloc(len + 1); memcpy(result, string, len); result[len] = '\0'; return result; } unsigned int swap_long(void *l) { unsigned char *b = (unsigned char*)l; return b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); } unsigned short swap_short(void *l) { unsigned char *b = (unsigned char*)l; return (unsigned short)b[0] | (b[1] << 8); } unsigned int swap_long_from_little(void *l) { unsigned char *b = (unsigned char*)l; unsigned int result; if (little_endian) { memcpy(&result, l, 4); } else { result = (unsigned int)b[0] + (b[1] << 8) + (b[2] << 16) + (b[3] << 24); } return result; } float swap_float_from_little(void *f) { union { int i; float fl; } temp; temp.i = swap_long_from_little(f); return temp.fl; } unsigned short swap_short_from_little(void *l) { unsigned char *b = (unsigned char*)l; unsigned short result; if (little_endian) { memcpy(&result, l, 2); } else { result = (unsigned short)b[0] | ((unsigned short)b[1] << 8); } return result; } /** write four byte to buf */ void put_long_little(unsigned val, char *buf) { buf[0] = val &0xFF; buf[1] = (val >> 8) &0xFF; buf[2] = (val >> 16) &0xFF; buf[3] = (val >> 24) &0xFF; } #define MAXSTRLEN 2048 char *xml_escape(char *string) { static unsigned char _buf[4][MAXSTRLEN + 8]; static int _buf_index = 0; unsigned char *result, *b, *end; unsigned int c; if (string == NULL) { return ""; } result = &_buf[_buf_index][0]; _buf_index = (_buf_index + 1) % 4; end = &result[MAXSTRLEN]; b = result; for (; *string && b < end; string++) { c = *string; switch (c) { case '&': *b++ = '&'; *b++ = 'a'; *b++ = 'm'; *b++ = 'p'; *b++ = ';'; continue; case '\'': *b++ = '&'; *b++ = 'a'; *b++ = 'p'; *b++ = 'o'; *b++ = 's'; *b++ = ';'; continue; case '"': *b++ = '&'; *b++ = 'q'; *b++ = 'u'; *b++ = 'o'; *b++ = 't'; *b++ = ';'; continue; case '<': *b++ = '&'; *b++ = 'l'; *b++ = 't'; *b++ = ';'; continue; case '>': *b++ = '&'; *b++ = 'g'; *b++ = 't'; *b++ = ';'; continue; default: break; } // Validate character // http://www.w3.org/TR/2000/REC-xml-20001006#charsets if ( ! ( 0x09 == c || 0xA == c || 0xD == c || ( 0x20 <= c && 0xD7FF >= c ) || ( 0xE000 <= c && 0xFFFD >= c ) || ( 0x10000 <= c && 0x10FFFF >= c ) ) ) { if ( show_errors ) { fprintf(stderr, "Encoding error (%d) for U+%x, D+%d\n", 1, c, c); } } else if (xml_encoding == ENCODING_LATIN_1) { if (!xform_names) { *b++ = c; } else { if (isprint(c)) { *b++ = c; } else { b += sprintf( (char *)b, "&#%u;", c); } } } else if (xml_encoding == ENCODING_UTF_8) { unsigned char tempbuf[10] = { 0 }; unsigned char *buf = &tempbuf[0]; int bytes = 0; int error = 1; // Valid character ranges if ( 0x09 == c || 0xA == c || 0xD == c || ( 0x20 <= c && 0xD7FF >= c ) || ( 0xE000 <= c && 0xFFFD >= c ) || ( 0x10000 <= c && 0x10FFFF >= c ) ) { error = 0; } if (c < 0x80) /* 0XXX XXXX one byte */ { buf[0] = c; bytes = 1; } else if (c < 0x0800) /* 110X XXXX two bytes */ { buf[0] = 0xC0 | (0x03 &(c >> 6)); buf[1] = 0x80 | (0x3F &c); bytes = 2; } else if (c < 0x10000) /* 1110 XXXX three bytes */ { buf[0] = 0xE0 | (c >> 12); buf[1] = 0x80 | ((c >> 6) &0x3F); buf[2] = 0x80 | (c &0x3F); bytes = 3; if (c == UTF8BYTESWAPNOTACHAR || c == UTF8NOTACHAR) { error = 3; } } else if (c < 0x10FFFF) /* 1111 0XXX four bytes */ { buf[0] = 0xF0 | (c >> 18); buf[1] = 0x80 | ((c >> 12) &0x3F); buf[2] = 0x80 | ((c >> 6) &0x3F); buf[3] = 0x80 | (c &0x3F); bytes = 4; if (c > UTF8MAXFROMUCS4) { error = 4; } } else if (c < 0x4000000) /* 1111 10XX five bytes */ { buf[0] = 0xF8 | (c >> 24); buf[1] = 0x80 | (c >> 18); buf[2] = 0x80 | ((c >> 12) &0x3F); buf[3] = 0x80 | ((c >> 6) &0x3F); buf[4] = 0x80 | (c &0x3F); bytes = 5; error = 5; } else if (c < 0x80000000) /* 1111 110X six bytes */ { buf[0] = 0xFC | (c >> 30); buf[1] = 0x80 | ((c >> 24) &0x3F); buf[2] = 0x80 | ((c >> 18) &0x3F); buf[3] = 0x80 | ((c >> 12) &0x3F); buf[4] = 0x80 | ((c >> 6) &0x3F); buf[5] = 0x80 | (c &0x3F); bytes = 6; error = 6; } else { error = 7; } if (error) { int i; fprintf(stderr, "UTF-8 encoding error (%d) for U+%x, D+%d : ", error, c, c); for (i = 0; i < bytes; i++) { fprintf(stderr, "0x%02x ", buf[i]); } fprintf(stderr, "\n"); } else { int i; for (i = 0; i < bytes; ++i) { *b++ = buf[i]; } } } } *b = '\0'; return (char*)result; } int is_default_rule(struct rule *rule) { if (strcmp(rule->name, "sv_maxspeed") == 0) { return strcmp(rule->value, Q_DEFAULT_SV_MAXSPEED) == 0; } if (strcmp(rule->name, "sv_friction") == 0) { return strcmp(rule->value, Q_DEFAULT_SV_FRICTION) == 0; } if (strcmp(rule->name, "sv_gravity") == 0) { return strcmp(rule->value, Q_DEFAULT_SV_GRAVITY) == 0; } if (strcmp(rule->name, "noexit") == 0) { return strcmp(rule->value, Q_DEFAULT_NOEXIT) == 0; } if (strcmp(rule->name, "teamplay") == 0) { return strcmp(rule->value, Q_DEFAULT_TEAMPLAY) == 0; } if (strcmp(rule->name, "timelimit") == 0) { return strcmp(rule->value, Q_DEFAULT_TIMELIMIT) == 0; } if (strcmp(rule->name, "fraglimit") == 0) { return strcmp(rule->value, Q_DEFAULT_FRAGLIMIT) == 0; } return 0; } char *strherror(int h_err) { static char msg[100]; switch (h_err) { case HOST_NOT_FOUND: return "host not found"; case TRY_AGAIN: return "try again"; case NO_RECOVERY: return "no recovery"; case NO_ADDRESS: return "no address"; default: sprintf(msg, "%d", h_err); return msg; } } int time_delta(struct timeval *later, struct timeval *past) { if (later->tv_usec < past->tv_usec) { later->tv_sec--; later->tv_usec += 1000000; } return (later->tv_sec - past->tv_sec) *1000+(later->tv_usec - past->tv_usec) / 1000; } int connection_inprogress() { #ifdef _WIN32 return WSAGetLastError() == WSAEWOULDBLOCK; #else return errno == EINPROGRESS; #endif } int connection_refused() { #ifdef _WIN32 return WSAGetLastError() == WSAECONNABORTED; #else return errno == ECONNREFUSED; #endif } int connection_would_block() { #ifdef _WIN32 return WSAGetLastError() == WSAEWOULDBLOCK; #else return errno == EAGAIN; #endif } int connection_reset() { #ifdef _WIN32 return WSAGetLastError() == WSAECONNRESET; #else return errno == ECONNRESET; #endif } void clear_socketerror() { #ifdef _WIN32 WSASetLastError(0); #else errno = 0; #endif } void set_non_blocking(int fd) { #ifdef _WIN32 int one = 1; ioctlsocket(fd, FIONBIO, (unsigned long*) &one); #else #ifdef O_NONBLOCK fcntl(fd, F_SETFL, O_NONBLOCK); #else fcntl(fd, F_SETFL, O_NDELAY); #endif // O_NONBLOCK #endif // _WIN32 } char *quake_color(int color) { static char *colors[] = { "White", /* 0 */ "Brown", /* 1 */ "Lavender", /* 2 */ "Khaki", /* 3 */ "Red", /* 4 */ "Lt Brown", /* 5 */ "Peach", /* 6 */ "Lt Peach", /* 7 */ "Purple", /* 8 */ "Dk Purple",/* 9 */ "Tan", /* 10 */ "Green", /* 11 */ "Yellow", /* 12 */ "Blue", /* 13 */ "Blue", /* 14 */ "Blue" /* 15 */ }; static char *rgb_colors[] = { "#ffffff", /* 0 */ "#8b4513", /* 1 */ "#e6e6fa", /* 2 */ "#f0e68c", /* 3 */ "#ff0000", /* 4 */ "#deb887", /* 5 */ "#eecbad", /* 6 */ "#ffdab9", /* 7 */ "#9370db", /* 8 */ "#5d478b", /* 9 */ "#d2b48c", /* 10 */ "#00ff00", /* 11 */ "#ffff00", /* 12 */ "#0000ff", /* 13 */ "#0000ff", /* 14 */ "#0000ff" /* 15 */ }; static char *color_nr[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15" }; if (color_names) { if (color_names == 1) { return colors[color &0xf]; } else { return rgb_colors[color &0xf]; } } else { return color_nr[color &0xf]; } } #define FMT_HOUR_1 "%2dh" #define FMT_HOUR_2 "%dh" #define FMT_MINUTE_1 "%2dm" #define FMT_MINUTE_2 "%dm" #define FMT_SECOND_1 "%2ds" #define FMT_SECOND_2 "%ds" char *play_time(int seconds, int show_seconds) { static char time_string[24]; if (time_format == CLOCK_TIME) { char *fmt_hour = show_seconds == 2 ? FMT_HOUR_2 : FMT_HOUR_1; char *fmt_minute = show_seconds == 2 ? FMT_MINUTE_2 : FMT_MINUTE_1; char *fmt_second = show_seconds == 2 ? FMT_SECOND_2 : FMT_SECOND_1; time_string[0] = '\0'; if (seconds / 3600) { sprintf(time_string, fmt_hour, seconds / 3600); } else if (show_seconds < 2) { strcat(time_string, " "); } if ((seconds % 3600) / 60 || seconds / 3600) { sprintf(time_string + strlen(time_string), fmt_minute, (seconds % 3600) / 60); } else if (!show_seconds) { sprintf(time_string + strlen(time_string), " 0m"); } else if (show_seconds < 2) { strcat(time_string, " "); } if (show_seconds) { sprintf(time_string + strlen(time_string), fmt_second, seconds % 60); } } else if (time_format == STOPWATCH_TIME) { if (show_seconds) { sprintf(time_string, "%02d:%02d:%02d", seconds / 3600, (seconds % 3600) / 60, seconds % 60); } else { sprintf(time_string, "%02d:%02d", seconds / 3600, (seconds % 3600) / 60); } } else { sprintf(time_string, "%d", seconds); } return time_string; } char *ping_time(int ms) { static char time_string[24]; if (ms < 1000) { sprintf(time_string, "%dms", ms); } else if (ms < 1000000) { sprintf(time_string, "%ds", ms / 1000); } else { sprintf(time_string, "%dm", ms / 1000 / 60); } return time_string; } int count_bits(int n) { int b = 0; for (; n; n >>= 1) if (n &1) { b++; } return b; } int strcmp_withnull(char *one, char *two) { if (one == NULL && two == NULL) { return 0; } if (one != NULL && two == NULL) { return -1; } if (one == NULL) { return 1; } return strcasecmp(one, two); } /* * Sorting functions */ void sort_servers(struct qserver **array, int size) { quicksort((void **)array, 0, size - 1, (int(*)(void *, void*))server_compare); } void sort_players(struct qserver *server) { struct player **array, *player, *last_team = NULL, **next; int np, i; if (server->num_players == 0 || server->players == NULL) { return ; } player = server->players; for (; player != NULL && player->number == TRIBES_TEAM;) { last_team = player; player = player->next; } if (player == NULL) { return ; } array = (struct player **)malloc(sizeof(struct player*)*(server->num_players + server->num_spectators)); for (np = 0; player != NULL && np < server->num_players + server->num_spectators; np++) { array[np] = player; player = player->next; } quicksort((void **)array, 0, np - 1, (int(*)(void *, void*))player_compare); if (last_team) { next = &last_team->next; } else { next = &server->players; } for (i = 0; i < np; i++) { *next = array[i]; array[i]->next = NULL; next = &array[i]->next; } free(array); } int server_compare(struct qserver *one, struct qserver *two) { int rc; char *key = sort_keys; for (; *key; key++) { switch (*key) { case 'g': rc = strcmp_withnull(one->game, two->game); if (rc) { return rc; } break; case 'p': if (one->n_requests == 0) { return two->n_requests; } else if (two->n_requests == 0) { return -1; } rc = one->ping_total / one->n_requests - two->ping_total / two->n_requests; if (rc) { return rc; } break; case 'i': if (one->ipaddr > two->ipaddr) { return 1; } else if (one->ipaddr < two->ipaddr) { return -1; } else if (one->port > two->port) { return 1; } else if (one->port < two->port) { return -1; } break; case 'h': rc = strcmp_withnull(one->host_name, two->host_name); if (rc) { return rc; } break; case 'n': rc = two->num_players - one->num_players; if (rc) { return rc; } break; } } return 0; } int type_option_compare(server_type *one, server_type *two) { return strcmp_withnull(one->type_option, two->type_option); } int type_string_compare(server_type *one, server_type *two) { return strcmp_withnull(one->type_string, two->type_string); } int player_compare(struct player *one, struct player *two) { int rc; char *key = sort_keys; for (; *key; key++) { switch (*key) { case 'P': rc = one->ping - two->ping; if (rc) { return rc; } break; case 'F': rc = two->frags - one->frags; if (rc) { return rc; } break; case 'S': rc = two->score - one->score; if (rc) { return rc; } break; case 'T': rc = one->team - two->team; if (rc) { return rc; } rc = strcmp_withnull(one->team_name, two->team_name); if (rc) { return rc; } break; case 'N': rc = strcmp_withnull(one->name, two->name); if (rc) { return rc; } return one->number - two->number; break; } } return 0; } void quicksort(void **array, int i, int j, int(*compare)(void *, void*)) { int q = 0; if (i < j) { q = qpartition(array, i, j, compare); quicksort(array, i, q, compare); quicksort(array, q + 1, j, compare); } } int qpartition(void **array, int a, int b, int(*compare)(void *, void*)) { /* this is our comparison point. when we are done splitting this array into 2 parts, we want all the elements on the left side to be less then or equal to this, all the elements on the right side need to be greater then or equal to this */ void *z; /* indicies into the array to sort. Used to calculate a partition point */ int i = a - 1; int j = b + 1; /* temp pointer used to swap two array elements */ void *tmp = NULL; z = array[a]; while (1) { /* move the right indice over until the value of that array elem is less than or equal to z. Stop if we hit the left side of the array (ie, j == a); */ do { j--; } while (j > a && compare(array[j], z) > 0); /* move the left indice over until the value of that array elem is greater than or equal to z, or until we hit the right side of the array (ie i == j) */ do { i++; } while (i <= j && compare(array[i], z) < 0); /* if i is less then j, we need to switch those two array elements, if not then we are done partitioning this array section */ if (i < j) { tmp = array[i]; array[i] = array[j]; array[j] = tmp; } else { return j; } } } qstat-2.15/ventrilo.h0000644000175000017500000000106012420765614011535 00000000000000/* * qstat * by Steve Jankowski * * Ventrilo query protocol * Algorithm by Luigi Auriemma (Reversing and first version in c) * Copyright 2010 Michael Willigens * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_VENTRILO_H #define QSTAT_VENTRILO_H #include "qserver.h" // Packet processing methods query_status_t deal_with_ventrilo_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_ventrilo_request_packet( struct qserver *server ); #endif qstat-2.15/gps.h0000644000175000017500000000065712420765615010500 00000000000000/* * qstat * by Steve Jankowski * * Gamespy query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_GPS_H #define QSTAT_GPS_H #include "qserver.h" // Packet processing methods query_status_t deal_with_gps_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_gps_request_packet( struct qserver *server ); #endif qstat-2.15/mumble.c0000644000175000017500000000315412420765615011156 00000000000000/* * qstat * by Steve Jankowski * * Mumble protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #include #include #ifndef _WIN32 #include #endif #include "debug.h" #include "qstat.h" #include "packet_manip.h" query_status_t send_mumble_request_packet( struct qserver *server ) { return send_packet( server, server->type->status_packet, server->type->status_len ); } query_status_t deal_with_mumble_packet( struct qserver *server, char *rawpkt, int pktlen ) { // skip unimplemented ack, crc, etc char *pkt = rawpkt; char bandwidth[11]; char version[11]; server->ping_total += time_delta(&packet_recv_time, &server->packet_time1); if ( 24 != pktlen || 0 != memcmp( pkt+4, server->type->status_packet+4, 8 ) ) { // unknown packet return PKT_ERROR; } // version server->protocol_version = ntohl(*(unsigned long*)pkt); sprintf(version,"%u.%u.%u", (unsigned char)*pkt+1, (unsigned char)*pkt+2, (unsigned char)*pkt+3); add_rule( server, "version", version, NO_FLAGS ); pkt += 4; // ident pkt += 8; // num players server->num_players = ntohl(*(unsigned long*)pkt); pkt += 4; // max players server->max_players = ntohl(*(unsigned long*)pkt); pkt += 4; // allowed bandwidth sprintf( bandwidth, "%d", ntohl(*(unsigned long*)pkt)); add_rule( server, "allowed_bandwidth", bandwidth, NO_FLAGS ); pkt += 4; // Unknown details server->map_name = strdup( "N/A" ); server->server_name = strdup( "Unknown" ); add_rule( server, "gametype", "Unknown", NO_FLAGS ); return DONE_FORCE; } qstat-2.15/debug.c0000644000175000017500000000641112420765614010761 00000000000000/* * qstat * by Steve Jankowski * * debug helper functions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #include #ifndef _WIN32 #include #include #else #include #endif #include #include #include #include #include #include #include #define QSTAT_DEBUG_C #include "debug.h" #ifdef ENABLE_DUMP #ifndef _WIN32 #include #else #include #endif #endif #ifdef DEBUG void _debug(const char* file, int line, const char* function, int level, const char* fmt, ...) { va_list ap; char buf[9]; time_t now = time( NULL ); strftime(buf,9,"%H:%M:%S", localtime( &now ) ); fprintf(stderr, "debug(%d) %s %s:%d %s() - ", level, buf, file, line, function); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if ( '\n' != fmt[strlen(fmt)-1] ) { fputs("\n", stderr); } return; } #endif static int debug_level = 0; void set_debug_level (int level) { debug_level = level; } int get_debug_level (void) { return (debug_level); } void malformed_packet(const struct qserver* server, const char* fmt, ...) { va_list ap; if(!show_errors) return; fputs("malformed packet", stderr); if(server) { fprintf(stderr, " from %d.%d.%d.%d:%hu", server->ipaddr&0xff, (server->ipaddr>>8)&0xff, (server->ipaddr>>16)&0xff, (server->ipaddr>>24)&0xff, server->port); } fputs(": ", stderr); va_start(ap, fmt); vfprintf(stderr, fmt, ap); va_end(ap); if(*fmt && fmt[strlen(fmt)-1] != '\n') { fputc('\n',stderr); } } #ifdef ENABLE_DUMP static unsigned count = 0; static void _dump_packet(const char* tag, const char* buf, int buflen) { char fn[PATH_MAX] = {0}; int fd; sprintf(fn, "%03u_%s.pkt", count++, tag); fprintf(stderr, "dumping to %s\n", fn); fd = open(fn, O_WRONLY|O_CREAT|O_EXCL, 0644); if(fd == -1) { perror("open"); return; } if(write(fd, buf, buflen) == -1) perror("write"); close(fd); } ssize_t send_dump(int s, const void *buf, size_t len, int flags) { if(do_dump) _dump_packet("send", buf, len); return send(s, buf, len, flags); } #endif void dump_packet(const char* buf, int buflen) { #ifdef ENABLE_DUMP _dump_packet("recv", buf, buflen); #endif } void print_packet( struct qserver *server, const char *buf, int buflen ) { output_packet( server, buf, buflen, 0 ); } void output_packet( struct qserver *server, const char *buf, int buflen, int to ) { static char *hex= "0123456789abcdef"; unsigned char *p= (unsigned char*)buf; int i, h, a, b, astart, offset= 0; char line[256]; if ( server != NULL) { fprintf( stderr, "%s %s len %d\n", ( to ) ? "TO" : "FROM", server->arg, buflen ); } for ( i= buflen; i ; offset+= 16) { memset( line, ' ', 256); h= 0; h+= sprintf( line, "%5d:", offset); a= astart = h + 16*2 + 16/4 + 2; for ( b=16; b && i; b--, i--, p++) { if ( (b & 3) == 0) { line[h++]= ' '; } line[h++]= hex[*p >> 4]; line[h++]= hex[*p & 0xf]; if ( isprint( *p)) { line[a++]= *p; } else { line[a++]= '.'; } if((a-astart)==8) { line[a++] = ' '; } } line[a]= '\0'; fputs( line, stderr); fputs( "\n", stderr); } fputs( "\n", stderr); } qstat-2.15/qserver.h0000644000175000017500000001424412420765615011373 00000000000000/* * qstat * by Steve Jankowski * * qserver functions and definitions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_QSERVER_H #define QSTAT_QSERVER_H struct query_param { char *key; char *value; int i_value; unsigned int ui_value; struct query_param *next; }; typedef struct SavedData { char *data; int datalen; int pkt_index; int pkt_max; unsigned int pkt_id; struct SavedData *next; } SavedData; typedef enum { STATE_INIT = 0, STATE_CONNECTING = 1, STATE_CONNECTED = 2, STATE_QUERYING = 3, STATE_QUERIED = 4, STATE_TIMEOUT = -1, STATE_SYS_ERROR = -2, } server_state_t; struct qserver { char *arg; char *host_name; unsigned int ipaddr; int flags; server_type * type; int fd; server_state_t state; char *outfilename; char *query_arg; char *challenge_string; struct query_param *params; unsigned long challenge; unsigned short port; unsigned short orig_port; // This port is always constant from creation where as port can be updated based on the query results unsigned short query_port; // State variable to flag if the current processing call is a call from combine_packets // This should really by done via a flag to the method itself but that would require changes // to all handlers :( unsigned short combined; /** \brief number of retries _left_ for status query or rule query. * * That means * if s->retry1 == (global)n_retries then no retries were necessary so far. * if s->retry1 == 0 then the server has to be cleaned up after timeout */ int retry1; /** \brief number retries _left_ for player query. @see retry1 */ int retry2; /** \brief how much retry packets were sent */ int n_retries; /** \brief time when the last packet to the server was sent */ struct timeval packet_time1; struct timeval packet_time2; /** \brief sum of packet deltas * * average server ping is ping_total / n_requests */ int ping_total; /** \brief number of requests send to a server. * * used for ping calculation * @see ping_total */ int n_requests; /** \brief number of packets already sent to this server * * doesn't seemt to have any use */ int n_packets; /** \brief number of servers in master_pkt * * normally master_pkt_len/6 */ int n_servers; /** \brief length of master_pkt */ int master_pkt_len; /** \brief IPs received from master. * * array of four bytes ip, two bytes port in network byte order */ char *master_pkt; /** \brief state info * * used for progressive master 4 bytes for WON 22 for Steam */ char master_query_tag[22]; char *error; /** \brief in-game name of the server. * * A server that has a NULL name did not receive any packets yet and is * considered down after a timeout. */ char *server_name; char *address; char *map_name; char *game; int max_players; int num_players; int protocol_version; int max_spectators; int num_spectators; SavedData saved_data; /** \brief number of the next player to retrieve info for. * * Only meaningful for servers that have type->player_packet. * This is used by q1 as it sends packets for each player individually. * cleanup_qserver() cleans up a server if next_rule == NULL and * next_player_info >= num_players */ int next_player_info; /** \brief number of player info packets received */ int n_player_info; struct player *players; /** \brief name of next rule to retreive * * Used by Q1 as it needs to send a packet for each rule. Other games would * set this to an empty string to indicate that rules need to be retrieved. * After rule packet is received set this to NULL. */ char *next_rule; int n_rules; struct rule *rules; struct rule **last_rule; int missing_rules; struct qserver *next; struct qserver *prev; }; void qserver_disconnect(struct qserver* server); /* server specific query parameters */ void add_query_param( struct qserver *server, char *arg); /** \brief get a parameter for the server as string * * @param server the server to get the value from * @param key which key to get * @param default_value value to return if key was not found * @return value for key or default_value */ char * get_param_value( struct qserver *server, const char *key, char *default_value); /** @see get_param_value */ int get_param_i_value( struct qserver *server, char *key, int default_value); /** @see get_param_value */ unsigned int get_param_ui_value( struct qserver *server, char *key, unsigned int default_value); /** \brief send an initial query packet to a server * * Sends a unicast packet to the server's file descriptor. The descriptor must * be connected. Updates n_requests or n_retries, retry1, n_packets, packet_time1 * * \param server the server * \param data data to send * \param len length of data * \returns number of bytes sent or SOCKET_ERROR */ query_status_t qserver_send_initial(struct qserver* server, const char* data, size_t len); /** \brief send an initial query packet to a server * * Sends a unicast packet to the server's file descriptor. The descriptor must * be connected. Updates n_requests, n_packets, packet_time1. Sets retry1 to * (global) n_retries * * @see qserver_send_initial */ query_status_t qserver_send(struct qserver* server, const char* data, size_t len); int send_broadcast( struct qserver *server, const char *pkt, size_t pktlen); /** * Registers the send of a request packet. * * This updates n_requests, n_packets, packet_time1 and decrements n_retries */ int register_send( struct qserver *server ); /** * Sends a packet to the server either direct or via broadcast. * * Once sent calls register_send to register the send of the packet */ query_status_t send_packet( struct qserver* server, const char* data, size_t len ); /** * Logs the error from a socket send */ query_status_t send_error( struct qserver *server, int rc ); #endif qstat-2.15/packet_manip.c0000644000175000017500000001463412420765614012334 00000000000000/* * qstat * by Steve Jankowski * * Packet module * Copyright 2005 Steven Hartland based on code by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include "qstat.h" #include "debug.h" #include #include #define MAX_PACKETS 8 #define MAX_FAGMENTS 128 int pkt_seq = 0; int pkt_id_index = -1; int n_ids; int counts[MAX_PACKETS]; SavedData *segments[MAX_PACKETS][MAX_FAGMENTS]; int combine_packets( struct qserver *server ) { unsigned int ids[MAX_PACKETS]; int maxes[MAX_PACKETS]; int lengths[MAX_PACKETS]; SavedData *sdata = &server->saved_data; int i, p, ret = INPROGRESS; n_ids = 0; memset( &segments[0][0], 0, sizeof(segments) ); memset( &counts[0], 0, sizeof(counts) ); memset( &lengths[0], 0, sizeof(lengths) ); // foreach packet for ( ; sdata != NULL; sdata= sdata->next) { debug( 4, "max:%d, id:%d\n", sdata->pkt_max, sdata->pkt_id ); if ( sdata->pkt_max == 0) { // not expecting multi packets or already processed? continue; } if ( sdata->pkt_index >= MAX_FAGMENTS ) { // we only deal up to MAX_FAGMENTS packet fragment fprintf( stderr, "Too many fragments %d for packetid %d max %d\n", sdata->pkt_index, sdata->pkt_id, MAX_FAGMENTS ); return PKT_ERROR; } for ( i = 0; i < n_ids; i++ ) { if ( sdata->pkt_id == ids[i]) { // found this packetid break; } } if ( i >= n_ids ) { // packetid we havent seen yet if ( n_ids >= MAX_PACKETS ) { // we only deal up to MAX_PACKETS packetids fprintf( stderr, "Too many distinct packetids %d max %d\n", n_ids, MAX_PACKETS ); return PKT_ERROR; } ids[n_ids]= sdata->pkt_id; maxes[n_ids]= sdata->pkt_max; i = n_ids++; } else if ( maxes[i] != sdata->pkt_max ) { // max's dont match debug( 4, "max mismatch %d != %d", maxes[i], sdata->pkt_max ); continue; } if ( segments[i][sdata->pkt_index] == NULL) { // add the packet to the list of segments segments[i][sdata->pkt_index]= sdata; counts[i]++; lengths[i] += sdata->datalen; } else { debug( 2, "duplicate packet detected for id %d, index %d", sdata->pkt_id, sdata->pkt_index ); } } // foreach distinct packetid for ( pkt_id_index = 0; pkt_id_index < n_ids; pkt_id_index++ ) { char *combined; int datalen = 0; int combinedlen; if ( counts[pkt_id_index] != maxes[pkt_id_index] ) { // we dont have all the expected packets yet debug( 4, "more expected: %d != %d\n", counts[pkt_id_index], maxes[pkt_id_index] ); continue; } // combine all the segments combinedlen = lengths[pkt_id_index]; combined = (char*)malloc(combinedlen); for ( p = 0; p < counts[pkt_id_index]; p++ ) { if ( segments[pkt_id_index][p] == NULL ) { debug( 4, "missing segment[%d][%d]", pkt_id_index, p ); // reset to be unusable pkt_id_index = -1; free( combined ); return INPROGRESS; } if (datalen + segments[pkt_id_index][p]->datalen > combinedlen) { fprintf(stderr, "Data length %d > combined length %d\n", datalen + segments[pkt_id_index][p]->datalen, combinedlen); // reset to be unusable pkt_id_index = -1; free(combined); return MEM_ERROR; } memcpy( combined + datalen, segments[pkt_id_index][p]->data, segments[pkt_id_index][p]->datalen ); datalen += segments[pkt_id_index][p]->datalen; } // prevent reprocessing? for ( p = 0; p < counts[pkt_id_index]; p++) { segments[pkt_id_index][p]->pkt_max = 0; } debug( 4, "callback" ); if( 4 <= get_debug_level() ) { print_packet( server, combined, datalen ); } // Call the server's packet processing method flagging as a combine call server->combined = 1; ret = ( (int (*)()) server->type->packet_func)( server, combined, datalen ); free( combined ); server->combined = 0; // Note: this is currently invalid as packet processing methods // are void not int if ( INPROGRESS != ret || NULL == server->saved_data.data ) { break; } } // reset to be unusable pkt_id_index = -1; return ret; } // NOTE: // pkt_id is the packet aka response identifier // pkt_index is the index of the packet fragment int add_packet( struct qserver *server, unsigned int pkt_id, int pkt_index, int pkt_max, int datalen, char *data, int calc_max ) { SavedData *sdata; // safety net for bad data if (datalen == 0) { debug(1, "Empty packet received!"); return 0; } if ( server->saved_data.data == NULL ) { debug( 4, "first packet: %d id, %d index, %d max, %d calc_max", pkt_id, pkt_index, pkt_max, calc_max ); sdata = &server->saved_data; } else { debug( 4, "another packet: %d id, %d index, %d max, %d calc_max", pkt_id, pkt_index, pkt_max, calc_max ); if ( calc_max ) { // check we have the correct max SavedData *cdata = &server->saved_data; for ( ; cdata != NULL; cdata = cdata->next ) { if ( cdata->pkt_max > pkt_max ) { pkt_max = cdata->pkt_max; } } // ensure all the packets know about this new max for ( cdata = &server->saved_data; cdata != NULL; cdata = cdata->next ) { cdata->pkt_max = pkt_max; } } debug( 4, "calced max = %d", pkt_max ); // allocate a new packet data and prepend to the list sdata = (SavedData*) calloc( 1, sizeof(SavedData) ); sdata->next = server->saved_data.next; server->saved_data.next = sdata; } sdata->pkt_id = pkt_id; sdata->pkt_index = pkt_index; sdata->pkt_max = pkt_max; sdata->datalen = datalen; sdata->data = (char*)malloc( sdata->datalen ); if ( NULL == sdata->data ) { fprintf( stderr, "Out of memory\n" ); return 0; } memcpy( sdata->data, data, sdata->datalen ); return 1; } int next_sequence() { return ++pkt_seq; } SavedData* get_packet_fragment( int index ) { if ( -1 == pkt_id_index ) { fprintf( stderr, "Invalid call to get_packet_fragment" ); return NULL; } if ( index > counts[pkt_id_index] ) { debug( 4, "Invalid index requested %d > %d", index, pkt_id_index ); return NULL; } return segments[pkt_id_index][index]; } unsigned combined_length( struct qserver *server, int pkt_id ) { SavedData *sdata = &server->saved_data; unsigned len = 0; for ( ; sdata != NULL; sdata = sdata->next ) { if ( pkt_id == sdata->pkt_id ) { len += sdata->datalen; } } return len; } unsigned packet_count( struct qserver *server ) { SavedData *sdata = &server->saved_data; unsigned cnt = 0; if ( NULL == sdata->data ) { return 0; } for ( ; sdata != NULL; sdata = sdata->next ) { cnt++; } return cnt; } qstat-2.15/gs2.c0000644000175000017500000001763412420765615010400 00000000000000/* * qstat * by Steve Jankowski * * New Gamespy v2 query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #endif #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" query_status_t send_gs2_request_packet( struct qserver *server ) { // The below should work but seems to make no difference to what some // servers send if ( get_player_info ) { server->type->status_packet[8] = 0xff; server->type->status_packet[9] = 0xff; } else { server->type->status_packet[8] = 0x00; server->type->status_packet[9] = 0x00; } return send_packet( server, server->type->status_packet, server->type->status_len ); } // 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; } qstat-2.15/farmsim.c0000644000175000017500000001216212420765615011332 00000000000000/* * qstat * by Steve Jankowski * * Crysis query protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "utils.h" #include "qstat.h" #include "md5.h" #include "packet_manip.h" char *decode_farmsim_val(char *val) { // Very basic html conversion val = str_replace(val, """, "\""); return str_replace(val, "&", "&"); } query_status_t send_farmsim_request_packet(struct qserver *server) { char buf[256], *code; server->saved_data.pkt_max = -1; code = get_param_value(server, "code", ""); sprintf(buf, "GET /feed/dedicated-server-stats.xml?code=%s HTTP/1.1\015\012User-Agent: qstat\015\012\015\012", code); return send_packet(server, buf, strlen(buf)); } query_status_t valid_farmsim_response(struct qserver *server, char *rawpkt, int pktlen) { char *s; int len; int cnt = packet_count(server); if (0 == cnt && 0 != strncmp("HTTP/1.1 200 OK", rawpkt, 15)) { // not valid response debug(2, "Invalid"); return REQ_ERROR; } s = strnstr(rawpkt, "Content-Length: ", pktlen); if (s == NULL) { // not valid response debug(2, "Invalid (no content-length)"); return INPROGRESS; } s += 16; // TODO: remove this bug work around if (*s == ':') { s += 2; } if (sscanf(s, "%d", &len) != 1) { debug(2, "Invalid (no length)"); return INPROGRESS; } s = strnstr(rawpkt, "\015\012\015\012", pktlen); if (s == NULL) { debug(2, "Invalid (no end of header"); return INPROGRESS; } s += 4; if (pktlen != (s - rawpkt + len)) { debug(2, "Outstanding data"); return INPROGRESS; } debug(2, "Valid data"); return DONE_FORCE; } char *farmsim_xml_attrib(char *line, char *name) { char *q, *p, *val; p = strstr(line, name); if (p == NULL) { return NULL; } p += strlen(name); if (strlen(p) < 4) { return NULL; } p += 2; q = strchr(p, '"'); if (q == NULL) { return NULL; } *q = '\0'; val = strdup(p); *q = '"'; debug(4, "%s = %s", name, val); return val; } query_status_t deal_with_farmsim_packet(struct qserver *server, char *rawpkt, int pktlen) { char *s, *val, *line; query_status_t state = INPROGRESS; debug(2, "processing..."); if (!server->combined) { state = valid_farmsim_response(server, rawpkt, pktlen); server->retry1 = n_retries; if (server->n_requests == 0) { server->ping_total = time_delta(&packet_recv_time, &server->packet_time1); server->n_requests++; } switch (state) { case INPROGRESS: { // 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; 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); } case DONE_FORCE: break; // single packet response fall through default: return state; } } if (state != DONE_FORCE) { state = valid_farmsim_response(server, rawpkt, pktlen); switch (state) { case DONE_FORCE: break; // actually process default: return state; } } // 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 = rawpkt; // Ensure we're null terminated (will only loose the last \x0a) s[pktlen - 1] = '\0'; s = decode_farmsim_val(s); line = strtok(s, "\012"); // NOTE: id=XXX and msg=XXX will be processed by the mod following the one they where the response of while (line != NULL) { debug(4, "LINE: %s\n", line); if (strstr(line, " // Server Name val = farmsim_xml_attrib(line, "name"); if (val != NULL) { server->server_name = val; } else { server->server_name = strdup("Unknown"); } // Map Name val = farmsim_xml_attrib(line, "mapName"); if (val != NULL) { server->map_name = val; } else { server->map_name = strdup("Default"); } } else if (strstr(line, " debug(1, "max_players = atoi(val); free(val); } else { server->max_players = get_param_ui_value(server, "maxplayers", 1); } // Num Players val = farmsim_xml_attrib(line, "numUsed"); if (val != NULL) { server->num_players = atoi(val); free(val); } else { server->num_players = 0; } } line = strtok(NULL, "\012"); } gettimeofday(&server->packet_time1, NULL); return DONE_FORCE; } qstat-2.15/xform.h0000644000175000017500000000050312420765614011027 00000000000000/* * xform Functions * Copyright 2013 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_XFORM_H #define QSTAT_XFORM_H #include "qstat.h" void xform_buf_free(); int xform_printf(FILE *, const char *, ...); char * xform_name(char *, struct qserver *); #endif qstat-2.15/cube2.h0000755000175000017500000000071212420765615010702 00000000000000/* * qstat * by Steve Jankowski * * Cube 2 / Sauerbraten protocol * Copyright 2011 NoisyB * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_CUBE2_H #define QSTAT_CUBE2_H #include "qserver.h" // Packet processing methods query_status_t deal_with_cube2_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_cube2_request_packet( struct qserver *server ); #endif // QSTAT_CUBE2_H qstat-2.15/cube2.c0000755000175000017500000001017212420765615010676 00000000000000/* * qstat * by Steve Jankowski * * Cube 2 / Sauerbraten protocol * Copyright 2011 NoisyB * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" struct offset { unsigned char *d; int pos; int len; }; //#define SB_MASTER_SERVER "http://sauerbraten.org/masterserver/retrieve.do?item=list" #define SB_PROTOCOL 258 #define MIN(a,b) ((a)<(b)?(a):(b)) #define MAX_ATTR 255 #define MAX_STRING 1024 static int getint (struct offset * d) { int val = 0; if ( d->pos >= d->len ) { return 0; } val = d->d[d->pos++] & 0xff; // 8 bit value // except... if ( val == 0x80 && d->pos < d->len - 2 ) // 16 bit value { val = (d->d[d->pos++] & 0xff); val |= (d->d[d->pos++] & 0xff) << 8; } else if ( val == 0x81 && d->pos < d->len - 4 ) // 32 bit value { val = (d->d[d->pos++] & 0xff); val |= (d->d[d->pos++] & 0xff) << 8; val |= (d->d[d->pos++] & 0xff) << 16; val |= (d->d[d->pos++] & 0xff) << 24; } return val; } static char * getstr( char *dest, int dest_len, struct offset *d ) { int len = 0; if (d->pos >= d->len) { return NULL; } len = MIN( dest_len, d->len - d->pos ); strncpy( dest, (const char *) d->d + d->pos, len )[len - 1] = 0; d->pos += strlen (dest) + 1; return dest; } static char* sb_getversion_s (int n) { static char *version_s[] = { "Justice", "CTF", "Assassin", "Summer", "Spring", "Gui", "Water", "Normalmap", "Sp", "Occlusion", "Shader", "Physics", "Mp", "", "Agc", "Quakecon", "Independence" }; n = SB_PROTOCOL - n; if (n >= 0 && (size_t) n < sizeof(version_s) / sizeof(version_s[0])) { return version_s[n]; } return "unknown"; } static char* sb_getmode_s(int n) { static char *mode_s[] = { "slowmo SP", "slowmo DMSP", "demo", "SP", "DMSP", "ffa/default", "coopedit", "ffa/duel", "teamplay", "instagib", "instagib team", "efficiency", "efficiency team", "insta arena", "insta clan arena", "tactics arena", "tactics clan arena", "capture", "insta capture", "regen capture", "assassin", "insta assassin", "ctf", "insta ctf" }; n += 6; if (n >= 0 && (size_t) n < sizeof(mode_s) / sizeof(mode_s[0])) { return mode_s[n]; } return "unknown"; } query_status_t send_cube2_request_packet( struct qserver *server ) { return send_packet( server, server->type->status_packet, server->type->status_len ); } query_status_t deal_with_cube2_packet( struct qserver *server, char *rawpkt, int pktlen ) { // skip unimplemented ack, crc, etc int i; int numattr; int attr[MAX_ATTR]; char buf[MAX_STRING]; enum { MM_OPEN = 0, MM_VETO, MM_LOCKED, MM_PRIVATE }; struct offset d; d.d = (unsigned char *) rawpkt; d.pos = 0; d.len = pktlen; server->ping_total += time_delta( &packet_recv_time, &server->packet_time1 ); getint( &d ); // we have the ping already server->num_players = getint( &d ); numattr = getint( &d ); for ( i = 0; i < numattr && i < MAX_ATTR; i++ ) { attr[i] = getint (&d); } server->protocol_version = attr[0]; sprintf( buf, "%d %s", attr[0], sb_getversion_s (attr[0]) ); add_rule( server, "version", buf, NO_FLAGS ); sprintf( buf, "%d %s", attr[1], sb_getmode_s (attr[1]) ); add_rule( server, "mode", buf, NO_FLAGS ); sprintf( buf, "%d", attr[2] ); add_rule( server, "seconds_left", buf, NO_FLAGS ); server->max_players = attr[3]; switch ( attr[5] ) { case MM_OPEN: sprintf( buf, "%d open", attr[5] ); break; case MM_VETO: sprintf( buf, "%d veto", attr[5] ); break; case MM_LOCKED: sprintf( buf, "%d locked", attr[5] ); break; case MM_PRIVATE: sprintf( buf, "%d private", attr[5] ); break; default: sprintf( buf, "%d unknown", attr[5] ); } add_rule( server, "mm", buf, NO_FLAGS); for ( i = 0; i < numattr && i < MAX_ATTR; i++ ) { char buf2[MAX_STRING]; sprintf( buf, "attr%d", i ); sprintf( buf2, "%d", attr[i] ); add_rule( server, buf, buf2, NO_FLAGS ); } getstr( buf, MAX_STRING, &d ); server->map_name = strdup(buf); getstr( buf, MAX_STRING, &d ); server->server_name = strdup(buf); return DONE_FORCE; } qstat-2.15/qserver.c0000644000175000017500000000710612420765615011365 00000000000000/* * qstat * by Steve Jankowski * * qserver functions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include "qstat.h" #include "qserver.h" #include "debug.h" #ifndef _WIN32 #include #include #endif #include #include #include #include #include // TODO: get rid of this and use send_packet instead, remove n_requests hack from a2s query_status_t qserver_send_initial(struct qserver* server, const char* data, size_t len) { int status = INPROGRESS; if( data ) { int ret; debug( 2, "[%s] send", server->type->type_prefix ); if( 4 <= get_debug_level() ) { output_packet( server, data, len, 1 ); } if ( server->flags & FLAG_BROADCAST) { ret = send_broadcast(server, data, len); } else { ret = send( server->fd, data, len, 0); } if ( ret == SOCKET_ERROR) { send_error( server, ret ); status = SYS_ERROR; } } if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST) { gettimeofday( &server->packet_time1, NULL); } else { server->n_retries++; } server->retry1--; server->n_packets++; return status; } query_status_t qserver_send(struct qserver* server, const char* data, size_t len) { int status = INPROGRESS; if(data) { int ret; if ( server->flags & FLAG_BROADCAST) { ret = send_broadcast(server, data, len); } else { ret = send( server->fd, data, len, 0); } if ( ret == SOCKET_ERROR) { send_error( server, ret ); status = SYS_ERROR; } } server->retry1 = n_retries-1; gettimeofday( &server->packet_time1, NULL); server->n_requests++; server->n_packets++; return status; } int send_broadcast( struct qserver *server, const char *pkt, size_t pktlen) { struct sockaddr_in addr; addr.sin_family= AF_INET; if ( no_port_offset || server->flags & TF_NO_PORT_OFFSET) { addr.sin_port= htons(server->port); } else { addr.sin_port= htons((unsigned short)( server->port + server->type->port_offset )); } addr.sin_addr.s_addr= server->ipaddr; memset( &(addr.sin_zero), 0, sizeof(addr.sin_zero)); return sendto( server->fd, (const char*) pkt, pktlen, 0, (struct sockaddr *) &addr, sizeof(addr)); } int register_send( struct qserver *server ) { if ( server->retry1 == n_retries || server->flags & FLAG_BROADCAST ) { server->n_requests++; } else { server->n_retries++; } // New request so reset the sent time. This ensures // that we record an accurate ping time even on retry gettimeofday( &server->packet_time1, NULL); server->retry1--; server->n_packets++; return INPROGRESS; } query_status_t send_packet( struct qserver* server, const char* data, size_t len ) { debug( 2, "[%s] send", server->type->type_prefix ); if( 4 <= get_debug_level() ) { output_packet( server, data, len, 1 ); } if( data ) { int ret; if ( server->flags & FLAG_BROADCAST ) { ret = send_broadcast( server, data, len ); } else { ret = send( server->fd, data, len, 0 ); } if ( ret == SOCKET_ERROR ) { return send_error( server, ret ); } } register_send( server ); return INPROGRESS; } query_status_t send_error( struct qserver *server, int rc ) { unsigned int ipaddr = ntohl(server->ipaddr); const char* errstr = strerror(errno); fprintf(stderr, "Error on %d.%d.%d.%d: %s, skipping ...\n", (ipaddr >> 24) &0xff, (ipaddr >> 16) &0xff, (ipaddr >> 8) &0xff, ipaddr &0xff, errstr ); return SYS_ERROR; } qstat-2.15/template.c0000644000175000017500000006173712420765614011522 00000000000000/* * qstat * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Thanks to Per Hammer for the OS/2 patches (per@mindbend.demon.co.uk) * Thanks to John Ross Hunt for the OpenVMS Alpha patches (bigboote@ais.net) * Thanks to Scott MacFiggen for the quicksort code (smf@webmethods.com) * * Inspired by QuakePing by Len Norton * * Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #include #include #include #include #include #if defined(__hpux) || defined(_AIX) || defined(__FreeBSD__) || defined(__MidnightBSD__) #include #endif #ifndef _WIN32 #include #endif #include "qstat.h" #include "xform.h" #ifdef _WIN32 #define strcasecmp stricmp #define strncasecmp strnicmp #endif #ifdef __hpux #define STATIC static #else #define STATIC #endif /* #ifdef __cplusplus extern "C" { #endif #ifndef _AIX extern unsigned int ntohl(unsigned int n); #endif #ifdef __cplusplus } #endif */ extern int hostname_lookup; extern int num_servers_total; extern int num_servers_timed_out; extern int num_servers_down; extern int num_players_total; extern int max_players_total; extern int xform_html_names; extern int xform_hex_player_names; extern FILE *OF; /* output file */ static char *server_template; static char *rule_template; static char *header_template; static char *trailer_template; static char *player_template; static void display_server_var( struct qserver *server, int var); static void display_player_var( struct player *player, int var, struct qserver *server); static void display_rule_var( struct rule *rule, int var, struct qserver *server); static void display_generic_var( int var); static int parse_var( char *varname, int *varlen); static int read_template( char *filename, char **template_text); static void display_string( char *str); static int is_true( struct qserver *server, struct player *player, struct rule *rule, char *expr); #define VARIABLE_CHAR '$' static char *variable_option; static int if_skip; static int if_level; static int if_skip_save; static int if_level_save; int html_mode= 0; int clear_newlines_mode= 0; int rule_name_spaces= 0; struct vardef { char *var; int varcode; int options; }; #define NO_OPTIONS 0 #define OPTIONS_OK 1 #define EXPR 2 struct vardef variable_defs[] = { #define V_HOSTNAME 1 {"HOSTNAME", V_HOSTNAME, NO_OPTIONS }, #define V_SERVERNAME 2 {"SERVERNAME", V_SERVERNAME, NO_OPTIONS }, #define V_PING 3 {"PING", V_PING, NO_OPTIONS }, #define V_PLAYERS 4 {"PLAYERS", V_PLAYERS, NO_OPTIONS | EXPR }, #define V_MAXPLAYERS 5 {"MAXPLAYERS", V_MAXPLAYERS, NO_OPTIONS }, #define V_MAP 6 {"MAP", V_MAP, NO_OPTIONS }, #define V_GAME 7 {"GAME", V_GAME, NO_OPTIONS | EXPR }, #define V_RETRIES 8 {"RETRIES", V_RETRIES, NO_OPTIONS }, #define V_IPADDR 9 {"IPADDR", V_IPADDR, NO_OPTIONS }, #define V_PORT 10 {"PORT", V_PORT, NO_OPTIONS }, #define V_ARG 11 {"ARG", V_ARG, NO_OPTIONS }, #define V_QSTATURL 12 {"QSTATURL", V_QSTATURL, NO_OPTIONS }, #define V_QSTATVERSION 13 {"QSTATVERSION", V_QSTATVERSION, NO_OPTIONS }, #define V_QSTATAUTHOR 14 {"QSTATAUTHOR", V_QSTATAUTHOR, NO_OPTIONS }, #define V_QSTATAUTHOREMAIL 15 {"QSTATAUTHOREMAIL", V_QSTATAUTHOREMAIL, NO_OPTIONS }, #define V_TYPE 16 {"TYPE", V_TYPE, NO_OPTIONS }, #define V_RULE 17 {"RULE", V_RULE, OPTIONS_OK | EXPR }, #define V_ALLRULES 18 {"ALLRULES", V_ALLRULES, NO_OPTIONS }, #define V_PLAYERTEMPLATE 19 {"PLAYERTEMPLATE", V_PLAYERTEMPLATE, NO_OPTIONS }, #define V_PLAYERNAME 20 {"PLAYERNAME", V_PLAYERNAME, NO_OPTIONS }, #define V_FRAGS 21 {"FRAGS", V_FRAGS, NO_OPTIONS }, #define V_PLAYERPING 22 {"PLAYERPING", V_PLAYERPING, NO_OPTIONS }, #define V_CONNECTTIME 23 {"CONNECTTIME", V_CONNECTTIME, NO_OPTIONS }, #define V_SKIN 24 {"SKIN", V_SKIN, NO_OPTIONS }, #define V_SHIRTCOLOR 25 {"SHIRTCOLOR", V_SHIRTCOLOR, NO_OPTIONS }, #define V_PANTSCOLOR 26 {"PANTSCOLOR", V_PANTSCOLOR, NO_OPTIONS }, #define V_PLAYERIP 27 {"PLAYERIP", V_PLAYERIP, NO_OPTIONS }, #define V_IF 28 {"IF", V_IF, OPTIONS_OK }, #define V_ENDIF 29 {"ENDIF", V_ENDIF, NO_OPTIONS }, #define V_HTML 35 {"HTML", V_HTML, NO_OPTIONS }, #define V_FLAG 36 {"FLAG", V_FLAG, OPTIONS_OK | EXPR }, #define V_UP 37 {"UP", V_UP, NO_OPTIONS | EXPR }, #define V_DOWN 38 {"DOWN", V_DOWN, NO_OPTIONS | EXPR }, #define V_IFNOT 39 {"IFNOT", V_IFNOT, OPTIONS_OK }, #define V_TIMEOUT 40 {"TIMEOUT", V_TIMEOUT, NO_OPTIONS | EXPR }, #define V_NOW 41 {"NOW", V_NOW, NO_OPTIONS }, #define V_TOTALSERVERS 42 {"TOTALSERVERS", V_TOTALSERVERS, NO_OPTIONS }, #define V_TOTALUP 43 {"TOTALUP", V_TOTALUP, NO_OPTIONS }, #define V_TOTALNOTUP 44 {"TOTALNOTUP", V_TOTALNOTUP, NO_OPTIONS }, #define V_TOTALPLAYERS 45 {"TOTALPLAYERS", V_TOTALPLAYERS, NO_OPTIONS }, #define V_TOTALMAXPLAYERS 46 {"TOTALMAXPLAYERS", V_TOTALMAXPLAYERS, NO_OPTIONS }, #define V_TEAMNUM 49 {"TEAMNUM", V_TEAMNUM, NO_OPTIONS }, #define V_BACKSLASH 50 {"\\", V_BACKSLASH, NO_OPTIONS }, #define V_HOSTNOTFOUND 51 {"HOSTNOTFOUND", V_HOSTNOTFOUND, NO_OPTIONS | EXPR }, #define V_MESH 52 {"MESH", V_MESH, NO_OPTIONS }, #define V_ISEMPTY 56 {"ISEMPTY", V_ISEMPTY, NO_OPTIONS | EXPR }, #define V_ISFULL 57 {"ISFULL", V_ISFULL, NO_OPTIONS | EXPR }, #define V_PACKETLOSS 58 {"PACKETLOSS", V_PACKETLOSS, NO_OPTIONS }, #define V_ISTEAM 59 {"ISTEAM", V_ISTEAM, NO_OPTIONS | EXPR }, #define V_TEAMNAME 60 {"TEAMNAME", V_TEAMNAME, NO_OPTIONS }, #define V_DEFAULTTYPE 61 {"DEFAULTTYPE", V_DEFAULTTYPE, NO_OPTIONS }, #define V_TYPESTRING 62 {"TYPESTRING", V_TYPESTRING, NO_OPTIONS }, #define V_FACE 63 {"FACE", V_FACE, NO_OPTIONS }, #define V_SOLDIEROFFORTUNE 64 {"SOLDIEROFFORTUNE", V_SOLDIEROFFORTUNE, NO_OPTIONS }, #define V_COLORNUMBERS 65 {"COLORNUMBERS", V_COLORNUMBERS, NO_OPTIONS }, #define V_COLORNAMES 66 {"COLORNAMES", V_COLORNAMES, NO_OPTIONS }, #define V_COLORRGB 67 {"COLORRGB", V_COLORRGB, NO_OPTIONS }, #define V_TIMESECONDS 68 {"TIMESECONDS", V_TIMESECONDS, NO_OPTIONS }, #define V_TIMECLOCK 69 {"TIMECLOCK", V_TIMECLOCK, NO_OPTIONS }, #define V_TIMESTOPWATCH 70 {"TIMESTOPWATCH", V_TIMESTOPWATCH, NO_OPTIONS }, #define V_NOWINT 71 {"NOWINT", V_NOWINT, NO_OPTIONS }, #define V_ISMASTER 72 {"ISMASTER", V_ISMASTER, NO_OPTIONS | EXPR }, #define V_HTMLPLAYERNAME 73 {"HTMLPLAYERNAME", V_HTMLPLAYERNAME, NO_OPTIONS }, #define V_ISBOT 74 {"ISBOT", V_ISBOT, NO_OPTIONS | EXPR }, #define V_ISALIAS 75 {"ISALIAS", V_ISALIAS, NO_OPTIONS | EXPR }, #define V_TRIBETAG 76 {"TRIBETAG", V_TRIBETAG, NO_OPTIONS | EXPR }, #define V_CLEARNEWLINES 77 {"CLEARNEWLINES", V_CLEARNEWLINES, NO_OPTIONS }, #define V_GAMETYPE 78 {"GAMETYPE", V_GAMETYPE, NO_OPTIONS }, #define V_DEATHS 79 {"DEATHS", V_DEATHS, NO_OPTIONS | EXPR }, #define V_TYPEPREFIX 80 {"TYPEPREFIX", V_TYPEPREFIX, NO_OPTIONS }, #define V_RULENAMESPACES 81 {"RULENAMESPACES", V_RULENAMESPACES, NO_OPTIONS }, #define V_RULETEMPLATE 82 {"RULETEMPLATE", V_RULETEMPLATE, NO_OPTIONS }, #define V_RULENAME 83 {"RULENAME", V_RULENAME, OPTIONS_OK | EXPR }, #define V_RULEVALUE 84 {"RULEVALUE", V_RULEVALUE, OPTIONS_OK | EXPR }, #define V_PLAYERSTATID 85 {"PLAYERSTATID", V_PLAYERSTATID, NO_OPTIONS }, #define V_PLAYERLEVEL 86 {"PLAYERLEVEL", V_PLAYERLEVEL, NO_OPTIONS }, #define V_TOTALUTILIZATION 87 {"TOTALUTILIZATION", V_TOTALUTILIZATION, NO_OPTIONS }, #define V_SCORE 88 {"SCORE", V_SCORE, NO_OPTIONS }, }; int read_qserver_template( char *filename) { return read_template( filename, &server_template); } int read_rule_template( char *filename) { return read_template( filename, &rule_template); } int read_header_template( char *filename) { return read_template( filename, &header_template); } int read_trailer_template( char *filename) { return read_template( filename, &trailer_template); } int read_player_template( char *filename) { return read_template( filename, &player_template); } STATIC int read_template( char *filename, char **template_text) { FILE *file; int length, rc; file= fopen( filename, "r"); if ( file == NULL) { perror( filename); return -1; } fseek( file, 0, SEEK_END); length= ftell( file); fseek( file, 0, SEEK_SET); *template_text= (char*)malloc( length+1); rc= fread( *template_text, 1, length, file); if ( rc == 0 && length > 0) { perror( filename); fclose( file); free( *template_text); *template_text= NULL; return -1; } (*template_text)[rc]= '\0'; return 0; } int have_server_template() { return server_template != NULL; } int have_header_template() { return header_template != NULL; } int have_trailer_template() { return trailer_template != NULL; } void template_display_server( struct qserver *server) { char *t= server_template; int var, varlen; if_level= 0; if_skip= 0; for ( ; *t; t++) { if ( *t != VARIABLE_CHAR) { if ( ! if_skip) putc( *t, OF); continue; } var= parse_var( t, &varlen); if ( var == -1) { if ( ! if_skip) putc( VARIABLE_CHAR, OF); continue; } if ( var == V_BACKSLASH) { t+= 2; if ( *t == '\r') { if ( *++t == '\n') t++; } else if ( *t == '\n') t++; t--; continue; } if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL) { int truth= (var==V_IF)?1:0; if ( !if_skip && is_true( server, NULL, NULL, variable_option) == truth) if_level++; else if_skip++; } else if ( var == V_ENDIF) { if ( if_skip) if_skip--; else if ( if_level) if_level--; } if ( ! if_skip) display_server_var( server, var); t+= varlen; } } void template_display_players( struct qserver *server) { struct player *player; for ( player= server->players; player != NULL; player= player->next) template_display_player( server, player); } void template_display_player( struct qserver *server, struct player *player) { char *t= player_template; int var, varlen; if ( player_template == NULL) return; if_level= 0; if_skip= 0; for ( ; *t; t++) { if ( *t != VARIABLE_CHAR) { if ( ! if_skip) putc( *t, OF); continue; } var= parse_var( t, &varlen); if ( var == -1) { if ( ! if_skip) putc( VARIABLE_CHAR, OF); continue; } if ( var == V_BACKSLASH) { t+= 2; if ( *t == '\r') { if ( *++t == '\n') t++; } else if ( *t == '\n') t++; t--; continue; } if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL) { int truth= (var==V_IF)?1:0; if ( !if_skip && is_true( server, player, NULL, variable_option) == truth) if_level++; else if_skip++; } else if ( var == V_ENDIF) { if ( if_skip) if_skip--; else if ( if_level) if_level--; } if ( ! if_skip) display_player_var( player, var, server); t+= varlen; } } void template_display_rules( struct qserver *server) { struct rule *rule; for ( rule= server->rules; rule != NULL; rule= rule->next) template_display_rule( server, rule); } void template_display_rule( struct qserver *server, struct rule *rule) { char *t= rule_template; int var, varlen; if ( rule_template == NULL) return; if_level= 0; if_skip= 0; for ( ; *t; t++) { if ( *t != VARIABLE_CHAR) { if ( ! if_skip) putc( *t, OF); continue; } var= parse_var( t, &varlen); if ( var == -1) { if ( ! if_skip) putc( VARIABLE_CHAR, OF); continue; } if ( var == V_BACKSLASH) { t+= 2; if ( *t == '\r') { if ( *++t == '\n') t++; } else if ( *t == '\n') t++; t--; continue; } if ( (var == V_IF || var == V_IFNOT) && variable_option != NULL) { int truth= (var==V_IF)?1:0; if ( !if_skip && is_true( server, NULL, rule, variable_option) == truth) if_level++; else if_skip++; } else if ( var == V_ENDIF) { if ( if_skip) if_skip--; else if ( if_level) if_level--; } if ( ! if_skip) display_rule_var( rule, var, server); t+= varlen; } } void template_display_header() { char *t= header_template; int var, varlen; if_level= 0; if_skip= 0; for ( ; *t; t++) { if ( *t != VARIABLE_CHAR) { putc( *t, OF); continue; } var= parse_var( t, &varlen); if ( var == -1) { putc( VARIABLE_CHAR, OF); continue; } if ( var == V_BACKSLASH) { t+= 2; if ( *t == '\r') { if ( *++t == '\n') t++; } else if ( *t == '\n') t++; t--; continue; } display_generic_var( var); t+= varlen; } } void template_display_trailer() { char *t= trailer_template; int var, varlen; if_level= 0; if_skip= 0; for ( ; *t; t++) { if ( *t != VARIABLE_CHAR) { putc( *t, OF); continue; } var= parse_var( t, &varlen); if ( var == -1) { putc( VARIABLE_CHAR, OF); continue; } if ( var == V_BACKSLASH) { t+= 2; if ( *t == '\r') { if ( *++t == '\n') t++; } else if ( *t == '\n') t++; t--; continue; } display_generic_var( var); t+= varlen; } } STATIC void display_server_var( struct qserver *server, int var) { char *game; int full_data= 1; if ( server->server_name == DOWN || server->server_name == TIMEOUT || server->server_name == SYSERROR || server->error != NULL || server->type->master) full_data= 0; switch( var) { case V_HOSTNAME: fputs( (hostname_lookup) ? server->host_name : server->arg, OF); break; case V_SERVERNAME: fputs( xform_name( server->server_name, server), OF); break; case V_PING: if ( server->server_name != TIMEOUT && server->server_name != DOWN && server->server_name != HOSTNOTFOUND && server->server_name != SYSERROR) fprintf( OF, "%d", server->n_requests ? server->ping_total/server->n_requests : 999); break; case V_PLAYERS: if ( full_data) fprintf( OF, "%d", server->num_players); break; case V_MAXPLAYERS: if ( full_data) fprintf( OF, "%d", server->max_players); break; case V_MAP: if ( full_data) fputs( (server->map_name) ? server->map_name : "?", OF); break; case V_GAME: if ( full_data) { game= get_qw_game( server); fputs( (game) ? game : "", OF); } break; case V_GAMETYPE: { struct rule *rule; for ( rule= server->rules; rule != NULL; rule= rule->next) if ( strcasecmp( rule->name, "g_gametype") == 0) break; if ( rule != NULL) { switch ( atoi(rule->value)) { case 0: fputs( "Free For All", OF); break; case 1: fputs( "Tournament", OF); break; case 3: fputs( "Team Deathmatch", OF); break; case 4: fputs( "Capture the Flag", OF); break; case 5: fputs( "Fortress or OSP", OF); break; case 6: fputs( "Capture and Hold", OF); break; case 8: fputs( "Arena", OF); break; default: fputs( "?", OF); break; } } } break; case V_RETRIES: if ( server->server_name != TIMEOUT && server->server_name != DOWN && server->server_name != HOSTNOTFOUND) fprintf( OF, "%d", server->n_retries); break; case V_IPADDR: { unsigned int ipaddr= ntohl(server->ipaddr); fprintf( OF, "%u.%u.%u.%u", (ipaddr>>24)&0xff, (ipaddr>>16)&0xff, (ipaddr>>8)&0xff, ipaddr&0xff); } break; case V_PORT: fprintf( OF, "%hu", server->port); break; case V_ARG: fputs( server->arg, OF); break; case V_TYPE: fputs( server->type->game_name, OF); break; case V_TYPESTRING: fputs( server->type->type_string, OF); break; case V_TYPEPREFIX: fputs( server->type->type_prefix, OF); break; case V_RULE: { struct rule *rule; if ( variable_option == NULL) break; for ( rule= server->rules; rule != NULL; rule= rule->next) if ( strcasecmp( rule->name, variable_option) == 0) display_string( rule->value); } break; case V_ALLRULES: { struct rule *rule; for ( rule= server->rules; rule != NULL; rule= rule->next) { if ( rule != server->rules) fputs( ", ", OF); display_string( rule->name); putc( '=', OF); display_string( rule->value); } } break; case V_PLAYERTEMPLATE: if_level_save= if_level; if_skip_save= if_skip; template_display_players( server); if_level= if_level_save; if_skip= if_skip_save; break; case V_RULETEMPLATE: if_level_save= if_level; if_skip_save= if_skip; template_display_rules( server); if_level= if_level_save; if_skip= if_skip_save; break; default: display_generic_var( var); } } STATIC void display_player_var( struct player *player, int var, struct qserver *server) { switch( var) { case V_PLAYERNAME: fputs( xform_name( player->name, server), OF); break; case V_HTMLPLAYERNAME: { int save_html_names= xform_html_names; int save_hex_player_names= xform_hex_player_names; xform_html_names= 1; xform_hex_player_names= 0; fputs( xform_name( player->name, server), OF); xform_html_names= save_html_names; xform_hex_player_names= save_hex_player_names; } break; case V_TRIBETAG: fputs( xform_name( player->tribe_tag, server), OF); break; case V_FRAGS: fprintf( OF, "%d", player->frags); break; case V_SCORE: fprintf( OF, "%d", player->score); break; case V_DEATHS: fprintf( OF, "%d", player->deaths); break; case V_PLAYERPING: fprintf( OF, "%d", player->ping); break; case V_CONNECTTIME: fputs( play_time(player->connect_time,0), OF); break; case V_SKIN: display_string( player->skin); break; case V_MESH: display_string( player->mesh); break; case V_FACE: display_string( player->face); break; case V_SHIRTCOLOR: if ( color_names) fputs( quake_color(player->shirt_color), OF); else fprintf( OF, "%d", player->shirt_color); break; case V_PANTSCOLOR: if ( color_names) fputs( quake_color(player->pants_color), OF); else fprintf( OF, "%d", player->pants_color); break; case V_PLAYERIP: if ( player->address) fputs( player->address, OF); break; case V_TEAMNUM: fprintf( OF, "%d", player->team); break; case V_PACKETLOSS: fprintf( OF, "%d", player->packet_loss); break; case V_TEAMNAME: if ( player->team_name) fprintf( OF, "%s", player->team_name); break; case V_COLORNUMBERS: color_names= 0; break; case V_COLORNAMES: color_names= 1; break; case V_COLORRGB: color_names= 2; break; case V_TIMESECONDS: time_format= SECONDS; break; case V_TIMECLOCK: time_format= CLOCK_TIME; break; case V_TIMESTOPWATCH: time_format= STOPWATCH_TIME; break; case V_PLAYERSTATID: case V_PLAYERLEVEL: fprintf( OF, "%u", player->ship); break; default: display_server_var( server, var); } } STATIC void display_rule_var( struct rule *rule, int var, struct qserver *server) { switch( var) { case V_RULENAME: fputs( rule->name, OF); break; case V_RULEVALUE: fputs( xform_name( rule->value, server), OF); break; default: display_server_var( server, var); } } STATIC void display_generic_var( int var) { switch( var) { case V_QSTATURL: fputs( "http://www.qstat.org", OF); break; case V_QSTATVERSION: fputs( qstat_version, OF); break; case V_QSTATAUTHOR: fputs( "Steve Jankowski", OF); break; case V_QSTATAUTHOREMAIL: fputs( "steve@qstat.org", OF); break; case V_HTML: html_mode^= 1; if ( html_mode && xform_html_names == -1) xform_html_names= 1; break; case V_CLEARNEWLINES: clear_newlines_mode^= 1; break; case V_NOW: { time_t now= time(0); char *now_string= ctime(&now); now_string[strlen(now_string)-1]= '\0'; fputs( now_string, OF); break; } case V_NOWINT: fprintf( OF, "%u", (unsigned int)time(0)); break; case V_TOTALSERVERS: fprintf( OF, "%d", num_servers_total); break; case V_TOTALUP: fprintf( OF, "%d", num_servers_total - num_servers_timed_out - num_servers_down); break; case V_TOTALNOTUP: fprintf( OF, "%d", num_servers_timed_out + num_servers_down); break; case V_TOTALPLAYERS: fprintf( OF, "%d", num_players_total); break; case V_TOTALMAXPLAYERS: fprintf( OF, "%d", max_players_total); break; case V_TOTALUTILIZATION: fprintf( OF, "%.1f", (100.0 / max_players_total) * num_players_total); break; case V_DEFAULTTYPE: fprintf( OF, "%s", default_server_type->game_name); break; case V_RULENAMESPACES: rule_name_spaces^= 1; break; default: break; } } STATIC int parse_var( char *varname, int *varlen) { char *v= ++varname, *colon= NULL; int i, quote= 0; if ( variable_option != NULL) { free( variable_option); variable_option= NULL; } if ( *v == '(') { v++; varname++; quote++; } else if ( *v == '\\') { *varlen= 1; return V_BACKSLASH; } for ( ; *v; v++) if ( (!quote && !isalpha( (unsigned char)*v)) || (quote && (*v == ')' || *v == ':'))) break; if ( v-varname == 0) return -1; *varlen= v-varname; if ( *v == ':') colon= v; else if ( quote && *v == ')') v++; for ( i= 0; i < sizeof(variable_defs)/sizeof(struct vardef); i++) if ( strncasecmp( varname, variable_defs[i].var, *varlen) == 0 && *varlen == strlen(variable_defs[i].var)) { if ( colon != NULL && ((variable_defs[i].options & OPTIONS_OK) || quote)) { for ( v++; *v; v++) { if ( (!quote && !isalnum( (unsigned char)*v) && *v != '*' && *v != '_' && *v != '.' && (*v == ' ' && !rule_name_spaces)) || (quote==1 && *v == ')')) break; if ( *v == '(') quote++; else if ( *v == ')') quote--; } variable_option= (char*)malloc( v-colon+1); strncpy( variable_option, colon+1, v-colon-1); variable_option[v-colon-1]= '\0'; if ( quote && *v == ')') v++; } *varlen= v-varname+quote; return variable_defs[i].varcode; } return -1; } STATIC int is_true( struct qserver *server, struct player *player, struct rule *rule, char *expr) { int i, len = 0, arglen = 0; char *arg= NULL, *lparen, *rparen; server_type *t; if ( (lparen= strchr( expr, '(')) != NULL) { if ( (rparen= strchr( lparen, ')')) != NULL) { len= lparen - expr; arg= lparen + 1; arglen= rparen - lparen - 1; } } else len= strlen( expr); for ( i= 0; i < sizeof(variable_defs)/sizeof(struct vardef); i++) if ( strncasecmp( expr, variable_defs[i].var, len) == 0 && len == strlen( variable_defs[i].var)) { if ( !(variable_defs[i].options & EXPR)) { fprintf( stderr, "unsupported IF expression \"%s\"\n", expr); return 1; } switch ( variable_defs[i].varcode) { case V_GAME: { char *g= get_qw_game( server); if ( g == NULL || *g == '\0') return 0; else return 1; } case V_PLAYERS: return server->num_players > 0; case V_ISEMPTY: return server->num_players == 0; case V_ISFULL: return server->max_players ? server->num_players >= server->max_players : 0; case V_ISTEAM: return player ? player->number == TRIBES_TEAM : 0; case V_ISBOT: return player ? player->type_flag == PLAYER_TYPE_BOT : 0; case V_ISALIAS: return player ? player->type_flag == PLAYER_TYPE_ALIAS : 0; case V_TRIBETAG: return player ? player->tribe_tag != NULL : 0; case V_RULE: { struct rule *rule; if ( arg == NULL) return 0; for ( rule= server->rules; rule != NULL; rule= rule->next) if ( strncasecmp( rule->name, arg, arglen) == 0 && strlen( rule->name) == arglen) return 1; return 0; } case V_RULENAME: { if ( rule && arg && strncmp( rule->name, arg, arglen) == 0 && strlen( rule->name) == arglen) return 1; else return 0; } case V_RULEVALUE: { if ( rule && arg && strncmp( rule->value, arg, arglen) == 0 && strlen( rule->value) == arglen) return 1; else return 0; } case V_FLAG: { if ( strncmp( "-H", arg, arglen) == 0) return hostname_lookup; if ( strncmp( "-P", arg, arglen) == 0) return get_player_info; if ( strncmp( "-R", arg, arglen) == 0) return get_server_rules; return 0; } case V_UP: return server->server_name != DOWN && server->server_name != TIMEOUT && server->server_name != HOSTNOTFOUND; case V_DOWN: return server->server_name == DOWN; case V_TIMEOUT: return server->server_name == TIMEOUT; case V_HOSTNOTFOUND: return server->server_name == HOSTNOTFOUND; case V_ISMASTER: return (server->type->id & MASTER_SERVER) ? 1 : 0; case V_DEATHS: return player->deaths; default: return 0; } } t= &types[0]; for ( ; t->id; t++) if ( strncasecmp( expr, t->template_var, len) == 0) return server->type->id == t->id; fprintf( stderr, "bad IF expression \"%s\"\n", expr); return 0; } STATIC void display_string( char *str) { if ( str == NULL) return; if ( ! html_mode && ! clear_newlines_mode) { fputs( str, OF); return; } if ( html_mode && ! clear_newlines_mode) { for ( ; *str; str++) switch ( *str) { case '<': fputs( "<", OF); break; case '>': fputs( ">", OF); break; case '&': fputs( "&", OF); break; case '\n': fputs( "NEWLINE", OF); default: putc( *str, OF); } return; } if ( ! html_mode && clear_newlines_mode) { for ( ; *str; str++) switch ( *str) { case '\n': case '\r': putc( ' ', OF); break; default: putc( *str, OF); } return; } for ( ; *str; str++) switch ( *str) { case '<': fputs( "<", OF); break; case '>': fputs( ">", OF); break; case '&': fputs( "&", OF); break; case '\n': case '\r': putc( ' ', OF); break; default: putc( *str, OF); } } qstat-2.15/fl.h0000644000175000017500000000073112420765615010301 00000000000000/* * qstat * by Steve Jankowski * * Frontlines-Fuel of War protocol * Copyright 2008 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_FL_H #define QSTAT_FL_H #include "qserver.h" query_status_t send_fl_request_packet(struct qserver *server); query_status_t send_fl_rule_request_packet(struct qserver *server); query_status_t deal_with_fl_packet(struct qserver *server, char *rawpkt, int pktlen); #endif qstat-2.15/bfbc2.c0000644000175000017500000000506412420765615010655 00000000000000/* * qstat * by Steve Jankowski * * Battlefield Bad Company 2 query protocol * Copyright 2009 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" query_status_t send_bfbc2_request_packet( struct qserver *server ) { char buf[50]; int size = 0; switch ( server->challenge ) { case 0: // Initial connect send serverInfo size = 27; memcpy( buf, "\x00\x00\x00\x00\x1b\x00\x00\x00\x01\x00\x00\x00\x0a\x00\x00\x00serverInfo\x00", size ); break; case 1: // All Done send quit size = 21; memcpy( buf, "\x01\x00\x00\x00\x15\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00quit\x00", size ); break; case 2: return DONE_FORCE; } debug( 3, "send_bfbc2_request_packet: state = %ld", server->challenge ); return send_packet( server, buf, size ); } query_status_t deal_with_bfbc2_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s, *end, *crlf; int size, words, word = 0; debug( 2, "processing..." ); if ( 17 > pktlen ) { // Invalid packet return REQ_ERROR; } rawpkt[pktlen-1] = '\0'; end = &rawpkt[pktlen-1]; s = rawpkt; server->ping_total = time_delta( &packet_recv_time, &server->packet_time1 ); server->n_requests++; // Header Sequence s += 4; // Packet Size size = *(int*)s; s += 4; // Num Words words = *(int*)s; s += 4; // Words while ( words > 0 && s + 5 < end ) { // Size int ws = *(int*)s; s += 4; // Content debug( 6, "word: %s\n", s ); switch ( word ) { case 0: // Status break; case 1: // Server Name // prevent CR & LF in the server name crlf = strchr( s, '\015' ); if ( NULL != crlf ) { *crlf = '\0'; } crlf = strchr( s, '\012' ); if ( NULL != crlf ) { *crlf = '\0'; } server->server_name = strdup( s ); break; case 2: // Player Count server->num_players = atoi( s ); break; case 3: // Max Players server->max_players = atoi( s ); break; case 4: // Game Mode add_rule( server, "gametype", s, NO_FLAGS ); break; case 5: // Map server->map_name = strdup( s ); break; } word++; s += ws + 1; words--; } server->challenge++; gettimeofday( &server->packet_time1, NULL ); if ( 1 == server->challenge ) { send_bfbc2_request_packet( server ); return INPROGRESS; } return DONE_FORCE; } qstat-2.15/dirtybomb.c0000644000175000017500000002024312420765614011665 00000000000000/* * qstat * by Steve Jankowski * * DirtyBomb query protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #include #else #include #endif #include #include #include #include "debug.h" #include "utils.h" #include "qstat.h" #include "md5.h" #include "packet_manip.h" int unpack_msgpack(struct qserver *server, unsigned char *, unsigned char *); query_status_t send_dirtybomb_request_packet(struct qserver *server) { char buf[1024], *password, chunks, len; password = get_param_value(server, "password", ""); len = strlen(password); chunks = 0x01; if (server->flags & TF_RULES_QUERY) { chunks |= 0x02; } if (server->flags & TF_PLAYER_QUERY) { chunks |= 0x04; // Player chunks |= 0x08; // Team - Currently not supported } sprintf(buf, "%c%c%s%c", 0x01, len, password, chunks); server->saved_data.pkt_max = -1; return send_packet(server, buf, len + 3); } query_status_t deal_with_dirtybomb_packet(struct qserver *server, char *rawpkt, int pktlen) { unsigned char *s, *l, pkt_id, pkt_max; debug(2, "processing..."); if (8 > pktlen) { // not valid response malformed_packet(server, "packet too small"); return PKT_ERROR; } if (rawpkt[4] != 0x01) { // not a known response malformed_packet(server, "unknown packet type 0x%02hhx", rawpkt[4]); return PKT_ERROR; } // Response ID - long // Response Type - byte // Current Packet Number - byte pkt_id = rawpkt[5]; // Last Packet Number - byte pkt_max = rawpkt[6]; // Payload Blob - msgpack map s = (unsigned char*)rawpkt + 7; if (!server->combined) { int pkt_cnt = packet_count(server); server->retry1 = n_retries; if (0 == server->n_requests) { server->ping_total = time_delta( &packet_recv_time, &server->packet_time1 ); server->n_requests++; } if (pkt_cnt < pkt_max) { // We're expecting more to come debug( 5, "fragment recieved..." ); 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); } } // Correct ping // Not quite right but gives a good estimate server->ping_total = (server->ping_total * server->n_requests) / 2; debug(3, "processing response..."); gettimeofday(&server->packet_time1, NULL); l = (unsigned char *)rawpkt + pktlen - 1; if (!unpack_msgpack(server, s, l)) { return PKT_ERROR; } return DONE_FORCE; } int unpack_msgpack_pos_fixnum(struct qserver *server, uint8_t *val, unsigned char **datap, unsigned char *last, int raw) { if (!raw) { if (*datap > last) { malformed_packet(server, "packet too small"); return 0; } if ((**datap & 0x80) != 0) { malformed_packet(server, "invalid positive fixnum type 0x%02hhx", **datap); return 0; } } *val = **datap; (*datap)++; return 1; } int unpack_msgpack_uint16(struct qserver *server, uint16_t *val, unsigned char **datap, unsigned char *last, int raw) { if (!raw) { if (*datap > last) { malformed_packet(server, "packet too small"); return 0; } if (**datap != 0xcd) { malformed_packet(server, "invalid uint16 type 0x%02hhx", **datap); return 0; } (*datap)++; } if (*datap + 2 > last) { malformed_packet(server, "packet too small"); return 0; } *val = (uint16_t)(*datap)[1] | ((uint16_t)(*datap)[0] << 8); *datap += 2; return 1; } int unpack_msgpack_uint32(struct qserver *server, uint32_t *val, unsigned char **datap, unsigned char *last, int raw) { if (!raw) { if (*datap > last) { malformed_packet(server, "packet too small"); return 0; } if (**datap != 0xce) { malformed_packet(server, "invalid uint32 type 0x%02hhx", **datap); return 0; } (*datap)++; } if (*datap + 4 > last) { malformed_packet(server, "packet too small"); return 0; } *val = (uint32_t)(*datap)[3] | ((uint32_t)(*datap)[2] << 8) | ((uint32_t)(*datap)[1] << 16) | ((uint32_t)(*datap)[0] << 24); *datap += 2; return 1; } int unpack_msgpack_raw_len(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last, uint32_t len) { char *data; debug(4, "raw_len: 0x%lu\n", (unsigned long)len); if (*datap + len > last) { malformed_packet(server, "packet too small"); return 0; } if (NULL == (data = malloc(len + 1))) { malformed_packet(server, "out of memory"); return 0; } memcpy(data, *datap, len); data[len] = '\0'; *valp = data; (*datap) += len; return 1; } int unpack_msgpack_raw(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last) { unsigned char type, len; if (*datap + 1 > last) { malformed_packet(server, "packet too small"); return 0; } type = (**datap & 0xa0); len = (**datap & 0x1f); if (0xa0 != type) { malformed_packet(server, "invalid raw type 0x%02hhx", **datap); return 0; } (*datap)++; return unpack_msgpack_raw_len(server, valp, datap, last, (uint32_t)len); } int unpack_msgpack_raw16(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last) { uint16_t len; if (*datap + 3 > last) { malformed_packet(server, "packet too small"); return 0; } (*datap)++; if (!unpack_msgpack_uint16(server, &len, datap, last, 1)) return 0; return unpack_msgpack_raw_len(server, valp, datap, last, (uint32_t)len); } int unpack_msgpack_raw32(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last) { uint32_t len; if (*datap + 5 > last) { malformed_packet(server, "packet too small"); return 0; } (*datap)++; if (!unpack_msgpack_uint32(server, &len, datap, last, 1)) return 0; return unpack_msgpack_raw_len(server, valp, datap, last, len); } int unpack_msgpack_string(struct qserver *server, char **valp, unsigned char **datap, unsigned char *last) { unsigned char type = **datap; debug(4, "string: 0x%02hhx\n", type); if (0xa0 == (type & 0xa0)) return unpack_msgpack_raw(server, valp, datap, last); else if (type == 0xda) return unpack_msgpack_raw16(server, valp, datap, last); else if (type == 0xdb) return unpack_msgpack_raw32(server, valp, datap, last); else malformed_packet(server, "invalid string type 0x%02hhx", type); return 0; } int unpack_msgpack(struct qserver *server, unsigned char *s, unsigned char *l) { uint16_t elements; unsigned char type, type_len; char *var, *str_val; uint8_t uint8_val; type_len = *s; s++; debug(3, "type/len: 0x%02hhx\n", type_len); if (0x80 == (type_len & 0x80)) { type = (type_len & 0x80); elements = (type_len & 0x0f); debug(3, "map type: 0x%02hhx, elements: %d\n", type, elements); } else if (type_len == 0xde) { // map 16 if (!unpack_msgpack_uint16(server, &elements, &s, l, 1)) return 0; } else { // There is a map 32 but we don't support it malformed_packet(server, "invalid map type 0x%02hhx", type_len); return 0; } while(elements) { type = *s; if (!unpack_msgpack_string(server, &var, &s, l)) return 0; debug(4, "Map[%s]\n", var); if (0 == strcmp(var, "SN")) { // Server Name if (!unpack_msgpack_string(server, &str_val, &s, l)) return 0; server->server_name = str_val; } else if (0 == strcmp(var, "MAP")) { // Map if (!unpack_msgpack_string(server, &str_val, &s, l)) return 0; server->map_name = str_val; } else if (0 == strcmp(var, "MP")) { // Max Players if (!unpack_msgpack_pos_fixnum(server, &uint8_val, &s, l, 0)) return 0; server->max_players = uint8_val; } else if (0 == strcmp(var, "NP")) { // Number of Players if (!unpack_msgpack_pos_fixnum(server, &uint8_val, &s, l, 0)) return 0; server->num_players = uint8_val; } else if (0 == strcmp(var, "RL")) { // Gametype if (!unpack_msgpack_string(server, &str_val, &s, l)) return 0; server->game = str_val; add_rule(server, "gametype", str_val, NO_FLAGS); } else if (0 == strcmp(var, "SFT")) { // Current Frametime in ms if (!unpack_msgpack_pos_fixnum(server, &uint8_val, &s, l, 0)) return 0; } else { debug(4, "Unknown setting '%s'\n", var); s++; } free(var); elements--; } return 1; } qstat-2.15/ut2004.c0000644000175000017500000003614412420765614010637 00000000000000/* * qstat * by Steve Jankowski * * UT2004 master query functions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms * * This code is inspired by ideas from 'Nurulwai' * */ #include #ifndef _WIN32 #include #endif #include #include #include "debug.h" #include "qstat.h" #include "md5.h" /** \brief convert bytes into hex string * * \param in data to convert * \param len length of data * \param out location to store string to. Must be 2*len */ static void bin2hex(const char* in, size_t len, char* out); #define CD_KEY_LENGTH 23 // arbitrary #define MAX_LISTING_RECORD_LEN 0x04FF #define RESPONSE_OFFSET_CDKEY 5 #define RESPONSE_OFFSET_CHALLENGE 39 static const char challenge_response[] = { 0x68, 0x00, 0x00, 0x00, '!', 0xCD, 0xCD, 0xCD, /* length | ! MD5SUM, CD is placeholder */ 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0x00, '!', 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0x00, 0x0c, 'U', 'T', '2', 'K', '4', 'C', 'L', /*^^ 12 byte string */ 'I', 'E', 'N', 'T', 0x00, 0xfb, 0x0c, 0x00, /* | unknown */ 0x00, 0x06, 0x04, 'i', 'n', 't', 0x00, 0x00, /* | ^^ 4 byte string | ? */ 0x00, 0x00, 0x00, 0xee, 0xee, 0x00, 0x00, 0x11, /* unknown */ 0x00, 0x00, 0x00, 0x01 }; static const char approved[] = { 0x0e, 0x00, 0x00, 0x00, 0x09, 'A', 'P', 'P', 'R', 'O', 'V', 'E', 'D', 0x00, 0x03, 0x00, 0x00, 0x00 }; static const char approved_response[] = { 0x22, 0x00, 0x00, 0x00, '!', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', 0x00 }; static const char verified[] = { 0x0a, 0x00, 0x00, 0x00, 0x09, 'V', 'E', 'R', 'I', 'F', 'I', 'E', 'D', 0x00 }; #if 0 struct server_listing_record_head { unsigned len; unsigned ip; short port; short queryport; char name[]; // char map[] }; struct server_listing_record_foot { unsigned char marker1[3]; unsigned char unknown1; unsigned char maxplayers; unsigned char unknown2[4]; unsigned char marker2[3]; }; #endif static char cdkey[CD_KEY_LENGTH+1] = ""; enum ut2004_state { STATE_CHALLENGE = 0x00, STATE_APPROVED = 0x01, STATE_VERIFIED = 0x02, STATE_LISTING = 0x03, }; query_status_t send_ut2004master_request_packet(struct qserver *server) { int ret; if(server->n_packets) { return DONE_FORCE; } if(!*cdkey) { char* param = get_param_value( server, "cdkey", NULL); if(!param) { debug(0, "Error: missing cdkey parameter"); server->server_name = SYSERROR; return PKT_ERROR; } if(*param == '/') { FILE* fp = fopen(param, "r"); if(!fp || fread(cdkey, 1, CD_KEY_LENGTH, fp) != CD_KEY_LENGTH) { debug(0, "Error: can't key from %s", param); server->server_name = SYSERROR; if(fp) { fclose(fp); } return PKT_ERROR; } fclose(fp); } else if(strchr(param, '-') && strlen(param) == CD_KEY_LENGTH) { memcpy(cdkey, param, CD_KEY_LENGTH); } else if( *param == '$' && (param = getenv(param+1)) // replaces param! && strlen(param) == CD_KEY_LENGTH) { memcpy(cdkey, param, CD_KEY_LENGTH); } else { debug(0, "Error: invalid cdkey parameter"); server->server_name = SYSERROR; return PKT_ERROR; } } ret = qserver_send(server, NULL, 0); #if 0 // XXX since we do not send but rather expect a reply directly after // connect it's pointless to retry doing nothing debug(0, "retry1: %d", server->retry1); server->retry1 = 0; #endif server->master_query_tag[0] = STATE_CHALLENGE; return ret; } static void ut2004_server_done(struct qserver* server) { if(server->saved_data.next) { debug(0, "%d bytes of unprocessed data left. Premature EOF!?", server->saved_data.next->datalen); free(server->saved_data.next->data); free(server->saved_data.next); server->saved_data.next = NULL; } } // we use n_servers to store number of used bytes in master_pkt so // it needs to be divided by 6 when finished static void ut2004_parse_record(struct qserver* server, char* pkt) { char* dest; #if 0 unsigned ip; unsigned short port; memcpy(&ip, pkt+4, 4); port = swap_short_from_little(pkt+4+4); debug(2, "got %d.%d.%d.%d:%hu", ip&0xff, (ip>>8)&0xff, (ip>>16)&0xff, (ip>>24)&0xff, port); #endif if(server->n_servers+6 > server->master_pkt_len) { if(!server->master_pkt_len) { server->master_pkt_len = 180; } else { server->master_pkt_len *= 2; } server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len); } dest = server->master_pkt + server->n_servers; memcpy(dest, pkt+4, 4 ); dest[4] = pkt[9]; dest[5] = pkt[8]; server->n_servers += 6; } static char* put_bytes(char* buf, const char* bytes, size_t len, size_t* left) { if(!buf || len > *left) return NULL; memcpy(buf, bytes, len); *left -= len; return buf+len; } static char* put_string(char* buf, const char* string, size_t* left) { size_t len = strlen(string)+1; char l; if(!buf || len > 0xFF || *left < len+1) return NULL; l = len; buf = put_bytes(buf, &l, 1, left); return put_bytes(buf, string, len, left); } /** \brief assemble the server filter and send the master query the query consists of four bytes length (excluding the four length bytes), a null byte and then the number of item pairs that follow. Each pair consists of two ut2 strings (length+null terminated string) followed by a byte which is either zero or 0x04 which means negate the query (e.g. not zero curplayers means not empty). */ static int ut2004_send_query(struct qserver* server) { char buf[4096] = {0}; size_t left = sizeof(buf); char *b = buf; char *param, *r, *sep= ""; unsigned flen = 0; unsigned char items = 0; // header is done later b += 6; left -= 6; param = get_param_value( server, "gametype", NULL); if(param) { ++items; b = put_string(b, "gametype", &left); b = put_string(b, param, &left); b = put_bytes(b, "", 1, &left); } param = get_param_value( server, "status", NULL); r = param; while ( param && sep ) { sep= strchr( r, ':'); if ( sep ) flen= sep-r; else flen= strlen(r); if ( strncmp( r, "standard", flen) == 0 || strncmp( r, "nostandard", flen) == 0) { ++items; b = put_string(b, "standard", &left); if(*r == 'n') b = put_string(b, "false", &left); else b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } else if ( strncmp( r, "password", flen) == 0 || strncmp( r, "nopassword", flen) == 0) { ++items; b = put_string(b, "password", &left); if(*r == 'n') b = put_string(b, "false", &left); else b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } else if ( strncmp( r, "notempty", flen) == 0) { ++items; b = put_string(b, "currentplayers", &left); b = put_string(b, "0", &left); b = put_bytes(b, "\x04", 1, &left); } else if ( strncmp( r, "notfull", flen) == 0) { ++items; b = put_string(b, "freespace", &left); b = put_string(b, "0", &left); b = put_bytes(b, "\x04", 1, &left); } else if ( strncmp( r, "nobots", flen) == 0) { ++items; b = put_string(b, "nobots", &left); b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } else if ( strncmp( r, "stats", flen) == 0 || strncmp( r, "nostats", flen) == 0) { ++items; b = put_string(b, "stats", &left); if(*r == 'n') b = put_string(b, "false", &left); else b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } else if ( strncmp( r, "weaponstay", flen) == 0 || strncmp( r, "noweaponstay", flen) == 0) { ++items; b = put_string(b, "weaponstay", &left); if(*r == 'n') b = put_string(b, "false", &left); else b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } else if ( strncmp( r, "transloc", flen) == 0 || strncmp( r, "notransloc", flen) == 0) { ++items; b = put_string(b, "transloc", &left); if(*r == 'n') b = put_string(b, "false", &left); else b = put_string(b, "true", &left); b = put_bytes(b, "", 1, &left); } r= sep+1; } param = get_param_value( server, "mutator", NULL); r = param; sep = ""; while ( param && sep ) { char neg = '\0'; unsigned char l; sep= strchr( r, ':'); if ( sep ) flen= sep-r; else flen= strlen(r); if(*r == '-') { neg = '\x04'; ++r; --flen; } if(!flen) continue; b = put_string(b, "mutator", &left); l = flen+1; b = put_bytes(b, (char*)&l, 1, &left); b = put_bytes(b, r, flen, &left); b = put_bytes(b, "", 1, &left); b = put_bytes(b, &neg, 1, &left); ++items; r= sep+1; } if(!b) { debug(0, "Error: query buffer too small. Please file a bug report!"); return 0; } put_long_little(b-buf-4, buf); buf[5] = items; return (qserver_send(server, buf, sizeof(buf)-left) > 0); } query_status_t deal_with_ut2004master_packet(struct qserver *server, char *rawpkt, int pktlen) { unsigned char* state = (unsigned char*)&server->master_query_tag[0]; md5_state_t md5; if(!pktlen) { ut2004_server_done(server); goto cleanup_out; } server->ping_total+= time_delta( &packet_recv_time, &server->packet_time1); switch(*state) { case STATE_CHALLENGE: // ensure at least one byte challenge, fit into buffer, // match challenge, null terminated if( pktlen < 4 +1 +1 +1 || pktlen > 4 +1 +8 +1 || rawpkt[pktlen-1] != '\0') { malformed_packet(server, "invalid challenge" ); goto cleanup_out; } else { char response[sizeof(challenge_response)]; char* challenge = rawpkt+5; char sum[16]; memcpy(response, challenge_response, sizeof(challenge_response)); debug(2, "challenge: %s", challenge); md5_init(&md5); md5_append(&md5, (unsigned char*)cdkey, CD_KEY_LENGTH); md5_finish(&md5, (unsigned char*)sum); bin2hex(sum, 16, response+RESPONSE_OFFSET_CDKEY); md5_init(&md5); md5_append(&md5, (unsigned char*)cdkey, CD_KEY_LENGTH); md5_append(&md5, (unsigned char*)challenge, strlen(challenge)); md5_finish(&md5, (unsigned char*)sum); bin2hex(sum, 16, response+RESPONSE_OFFSET_CHALLENGE); if(qserver_send(server, response, sizeof(response))) goto cleanup_out; server->server_name = MASTER; *state = STATE_APPROVED; } break; case STATE_APPROVED: if(pktlen != sizeof(approved) || 0 != memcmp(rawpkt, approved, pktlen)) { malformed_packet(server, "CD key not approved" ); goto cleanup_out; } debug(2, "got approval, sending verify"); if(qserver_send(server, approved_response, sizeof(approved_response))) goto cleanup_out; *state = STATE_VERIFIED; break; case STATE_VERIFIED: if(pktlen != sizeof(verified) || 0 != memcmp(rawpkt, verified, pktlen)) { malformed_packet(server, "CD key not verified" ); goto cleanup_out; } debug(2, "CD key verified, sending query"); if(ut2004_send_query(server)) goto cleanup_out; *state = STATE_LISTING; break; case STATE_LISTING: // first packet. contains number of servers to expect if(!server->saved_data.pkt_id) { /* server->saved_data.data = malloc(pktlen); memcpy(server->saved_data.data, rawpkt, pktlen); server->saved_data.datalen = pktlen; */ server->saved_data.pkt_id = 1; if(pktlen == 9) { unsigned num = swap_long_from_little(rawpkt+4); debug(2, "expect %u servers", num); #if 1 if(num < 10000) { server->master_pkt_len = num*6; server->master_pkt = (char*)realloc(server->master_pkt, server->master_pkt_len); } #endif } } else if(pktlen < 4) { malformed_packet(server, "packet too short"); goto cleanup_out; } else { char* p = rawpkt; unsigned recordlen = 0; if(server->saved_data.next) { unsigned need = 0; SavedData* data = server->saved_data.next; // nasty, four bytes of record length are split up. since // we alloc'ed at least four bytes we just copy the 4-x // bytes to data->data if(data->datalen < 4) { need = 4 - data->datalen; debug(2, "need %d bytes more for recordlen", need); if( need > pktlen) { // XXX ok, im lazy now. Stupid server can't even // send four bytes in a row malformed_packet(server, "chunk too small"); goto cleanup_out; } memcpy(data->data+data->datalen, p, need); p += need; data->datalen = 4; } recordlen = swap_long_from_little(data->data); if(!recordlen || recordlen > MAX_LISTING_RECORD_LEN) { malformed_packet(server, "record lengthx %x out of range, position %d", recordlen, (int)(p-rawpkt)); goto cleanup_out; } need = 4+recordlen - data->datalen; debug(2, "recordlen: %d, saved: %d, pkglen: %d, needed: %d", recordlen, data->datalen, pktlen, need); if( need <= pktlen) { data->data = realloc(data->data, 4+recordlen); memcpy(data->data + data->datalen, p, need); ut2004_parse_record(server, data->data); p += need; free(data->data); free(data); server->saved_data.next = NULL; } } while(!server->saved_data.next && p-rawpkt+4 < pktlen) { recordlen = swap_long_from_little(p); // record too large if(!recordlen || recordlen > MAX_LISTING_RECORD_LEN) { malformed_packet(server, "record length %x out of range, position %d", recordlen, (int)(p-rawpkt)); goto cleanup_out; } // recordlen itself is four bytes recordlen += 4; // record fully inside packet if(p-rawpkt+recordlen <= pktlen) { ut2004_parse_record(server, p); p += recordlen; } else break; } // record continues in next packet. save it. if(p-rawpkt < pktlen) { SavedData* data = server->saved_data.next; unsigned tosave = pktlen - (p-rawpkt); if(!data) { data = malloc(sizeof(SavedData)); data->data = malloc(tosave<4?4:tosave); // alloc at least four bytes data->datalen = tosave; memcpy(data->data, p, data->datalen); data->next = NULL; server->saved_data.next = data; debug(1, "saved %d bytes", data->datalen ); } else { data->data = realloc(data->data, data->datalen + tosave ); memcpy(data->data+data->datalen, p, tosave); data->datalen += tosave; debug(1, "saved %d bytes (+)", data->datalen ); } } } break; } debug(2, "%d servers total", server->n_servers/6); return INPROGRESS; cleanup_out: server->master_pkt_len = server->n_servers; server->n_servers /= 6; return DONE_FORCE; } static const char hexchar[] = "0123456789abcdef"; static void bin2hex(const char* in, size_t len, char* out) { char* o = out+len*2; in += len; do { *--o = hexchar[*--in&0x0F]; *--o = hexchar[(*in>>4)&0x0F]; } while(o != out); } // vim: sw=4 ts=4 noet qstat-2.15/gs3.h0000644000175000017500000000101612420765614010370 00000000000000/* * qstat * by Steve Jankowski * * New Gamespy v3 query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_GS3_H #define QSTAT_GS3_H #include "qserver.h" // Packet processing methods query_status_t deal_with_gs3_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t deal_with_gs3_status( struct qserver *server, char *rawpkt, int pktlen ); query_status_t send_gs3_request_packet( struct qserver *server ); #endif qstat-2.15/terraria.h0000644000175000017500000000070712420765614011513 00000000000000/* * qstat * by Steve Jankowski * * Terraria / TShock protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_TERRARIA_H #define QSTAT_TERRARIA_H #include "qserver.h" // Packet processing methods query_status_t deal_with_terraria_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_terraria_request_packet( struct qserver *server ); #endif qstat-2.15/qstat.h0000644000175000017500000040307412420765614011042 00000000000000/* * qstat.h * by Steve Jankowski * steve@qstat.org * http://www.qstat.org * * Copyright 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski */ #ifndef __H_QSTAT #define __H_QSTAT #ifdef HAVE_CONFIG_H #include "gnuconfig.h" #else #ifndef VERSION #define VERSION "2.15" #endif #endif #ifdef __EMX__ #include #include #define strcasecmp stricmp #define strncasecmp strnicmp #endif #ifdef _WIN32 # include # include # define PATH_MAX MAX_PATH # include # define _POSIX_ 1 # ifndef FD_SETSIZE # define FD_SETSIZE 256 # endif # define close(a) closesocket(a) static int gettimeofday(struct timeval *now, void *blah) { struct timeb timeb; ftime( &timeb); now->tv_sec= timeb.time; now->tv_usec= (unsigned int)timeb.millitm * 1000; return 0; } # define sockerr() WSAGetLastError() # define strcasecmp stricmp # define strncasecmp strnicmp # define STATIC # ifndef EADDRINUSE # define EADDRINUSE WSAEADDRINUSE # endif # define snprintf _snprintf #else # include # define SOCKET_ERROR -1 #endif /* _WIN32 */ #include typedef struct _server_type server_type; #ifdef __GNUC__ #define GCC_FORMAT_PRINTF(a, b) __attribute__ ((format (printf, a, b))) #else #define GCC_FORMAT_PRINTF(a, b) #endif typedef enum { INPROGRESS = 0, DONE_AUTO = 1, DONE_FORCE = 2, SYS_ERROR = -1, MEM_ERROR = -2, PKT_ERROR = -3, ORD_ERROR = -4, REQ_ERROR = -5 } query_status_t; #include "qserver.h" typedef void (*DisplayFunc)( struct qserver *); typedef query_status_t (*QueryFunc)( struct qserver *); typedef query_status_t (*PacketFunc)( struct qserver *, char *rawpkt, int pktlen); // Packet modules #include "ut2004.h" #include "doom3.h" #include "a2s.h" #include "fl.h" #include "gps.h" #include "gs2.h" #include "gs3.h" #include "haze.h" #include "ts2.h" #include "ts3.h" #include "tm.h" #include "wic.h" #include "ottd.h" #include "tee.h" #include "cube2.h" #include "bfbc2.h" #include "ventrilo.h" #include "mumble.h" #include "terraria.h" #include "crysis.h" #include "dirtybomb.h" #include "starmade.h" #include "farmsim.h" #include "ksp.h" /* * Various magic numbers. */ #define Q_DEFAULT_PORT 26000 #define HEXEN2_DEFAULT_PORT 26900 #define Q2_DEFAULT_PORT 27910 #define Q3_DEFAULT_PORT 27960 #define Q2_MASTER_DEFAULT_PORT 27900 #define Q3_MASTER_DEFAULT_PORT 27950 #define QW_DEFAULT_PORT 27500 #define QW_MASTER_DEFAULT_PORT 27000 #define HW_DEFAULT_PORT 26950 #define HW_MASTER_DEFAULT_PORT 26900 #define UNREAL_DEFAULT_PORT 7777 #define UNREAL_MASTER_DEFAULT_PORT 28900 #define HALFLIFE_DEFAULT_PORT 27015 #define HL_MASTER_DEFAULT_PORT 27010 #define SIN_DEFAULT_PORT 22450 #define SHOGO_DEFAULT_PORT 27888 #define TRIBES_DEFAULT_PORT 28001 #define TRIBES_MASTER_DEFAULT_PORT 28000 #define BFRIS_DEFAULT_PORT 44001 #define KINGPIN_DEFAULT_PORT 31510 #define HERETIC2_DEFAULT_PORT 28910 #define SOF_DEFAULT_PORT 28910 #define GAMESPY_MASTER_DEFAULT_PORT 28900 #define TRIBES2_DEFAULT_PORT 28000 #define TRIBES2_MASTER_DEFAULT_PORT 28002 #define DESCENT3_GAMESPY_DEFAULT_PORT 20142 #define DESCENT3_DEFAULT_PORT 2092 #define DESCENT3_MASTER_DEFAULT_PORT 3445 #define RTCW_DEFAULT_PORT 27960 #define RTCW_MASTER_DEFAULT_PORT 27950 #define STEF_DEFAULT_PORT 27960 #define STEF_MASTER_DEFAULT_PORT 27953 #define JK3_DEFAULT_PORT 29070 #define JK3_MASTER_DEFAULT_PORT 29060 #define GHOSTRECON_PLAYER_DEFAULT_PORT 2346 #define RAVENSHIELD_DEFAULT_PORT 8777 #define SAVAGE_DEFAULT_PORT 11235 #define FARCRY_DEFAULT_PORT 49001 #define STEAM_MASTER_DEFAULT_PORT 27010 #define HL2_DEFAULT_PORT 27015 #define HL2_MASTER_DEFAULT_PORT 27011 #define TS2_DEFAULT_PORT 51234 #define TS3_DEFAULT_PORT 10011 #define BFBC2_DEFAULT_PORT 48888 #define TM_DEFAULT_PORT 5000 #define WIC_DEFAULT_PORT 5000 // Default is actually disabled #define FL_DEFAULT_PORT 5478 #define VENTRILO_DEFAULT_PORT 3784 #define CUBE2_DEFAULT_PORT 28785 #define MUMBLE_DEFAULT_PORT 64738 #define TERRARIA_DEFAULT_PORT 7777 #define CRYSIS_DEFAULT_PORT 64087 #define DIRTYBOMB_DEFAULT_PORT 7877 #define STARMADE_DEFAULT_PORT 4242 #define FARMSIM_DEFAULT_PORT 10828 #define KSP_DEFAULT_PORT 6702 #define Q_UNKNOWN_TYPE 0 #define MASTER_SERVER 0x40000000 #define Q_SERVER 1 #define QW_SERVER 2 #define QW_MASTER (3 | MASTER_SERVER) #define H2_SERVER 4 #define Q2_SERVER 5 #define Q2_MASTER (6|MASTER_SERVER) #define HW_SERVER 7 #define UN_SERVER 8 #define UN_MASTER (9|MASTER_SERVER) #define HL_SERVER 10 #define HL_MASTER (11|MASTER_SERVER) #define SIN_SERVER 12 #define SHOGO_SERVER 13 #define TRIBES_SERVER 14 #define TRIBES_MASTER (15|MASTER_SERVER) #define Q3_SERVER 16 #define Q3_MASTER (17|MASTER_SERVER) #define BFRIS_SERVER 18 #define KINGPIN_SERVER 19 #define HERETIC2_SERVER 20 #define SOF_SERVER 21 #define GAMESPY_PROTOCOL_SERVER 22 #define GAMESPY_MASTER (23|MASTER_SERVER) #define TRIBES2_SERVER 24 #define TRIBES2_MASTER (25|MASTER_SERVER) #define DESCENT3_GAMESPY_SERVER 26 #define DESCENT3_PXO_SERVER 27 #define DESCENT3_SERVER 28 #define DESCENT3_MASTER (29|MASTER_SERVER) #define RTCW_SERVER 30 #define RTCW_MASTER (31|MASTER_SERVER) #define STEF_SERVER 32 #define STEF_MASTER (33|MASTER_SERVER) #define UT2003_SERVER 34 #define GHOSTRECON_SERVER 35 #define ALLSEEINGEYE_PROTOCOL_SERVER 36 #define RAVENSHIELD_SERVER 37 #define SAVAGE_SERVER 38 #define FARCRY_SERVER 39 #define GAMESPY2_PROTOCOL_SERVER 40 #define STEAM_MASTER (41|MASTER_SERVER) #define JK3_SERVER 42 #define JK3_MASTER (43|MASTER_SERVER) #define DOOM3_SERVER 44 #define DOOM3_MASTER (45|MASTER_SERVER) #define HL2_SERVER 46 #define HL2_MASTER (47|MASTER_SERVER) #define UT2004_MASTER (48|MASTER_SERVER) #define A2S_SERVER 49 #define PARIAH_SERVER 50 #define GAMESPY3_PROTOCOL_SERVER 51 #define TS2_PROTOCOL_SERVER 52 #define QUAKE4_SERVER 53 #define QUAKE4_MASTER (53|MASTER_SERVER) #define ARMYOPS_SERVER 54 #define GAMESPY4_PROTOCOL_SERVER 55 #define PREY_SERVER 56 #define TM_PROTOCOL_SERVER 57 #define ETQW_SERVER 58 #define HAZE_SERVER 59 #define HW_MASTER (60 | MASTER_SERVER) #define WIC_PROTOCOL_SERVER 61 #define OTTD_SERVER 62 #define OTTD_MASTER (63 | MASTER_SERVER) #define FL_SERVER 64 #define WOLF_SERVER 65 #define TEE_SERVER 66 #define TS3_PROTOCOL_SERVER 67 #define BFBC2_PROTOCOL_SERVER 68 #define VENTRILO_PROTOCOL_SERVER 69 #define CUBE2_SERVER 70 #define MUMBLE_PROTOCOL_SERVER 71 #define TERRARIA_PROTOCOL_SERVER 72 #define CRYSIS_PROTOCOL_SERVER 73 #define DIRTYBOMB_PROTOCOL_SERVER 74 #define STARMADE_PROTOCOL_SERVER 75 #define FARMSIM_PROTOCOL_SERVER 76 #define KSP_PROTOCOL_SERVER 77 #define LAST_BUILTIN_SERVER 77 #define TF_SINGLE_QUERY (1<<1) #define TF_OUTFILE (1<<2) #define TF_MASTER_MULTI_RESPONSE (1<<3) #define TF_TCP_CONNECT (1<<4) #define TF_QUERY_ARG (1<<5) #define TF_QUERY_ARG_REQUIRED (1<<6) #define TF_QUAKE3_NAMES (1<<7) #define TF_TRIBES2_NAMES (1<<8) #define TF_SOF_NAMES (1<<9) #define TF_U2_NAMES (1<<10) #define TF_RAW_STYLE_QUAKE (1<<11) #define TF_RAW_STYLE_TRIBES (1<<12) #define TF_RAW_STYLE_GHOSTRECON (1<<13) #define TF_NO_PORT_OFFSET (1<<14) #define TF_SHOW_GAME_PORT (1<<15) #define TF_MASTER_STEAM (1<<16) /* supports steam server filter */ // What response type are we expecting // XXX: this is not what server->flags is for #define TF_STATUS_QUERY (1<<17) #define TF_PLAYER_QUERY (1<<18) #define TF_RULES_QUERY (1<<19) #define TF_TM_NAMES (1<<20) #define TRIBES_TEAM -1 struct q_packet; /* * Output and formatting functions */ void display_server( struct qserver *server); void display_qwmaster( struct qserver *server); void display_server_rules( struct qserver *server); void display_player_info( struct qserver *server); void display_q_player_info( struct qserver *server); void display_qw_player_info( struct qserver *server); void display_q2_player_info( struct qserver *server); void display_unreal_player_info( struct qserver *server); void display_shogo_player_info( struct qserver *server); void display_halflife_player_info( struct qserver *server); void display_tribes_player_info( struct qserver *server); void display_tribes2_player_info( struct qserver *server); void display_bfris_player_info( struct qserver *server); void display_descent3_player_info( struct qserver *server); void display_ravenshield_player_info( struct qserver *server); void display_savage_player_info( struct qserver *server); void display_farcry_player_info( struct qserver *server); void display_ghostrecon_player_info( struct qserver *server); void display_eye_player_info( struct qserver *server); void display_armyops_player_info( struct qserver *server); void display_gs2_player_info( struct qserver *server); void display_doom3_player_info( struct qserver *server); void display_ts2_player_info( struct qserver *server); void display_ts3_player_info( struct qserver *server); void display_bfbc2_player_info( struct qserver *server); void display_tm_player_info( struct qserver *server); void display_wic_player_info( struct qserver *server); void display_fl_player_info( struct qserver *server); void display_tee_player_info( struct qserver *server); void display_ventrilo_player_info( struct qserver *server); void display_starmade_player_info( struct qserver *server); void raw_display_server( struct qserver *server); void raw_display_server_rules( struct qserver *server); void raw_display_player_info( struct qserver *server); void raw_display_q_player_info( struct qserver *server); void raw_display_qw_player_info( struct qserver *server); void raw_display_q2_player_info( struct qserver *server); void raw_display_unreal_player_info( struct qserver *server); void raw_display_halflife_player_info( struct qserver *server); void raw_display_tribes_player_info( struct qserver *server); void raw_display_tribes2_player_info( struct qserver *server); void raw_display_bfris_player_info( struct qserver *server); void raw_display_ravenshield_player_info( struct qserver *server); void raw_display_savage_player_info( struct qserver *server); void raw_display_farcry_player_info( struct qserver *server); void raw_display_descent3_player_info( struct qserver *server); void raw_display_ghostrecon_player_info( struct qserver *server); void raw_display_eye_player_info( struct qserver *server); void raw_display_armyops_player_info( struct qserver *server); void raw_display_gs2_player_info( struct qserver *server); void raw_display_doom3_player_info( struct qserver *server); void raw_display_ts2_player_info( struct qserver *server); void raw_display_ts3_player_info( struct qserver *server); void raw_display_bfbc2_player_info( struct qserver *server); void raw_display_tm_player_info( struct qserver *server); void raw_display_wic_player_info( struct qserver *server); void raw_display_fl_player_info( struct qserver *server); void raw_display_tee_player_info( struct qserver *server); void raw_display_ventrilo_player_info( struct qserver *server); void raw_display_starmade_player_info( struct qserver *server); void xml_display_server( struct qserver *server); void xml_header(); void xml_footer(); void xml_display_server_rules( struct qserver *server); void xml_display_player_info( struct qserver *server); void xml_display_q_player_info( struct qserver *server); void xml_display_qw_player_info( struct qserver *server); void xml_display_q2_player_info( struct qserver *server); void xml_display_unreal_player_info( struct qserver *server); void xml_display_halflife_player_info( struct qserver *server); void xml_display_tribes_player_info( struct qserver *server); void xml_display_tribes2_player_info( struct qserver *server); void xml_display_ravenshield_player_info( struct qserver *server); void xml_display_savage_player_info( struct qserver *server); void xml_display_farcry_player_info( struct qserver *server); void xml_display_bfris_player_info( struct qserver *server); void xml_display_descent3_player_info( struct qserver *server); void xml_display_ghostrecon_player_info( struct qserver *server); void xml_display_eye_player_info( struct qserver *server); void xml_display_armyops_player_info( struct qserver *server); void xml_display_player_info( struct qserver *server); void xml_display_doom3_player_info( struct qserver *server); void xml_display_ts2_player_info( struct qserver *server); void xml_display_ts3_player_info( struct qserver *server); void xml_display_bfbc2_player_info( struct qserver *server); void xml_display_tm_player_info( struct qserver *server); void xml_display_wic_player_info( struct qserver *server); void xml_display_fl_player_info( struct qserver *server); void xml_display_tee_player_info( struct qserver *server); void xml_display_ventrilo_player_info( struct qserver *server); void xml_display_starmade_player_info( struct qserver *server); char *xml_escape( char*); query_status_t send_qserver_request_packet( struct qserver *server); query_status_t send_qwserver_request_packet( struct qserver *server); query_status_t send_ut2003_request_packet( struct qserver *server); query_status_t send_tribes_request_packet( struct qserver *server); query_status_t send_qwmaster_request_packet( struct qserver *server); query_status_t send_bfris_request_packet( struct qserver *server); query_status_t send_player_request_packet( struct qserver *server); query_status_t send_rule_request_packet( struct qserver *server); query_status_t send_savage_request_packet( struct qserver *server); query_status_t send_farcry_request_packet( struct qserver *server); query_status_t send_gamespy_master_request( struct qserver *server); query_status_t send_tribes2_request_packet( struct qserver *server); query_status_t send_tribes2master_request_packet( struct qserver *server); query_status_t send_hl2_request_packet( struct qserver *server); query_status_t deal_with_q_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_qw_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_q1qw_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_q2_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t deal_with_qwmaster_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_halflife_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_ut2003_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_tribes_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_tribesmaster_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_bfris_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_gamespy_master_response( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_ravenshield_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_savage_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_farcry_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_tribes2_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_tribes2master_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_descent3_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_descent3master_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_ghostrecon_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_eye_packet( struct qserver *server, char *pkt, int pktlen); query_status_t deal_with_hl2_packet( struct qserver *server, char *pkt, int pktlen); struct _server_type { int id; char *type_prefix; char *type_string; char *type_option; char *game_name; int master; unsigned short default_port; unsigned short port_offset; int flags; char *game_rule; char *template_var; char *status_packet; int status_len; char *player_packet; int player_len; char *rule_packet; int rule_len; char *master_packet; int master_len; char *master_protocol; char *master_query; DisplayFunc display_player_func; DisplayFunc display_rule_func; DisplayFunc display_raw_player_func; DisplayFunc display_raw_rule_func; DisplayFunc display_xml_player_func; DisplayFunc display_xml_rule_func; QueryFunc status_query_func; QueryFunc rule_query_func; QueryFunc player_query_func; PacketFunc packet_func; }; extern server_type builtin_types[]; extern server_type *types; extern int n_server_types; extern server_type* default_server_type; server_type* find_server_type_string( char* type_string); #ifdef QUERY_PACKETS #undef QUERY_PACKETS /* QUAKE */ struct q_packet { unsigned char flag1; unsigned char flag2; unsigned short length; unsigned char op_code; unsigned char data[19]; }; #define Q_HEADER_LEN 5 /* struct { unsigned char flag1; unsigned char flag2; unsigned short length; unsigned char op_code; char name[6]; unsigned char version; }; */ #define Q_FLAG1 0x80 #define Q_FLAG2 0x00 #define Q_CCREQ_SERVER_INFO 0x02 #define Q_CCREQ_PLAYER_INFO 0x03 #define Q_CCREQ_RULE_INFO 0x04 /* The \003 below is the protocol version */ #define Q_SERVERINFO_LEN 12 struct q_packet q_serverinfo = { Q_FLAG1, Q_FLAG2, Q_SERVERINFO_LEN, Q_CCREQ_SERVER_INFO, "QUAKE\000\003" }; struct q_packet q_rule = {Q_FLAG1,Q_FLAG2, 0, Q_CCREQ_RULE_INFO, ""}; struct q_packet q_player = {Q_FLAG1,Q_FLAG2, 6, Q_CCREQ_PLAYER_INFO, ""}; /* QUAKE WORLD */ struct { char prefix[4]; char command[10]; } qw_serverstatus = { { '\377', '\377', '\377', '\377' }, { 's', 't', 'a', 't', 'u', 's', ' ', '2', '3', '\n' } }; /* QUAKE3 */ struct { char prefix[4]; char command[10]; } q3_serverstatus = { { '\377', '\377', '\377', '\377' }, { 'g', 'e', 't', 's', 't', 'a', 't', 'u', 's', '\n' } }; struct { char prefix[4]; char command[8]; } q3_serverinfo = { { '\377', '\377', '\377', '\377' }, { 'g', 'e', 't', 'i', 'n', 'f', 'o', '\n' } }; /* DOOM 3 */ struct { char prefix[2]; char command[12]; } doom3_serverinfo = { { '\377', '\377' }, { 'g', 'e', 't', 'I', 'n', 'f', 'o', '\0', '\0', '\0', '\0', '\0' } }; /* HALF-LIFE 2 */ char hl2_serverinfo[20] = { '\xFF', '\xFF', '\xFF', '\xFF', 'T', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; char hl2_playerinfo[20] = { '\xFF', '\xFF', '\xFF', '\xFF', 'U', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; char hl2_ruleinfo[20] = { '\xFF', '\xFF', '\xFF', '\xFF', 'V', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' }; /* HEXEN WORLD */ struct { char prefix[5]; char command[7]; } hw_serverstatus = { { '\377', '\377', '\377', '\377', '\377' }, { 's', 't', 'a', 't', 'u', 's', '\n' } }; /* HEXEN 2 */ /* The \004 below is the protocol version */ #define H2_SERVERINFO_LEN 14 struct q_packet h2_serverinfo = { Q_FLAG1, Q_FLAG2, H2_SERVERINFO_LEN, Q_CCREQ_SERVER_INFO, "HEXENII\000\004" }; /* UNREAL */ char unreal_serverstatus[8] = { '\\', 's','t','a','t','u','s', '\\' }; /* char unreal_serverstatus[] = { '\\', 's','t','a','t','u','s', '\\', '\\', 'p','l','a','y','e','r','s', '\\', '\\' }; */ char unreal_masterlist[23] = "\\list\\\\gamename\\unreal"; /* UT 2003 */ char ut2003_basicstatus[] = { 0x78, 0,0,0, 0 }; //char ut2003_ruleinfo[] = { 0x78, 0,0,0, 1 }; //char ut2003_playerinfo[] = { 0x78, 0,0,0, 2 }; char ut2003_allinfo[] = { 0x78, 0,0,0, 3 }; /* Pariah */ char pariah_basicstatus[] = { 0x77, 0,0,0, 0x13 }; /* HALF LIFE */ char hl_ping[9] = { '\377', '\377', '\377', '\377', 'p', 'i', 'n', 'g', '\0' }; char hl_rules[10] = { '\377', '\377', '\377', '\377', 'r', 'u', 'l', 'e', 's', '\0' }; char hl_info[9] = { '\377', '\377', '\377', '\377', 'i', 'n', 'f', 'o', '\0' }; char hl_players[12] = { '\377', '\377', '\377', '\377', 'p', 'l', 'a', 'y', 'e', 'r', 's', '\0' }; char hl_details[12] = { '\377', '\377', '\377', '\377', 'd', 'e', 't', 'a', 'i', 'l', 's', '\0' }; /* QUAKE WORLD MASTER */ #define QW_GET_SERVERS 'c' char qw_masterquery[] = { QW_GET_SERVERS, '\n', '\0' }; /* HEXENWORLD MASTER */ #define HW_GET_SERVERS 'c' char hw_masterquery[] = { '\377', HW_GET_SERVERS, '\0' }; /* QUAKE 2 MASTER */ char q2_masterquery[] = { 'q', 'u', 'e', 'r', 'y', '\n', '\0' }; /* QUAKE 3 MASTER */ char q3_master_query_template[] = "\377\377\377\377getservers %s %s"; char q3_master_default_protocol[] = "68"; char q3_master_default_query[] = "empty full demo\n"; /* RETURN TO CASTLE WOLFENSTEIN */ char rtcw_master_default_protocol[] = "60"; /* STAR TREK: ELITE FORCE */ char stef_master_default_protocol[] = "24"; /* JEDI KNIGHT: JEDI ACADEMY */ char jk3_master_default_protocol[] = "26"; /* HALF-LIFE MASTER */ char hl_masterquery[4] = { 'e', '\0', '\0', '\0' }; char new_hl_masterquery_prefix[5] = { '1', '\0', '\0', '\0', '\0' }; /* 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 }; /* GAMESPY */ char gamespy_master_request_prefix[] = "\\list\\\\gamename\\"; char gamespy_master_validate[] = "\\gamename\\gamespy2\\gamever\\020109017\\location\\5\\validate\\12345678\\final\\"; /* TRIBES 2 */ #define TRIBES2_QUERY_GAME_TYPES 2 #define TRIBES2_QUERY_MASTER 6 #define TRIBES2_QUERY_PING 14 #define TRIBES2_QUERY_INFO 18 #define TRIBES2_RESPONSE_GAME_TYPES 4 #define TRIBES2_RESPONSE_MASTER 8 #define TRIBES2_RESPONSE_PING 16 #define TRIBES2_RESPONSE_INFO 20 #define TRIBES2_NO_COMPRESS 2 #define TRIBES2_DEFAULT_PACKET_INDEX 255 #define TRIBES2_STATUS_DEDICATED (1<<0) #define TRIBES2_STATUS_PASSWORD (1<<1) #define TRIBES2_STATUS_LINUX (1<<2) #define TRIBES2_STATUS_TOURNAMENT (1<<3) #define TRIBES2_STATUS_NOALIAS (1<<4) #define TRIBES2_STATUS_TEAMDAMAGE (1<<5) #define TRIBES2_STATUS_TOURNAMENT_VER3 (1<<6) #define TRIBES2_STATUS_NOALIAS_VER3 (1<<7) char tribes2_game_types_request[] = { TRIBES2_QUERY_GAME_TYPES, 0, 1,2,3,4 }; char tribes2_ping[] = { TRIBES2_QUERY_PING, TRIBES2_NO_COMPRESS, 1,2,3,4 }; char tribes2_info[] = { TRIBES2_QUERY_INFO, TRIBES2_NO_COMPRESS, 1,2,3,4 }; unsigned char tribes2_masterquery[] = { TRIBES2_QUERY_MASTER, 128, /* <= build 22228, this was 0 */ 11,12,13,14, 255, 3, 'a', 'n', 'y', 3, 'a', 'n', 'y', 0, 255, /* min/max players */ 0xff, 0xff, 0xff, 0xff, /* region mask */ 0, 0, 0, 0, /* build version */ 0, /* status */ 255, /* max bots */ 0, 0, /* min cpu */ 0 /* # buddies */ }; #define TRIBES2_ID_OFFSET 2 unsigned char descent3_masterquery[] = { 0x03, /* ID or something */ 0x24, 0x00, 0x00, 0x00, /* packet len */ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* unknown */ 0x07, /* type */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* unknown */ 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x00 /* "global" */ }; /* for some reason Descent3 uses a different request for pxo/non-pxo games. blah. */ unsigned char descent3_pxoinfoquery[] = { 0x01, /* "internal descent3 routing" */ 0x29, /* request server info? (pxo listed servers) */ 0x0b, 0x00, /* packet length (- routing byte) */ 0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */ }; unsigned char descent3_tcpipinfoquery[] = { 0x01, /* "internal descent3 routing" */ 0x1e, /* request server info? (tcpip only servers) */ 0x0b, 0x00, /* packet length (- routing byte) */ 0x1b, 0x2f, 0xf4, 0x41, 0x09, 0x00, 0x00, 0x00 /* unknown */ }; /* http://ml.warpcore.org/d3dl/200101/msg00001.html * http://ml.warpcore.org/d3dl/200101/msg00004.html */ unsigned char descent3_playerquery[] = { 0x01, /* "internal descent3 routing" */ 0x72, /* MP_REQUEST_PLAYERLIST */ 0x03, 0x00 /* packet length (- routing byte) */ }; unsigned char ghostrecon_serverquery[] = { 0xc0,0xde,0xf1,0x11, /* const ? header */ 0x42, /* start flag */ 0x03,0x00, /* data len */ 0xe9,0x03,0x00 /* server request ?? */ }; unsigned char ghostrecon_playerquery[] = { 0xc0,0xde,0xf1,0x11, /* const ? header */ 0x42, /* start flag */ 0x06,0x00, /* data len */ 0xf5,0x03,0x00,0x78,0x30,0x63 /* player request ?? may be flag 0xf5; len 0x03,0x00; data 0x78, 0x30, 0x63 */ }; /* All Seeing Eye */ char eye_status_query[1]= "s"; char eye_ping_query[1]= "p"; // Gamespy v2 // Format: // 1 - 3: query head // 4 - 7: queryid // 8: server + rules info (00 to disable) // 9: Player information (00 to disable) // 10: Team information (00 to disable) unsigned char gs2_status_query[] = { 0xfe,0xfd,0x00,0x10,0x20,0x30,0x40,0xff,0xff,0xff }; // Gamespy v3 // Format: // 1 - 3: query head // 4 - 7: queryid // 8: server + rules info (00 to disable) // 9: Player information (00 to disable) // 10: Team information (00 to disable) // 11: Request new format unsigned char gs3_player_query[] = { 0xfe,0xfd,0x00, 0x10,0x20,0x30,0x40, 0xff,0xff,0xff,0x01 }; // Format: // 1 - 3: query head // 4 - 7: queryid // 8: requested number of rules // 9 - 9 + no_rules: requested ruleid // last 2 : terminator? // Known ruleid's: // 0x01: hostname // 0x03: version // 0x04: hostport // 0x05: map // 0x06: gametype // 0x07: gamevarient // 0x08: num_players // 0x0a: max_players // 0x0b: gamemode unsigned char gs3_status_query[] = { 0xfe,0xfd,0x00, 0x10,0x20,0x30,0x40, 0x06,0x01,0x06,0x05,0x08,0x0a,0x04,0x00,0x00 }; // Gamespy v3 + challenge // Format: // 1 - 3: query head // 4 - 7: queryid unsigned char gs3_challenge[] = { 0xfe,0xfd,0x09, 0x10,0x20,0x30,0x40 }; // Format: // 1 - 8: Query Request // 9 - 12: Query Header // 13: Query ID // Query ID is made up of the following // 0x01: Basic Info // 0x02: Game Rules // 0x03: Player Information // 0x04: Team Information unsigned char haze_status_query[] = { 'f', 'r', 'd', 'q', 'u', 'e', 'r', 'y', 0x10,0x20,0x30,0x40, 0x0A }; // Format: // 1 - 8: Query Request // 9 - 12: Query Header // 13: Query ID // Query ID is made up of the following // 0x01: Basic Info // 0x02: Game Rules // 0x03: Player Information // 0x04: Team Information unsigned char haze_player_query[] = { 'f', 'r', 'd', 'q', 'u', 'e', 'r', 'y', 0x10,0x20,0x30,0x40, 0x03 }; // Steam // Format: // 1. Request type ( 1 byte ) // 2. Region ( 1 byte ) // 3. ip ( string + null ) // 4. Filter ( optional + null ) // // Regions: // 0 = US East Coast // 1 = US West Coast // 2 = South America // 3 = Europe // 4 = Asia // 5 = Australia // 6 = Middle East // 7 = Africa // 255 = N/A // Filter: // \type\d = Returns only dedicated servers // // \secure\1 = Returns servers running anti-cheat technology // // \gamedir\[mod] = Servers running the specified modification. // The parameter is the directory that the mod resides in e.g. // cstrike for Counter-Strike or dod for Day of Defeat. // // \map\[map] = Returns servers running the specified map // (e.g. de_dust2 or cs_italy) // // \linux\1 = Servers running on the Linux platform // // \empty\1 = Servers that are not empty // // \full\1 = Servers that are not full // // \proxy\1 = Servers that are spectator proxies // // End the filter with 0x00 // unsigned char steam_masterquery_template[] = "1%c%s%c%s"; 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 }; unsigned char farcry_serverquery[] = { 0x08,0x80 }; char ravenshield_serverquery[] = "REPORT"; char ottd_master_query[] = { 0x04, 0x00, // packet length 0x06, // packet type 0x01 // packet version }; char ottd_serverinfo[] = { 0x03, 0x00, // packet length 0x00, // packet type }; char ottd_serverdetails[] = { 0x03, 0x00, // packet length 0x02, // packet type }; /* Teeworlds */ char tee_serverstatus[14] = { '\x20', '\0', '\0', '\0', '\0', '\0', '\xFF', '\xFF', '\xFF', '\xFF', 'g', 'i', 'e', 'f' }; /* Cube2 */ char cube2_serverstatus[3] = {'\x80', '\x10', '\x27'}; /* Mumble */ char mumble_serverstatus[12] = {'\x00', '\x00', '\x00', '\x00', '\x01', '\x02', '\x03', '\x04', '\x05', '\x06', '\x07', '\x08' }; /* Terraria */ char terraria_serverstatus[] = "GET /v2/server/status HTTP/1.1\x0d\x0a\x0d\x0a"; /* SERVER BUILTIN TYPES */ server_type builtin_types[] = { { /* QUAKE */ Q_SERVER, /* id */ "QS", /* type_prefix */ "qs", /* type_string */ "-qs", /* type_option */ "Quake", /* game_name */ 0, /* master */ Q_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_RAW_STYLE_QUAKE, /* flags */ "*gamedir", /* game_rule */ "QUAKE", /* template_var */ (char*) &q_serverinfo, /* status_packet */ Q_SERVERINFO_LEN, /* status_len */ (char*) &q_player, /* player_packet */ Q_HEADER_LEN+1, /* player_len */ (char*) &q_rule, /* rule_packet */ sizeof( q_rule), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_q_packet, /* packet_func */ }, { /* HEXEN 2 */ H2_SERVER, /* id */ "H2S", /* type_prefix */ "h2s", /* type_string */ "-h2s", /* type_option */ "Hexen II", /* game_name */ 0, /* master */ HEXEN2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_RAW_STYLE_QUAKE, /* flags */ "*gamedir", /* game_rule */ "HEXEN2", /* template_var */ (char*) &h2_serverinfo, /* status_packet */ H2_SERVERINFO_LEN, /* status_len */ (char*) &q_player, /* player_packet */ Q_HEADER_LEN+1, /* player_len */ (char*) &q_rule, /* rule_packet */ sizeof( q_rule), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_q_packet, /* packet_func */ }, { /* QUAKE WORLD */ QW_SERVER, /* id */ "QWS", /* type_prefix */ "qws", /* type_string */ "-qws", /* type_option */ "QuakeWorld", /* game_name */ 0, /* master */ QW_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "*gamedir", /* game_rule */ "QUAKEWORLD", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qw_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_qw_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_qw_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* HEXEN WORLD */ HW_SERVER, /* id */ "HWS", /* type_prefix */ "hws", /* type_string */ "-hws", /* type_option */ "HexenWorld", /* game_name */ 0, /* master */ HW_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "*gamedir", /* game_rule */ "HEXENWORLD", /* template_var */ (char*) &hw_serverstatus, /* status_packet */ sizeof( hw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qw_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_qw_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_qw_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* QUAKE 2 */ Q2_SERVER, /* id */ "Q2S", /* type_prefix */ "q2s", /* type_string */ "-q2s", /* type_option */ "Quake II", /* game_name */ 0, /* master */ Q2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gamedir", /* game_rule */ "QUAKE2", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* QUAKE 3 */ Q3_SERVER, /* id */ "Q3S", /* type_prefix */ "q3s", /* type_string */ "-q3s", /* type_option */ "Quake III: Arena", /* game_name */ 0, /* master */ Q3_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES /* TF_SINGLE_QUERY */, /* flags */ "game", /* game_rule */ "QUAKE3", /* template_var */ (char*) &q3_serverinfo, /* status_packet */ sizeof( q3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &q3_serverstatus, /* rule_packet */ sizeof( q3_serverstatus), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* DOOM 3 */ DOOM3_SERVER, /* id */ "DM3S", /* type_prefix */ "dm3s", /* type_string */ "-dm3s", /* type_option */ "Doom 3", /* game_name */ 0, /* master */ DOOM3_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "fs_game", /* game_rule */ "DOOM3", /* template_var */ (char*) &doom3_serverinfo, /* status_packet */ sizeof( doom3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_doom3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_doom3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_doom3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_doom3_packet, /* packet_func */ }, { /* HALFLIFE 2 */ HL2_SERVER, /* id */ "HL2S", /* type_prefix */ "hl2s", /* type_string */ "-hl2s", /* type_option */ "Half-Life 2", /* game_name */ 0, /* master */ HL2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "", /* game_rule */ "HL2", /* template_var */ (char*) &hl2_serverinfo, /* status_packet */ sizeof( hl2_serverinfo), /* status_len */ (char*) &hl2_playerinfo, /* player_packet */ sizeof( hl2_playerinfo), /* player_len */ (char*) &hl2_ruleinfo, /* rule_packet */ sizeof( hl2_ruleinfo), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_halflife_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_halflife_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_halflife_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_hl2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_hl2_packet, /* packet_func */ }, { /* RETURN TO CASTLE WOLFENSTEIN */ RTCW_SERVER, /* id */ "RWS", /* type_prefix */ "rws", /* type_string */ "-rws", /* type_option */ "Return to Castle Wolfenstein", /* game_name */ 0, /* master */ RTCW_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES /* TF_SINGLE_QUERY */, /* flags */ "game", /* game_rule */ "RTCW", /* template_var */ (char*) &q3_serverinfo, /* status_packet */ sizeof( q3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &q3_serverstatus, /* rule_packet */ sizeof( q3_serverstatus), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* STAR TREK: ELITE FORCE */ STEF_SERVER, /* id */ "EFS", /* type_prefix */ "efs", /* type_string */ "-efs", /* type_option */ "Star Trek: Elite Force", /* game_name */ 0, /* master */ STEF_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES /* TF_SINGLE_QUERY */, /* flags */ "game", /* game_rule */ "ELITEFORCE", /* template_var */ (char*) &q3_serverinfo, /* status_packet */ sizeof( q3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &q3_serverstatus, /* rule_packet */ sizeof( q3_serverstatus), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* JEDI KNIGHT: JEDI ACADEMY */ JK3_SERVER, /* id */ "JK3S", /* type_prefix */ "jk3s", /* type_string */ "-jk3s", /* type_option */ "Jedi Knight: Jedi Academy", /* game_name */ 0, /* master */ JK3_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES /* TF_SINGLE_QUERY */, /* flags */ "game", /* game_rule */ "JEDIKNIGHT3", /* template_var */ (char*) &q3_serverinfo, /* status_packet */ sizeof( q3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &q3_serverstatus, /* rule_packet */ sizeof( q3_serverstatus), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* UNREAL TOURNAMENT 2003 */ UT2003_SERVER, /* id */ "UT2S", /* type_prefix */ "ut2s", /* type_string */ "-ut2s", /* type_option */ "Unreal Tournament 2003", /* game_name */ 0, /* master */ UNREAL_DEFAULT_PORT, /* default_port */ 1, /* port_offset */ TF_U2_NAMES, /* flags */ "gametype", /* game_rule */ "UNREALTOURNAMENT2003", /* template_var */ (char*) &ut2003_basicstatus,/* status_packet */ sizeof( ut2003_basicstatus),/* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &ut2003_allinfo, /* rule_packet */ sizeof( ut2003_allinfo), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ 0, /* master_query */ display_unreal_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_unreal_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_unreal_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ut2003_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ut2003_packet, /* packet_func */ }, { /* UNREAL */ UN_SERVER, /* id */ "UNS", /* type_prefix */ "uns", /* type_string */ "-uns", /* type_option */ "Unreal", /* game_name */ 0, /* master */ UNREAL_DEFAULT_PORT, /* default_port */ 1, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "UNREAL", /* template_var */ (char*) &unreal_serverstatus, /* status_packet */ sizeof( unreal_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_unreal_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_unreal_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_unreal_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gps_packet, /* packet_func */ }, { /* HALF LIFE */ HL_SERVER, /* id */ "HLS", /* type_prefix */ "hls", /* type_string */ "-hls", /* type_option */ "Half-Life", /* game_name */ 0, /* master */ HALFLIFE_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "game", /* game_rule */ "HALFLIFE", /* template_var */ (char*) &hl_details, /* status_packet */ sizeof( hl_details), /* status_len */ (char*) &hl_players, /* player_packet */ sizeof( hl_players), /* player_len */ (char*) &hl_rules, /* rule_packet */ sizeof( hl_rules), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_halflife_player_info,/* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_halflife_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_halflife_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_halflife_packet, /* packet_func */ }, { /* SIN */ SIN_SERVER, /* id */ "SNS", /* type_prefix */ "sns", /* type_string */ "-sns", /* type_option */ "Sin", /* game_name */ 0, /* master */ SIN_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gamedir", /* game_rule */ "SIN", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* SHOGO */ SHOGO_SERVER, /* id */ "SGS", /* type_prefix */ "sgs", /* type_string */ "-sgs", /* type_option */ "Shogo: Mobile Armor Division", /* game_name */ 0, /* master */ SHOGO_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "", /* game_rule */ "SHOGO", /* template_var */ (char*) &unreal_serverstatus, /* status_packet */ sizeof( unreal_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gps_packet, /* packet_func */ }, { /* 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 */ }, { /* BFRIS */ BFRIS_SERVER, /* id */ "BFS", /* type_prefix */ "bfs", /* type_string */ "-bfs", /* type_option */ "BFRIS", /* game_name */ 0, /* master */ BFRIS_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "Rules", /* game_rule */ "BFRIS", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_bfris_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_bfris_player_info,/* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_bfris_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_bfris_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_bfris_packet, /* packet_func */ }, { /* KINGPIN */ KINGPIN_SERVER, /* id */ "KPS", /* type_prefix */ "kps", /* type_string */ "-kps", /* type_option */ "Kingpin", /* game_name */ 0, /* master */ KINGPIN_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gamedir", /* game_rule */ "KINGPIN", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* HERETIC II */ HERETIC2_SERVER, /* id */ "HRS", /* type_prefix */ "hrs", /* type_string */ "-hrs", /* type_option */ "Heretic II", /* game_name */ 0, /* master */ HERETIC2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gamedir", /* game_rule */ "HERETIC2", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* SOLDIER OF FORTUNE */ SOF_SERVER, /* id */ "SFS", /* type_prefix */ "sfs", /* type_string */ "-sfs", /* type_option */ "Soldier of Fortune", /* game_name */ 0, /* master */ SOF_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_SOF_NAMES, /* flags */ "gamedir", /* game_rule */ "SOLDIEROFFORTUNE", /* template_var */ (char*) &qw_serverstatus, /* status_packet */ sizeof( qw_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_q2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qw_packet, /* packet_func */ }, { /* GAMESPY PROTOCOL */ GAMESPY_PROTOCOL_SERVER, /* id */ "GPS", /* type_prefix */ "gps", /* type_string */ "-gps", /* type_option */ "Gamespy Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_U2_NAMES, /* flags */ "gametype", /* game_rule */ "GAMESPYPROTOCOL", /* template_var */ (char*) &unreal_serverstatus, /* status_packet */ sizeof( unreal_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_unreal_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_unreal_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_unreal_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gps_packet, /* packet_func */ }, { /* TRIBES 2 */ TRIBES2_SERVER, /* id */ "T2S", /* type_prefix */ "t2s", /* type_string */ "-t2s", /* type_option */ "Tribes 2", /* game_name */ 0, /* master */ TRIBES2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "game", /* game_rule */ "TRIBES2", /* template_var */ (char*) &tribes2_ping, /* status_packet */ sizeof( tribes2_ping), /* status_len */ (char*) &tribes2_info, /* player_packet */ sizeof( tribes2_info), /* player_len */ (char*) NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_tribes2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_tribes2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_tribes2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_tribes2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_tribes2_packet, /* packet_func */ }, { /* DESCENT3 GAMESPY PROTOCOL */ DESCENT3_GAMESPY_SERVER, /* id */ "D3G", /* type_prefix */ "d3g", /* type_string */ "-d3g", /* type_option */ "Descent3 Gamespy Protocol", /* game_name */ 0, /* master */ DESCENT3_GAMESPY_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "DESCENT3", /* template_var */ (char*) &unreal_serverstatus, /* status_packet */ sizeof( unreal_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_descent3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_descent3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_descent3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gps_packet, /* packet_func */ }, { /* DESCENT3 PROTOCOL */ DESCENT3_SERVER, /* id */ "D3S", /* type_prefix */ "d3s", /* type_string */ "-d3s", /* type_option */ "Descent3", /* game_name */ 0, /* master */ DESCENT3_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gametype", /* game_rule */ "DESCENT3", /* template_var */ (char*) &descent3_tcpipinfoquery, /* status_packet */ sizeof( descent3_tcpipinfoquery), /* status_len */ (char*) &descent3_playerquery, /* player_packet */ sizeof( descent3_playerquery), /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_descent3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_descent3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_descent3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_descent3_packet, /* packet_func */ }, { /* DESCENT3 PROTOCOL */ DESCENT3_PXO_SERVER, /* id */ "D3P", /* type_prefix */ "d3p", /* type_string */ "-d3p", /* type_option */ "Descent3 PXO protocol", /* game_name */ 0, /* master */ DESCENT3_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gametype", /* game_rule */ "DESCENT3", /* template_var */ (char*) &descent3_pxoinfoquery, /* status_packet */ sizeof( descent3_pxoinfoquery), /* status_len */ (char*) &descent3_playerquery, /* player_packet */ sizeof( descent3_playerquery), /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_descent3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_descent3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_descent3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gps_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_descent3_packet, /* packet_func */ }, { /* GHOSTRECON PROTOCOL */ GHOSTRECON_SERVER, /* id */ "GRS", /* type_prefix */ "grs", /* type_string */ "-grs", /* type_option */ "Ghost Recon", /* game_name */ 0, /* master */ GHOSTRECON_PLAYER_DEFAULT_PORT, /* default_port */ 2, /* port_offset */ TF_QUERY_ARG, /* flags */ "gametype", /* game_rule */ "GHOSTRECON", /* template_var */ (char*) &ghostrecon_playerquery, /* status_packet */ sizeof( ghostrecon_playerquery), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_ghostrecon_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_ghostrecon_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_ghostrecon_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ghostrecon_packet, /* packet_func */ }, { /* ALL SEEING EYE PROTOCOL */ ALLSEEINGEYE_PROTOCOL_SERVER, /* id */ "EYE", /* type_prefix */ "eye", /* type_string */ "-eye", /* type_option */ "All Seeing Eye Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 123, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "EYEPROTOCOL", /* template_var */ (char*) &eye_status_query, /* status_packet */ sizeof( eye_status_query), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_eye_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_eye_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_eye_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_eye_packet, /* packet_func */ }, { /* GAMESPY V2 PROTOCOL */ GAMESPY2_PROTOCOL_SERVER, /* id */ "GS2", /* type_prefix */ "gs2", /* type_string */ "-gs2", /* type_option */ "Gamespy V2 Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "GPS2PROTOCOL", /* template_var */ (char*) &gs2_status_query, /* status_packet */ sizeof( gs2_status_query), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_gs2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_gs2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gs2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gs2_packet, /* packet_func */ }, { /* AMERICA'S ARMY EXTENSION (GS2 BASED) */ ARMYOPS_SERVER, /* id */ "AMS", /* type_prefix */ "ams", /* type_string */ "-ams", /* type_option */ "America's Army v2.x", /* game_name */ 0, /* master */ 1716, /* default_port */ 1, /* port_offset */ TF_SINGLE_QUERY|TF_U2_NAMES, /* flags */ "gametype", /* game_rule */ "AMERICASARMY", /* template_var */ (char*) &gs2_status_query, /* status_packet */ sizeof( gs2_status_query), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_armyops_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_armyops_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_armyops_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gs2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gs2_packet, /* packet_func */ }, { /* RAVENSHIELD PROTOCOL */ RAVENSHIELD_SERVER, /* id */ "RSS", /* type_prefix */ "rss", /* type_string */ "-rss", /* type_option */ "Ravenshield", /* game_name */ 0, /* master */ RAVENSHIELD_DEFAULT_PORT, /* default_port */ 1000, /* port_offset */ TF_QUERY_ARG, /* flags */ "gametype", /* game_rule */ "RAVENSHIELD", /* template_var */ (char*)ravenshield_serverquery, /* status_packet */ sizeof( ravenshield_serverquery ) - 1, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_ravenshield_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_ravenshield_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_ravenshield_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ravenshield_packet, /* packet_func */ }, { /* 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 */ }, { /* FARCRY PROTOCOL */ FARCRY_SERVER, /* id */ "FCS", /* type_prefix */ "fcs", /* type_string */ "-fcs", /* type_option */ "FarCry", /* game_name */ 0, /* master */ FARCRY_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUERY_ARG, /* flags */ "gametype", /* game_rule */ "FARCRY", /* template_var */ (char*)farcry_serverquery, /* status_packet */ sizeof( savage_serverquery ) - 1, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_farcry_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_farcry_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_farcry_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_farcry_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_farcry_packet, /* packet_func */ }, /* --- MASTER SERVERS --- */ { /* QUAKE WORLD MASTER */ QW_MASTER, /* id */ "QWM", /* type_prefix */ "qwm", /* type_string */ "-qwm", /* type_option */ /* ## also "-qw" */ "QuakeWorld Master", /* game_name */ QW_SERVER, /* master */ QW_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_OUTFILE, /* flags */ "", /* game_rule */ "QWMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &qw_masterquery, /* master_packet */ sizeof( qw_masterquery), /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* HEXEN2WORLD MASTER */ HW_MASTER, /* id */ "HWM", /* type_prefix */ "hwm", /* type_string */ "-hwm", /* type_option */ /* ## also "-qw" */ "HexenWorld Master", /* game_name */ HW_SERVER, /* master */ HW_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_OUTFILE, /* flags */ "", /* game_rule */ "HWMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &hw_masterquery, /* master_packet */ sizeof( hw_masterquery), /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* QUAKE 2 MASTER */ Q2_MASTER, /* id */ "Q2M", /* type_prefix */ "q2m", /* type_string */ "-q2m", /* type_option */ /* ## also "-qw" */ "Quake II Master", /* game_name */ Q2_SERVER, /* master */ Q2_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_OUTFILE, /* flags */ "", /* game_rule */ "Q2MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ q2_masterquery, /* master_packet */ sizeof( q2_masterquery), /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* QUAKE 3 MASTER */ Q3_MASTER, /* id */ "Q3M", /* type_prefix */ "q3m", /* type_string */ "-q3m", /* type_option */ "Quake III Master", /* game_name */ Q3_SERVER, /* master */ Q3_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "Q3MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ q3_master_query_template, /* master_packet */ 0, /* master_len */ q3_master_default_protocol, /* master_protocol */ q3_master_default_query, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* DOOM 3 MASTER */ DOOM3_MASTER, /* id */ "DM3M", /* type_prefix */ "dm3m", /* type_string */ "-dm3m", /* type_option */ "Doom 3 Master", /* game_name */ DOOM3_SERVER, /* master */ DOOM3_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE|TF_QUERY_ARG, /* flags */ "", /* game_rule */ "DOOM3MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_doom3master_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_doom3master_packet, /* packet_func */ }, { /* RETURN TO CASTLE WOLFENSTEIN MASTER */ RTCW_MASTER, /* id */ "RWM", /* type_prefix */ "rwm", /* type_string */ "-rwm", /* type_option */ "Return to Castle Wolfenstein Master", /* game_name */ RTCW_SERVER, /* master */ RTCW_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "RTCWMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ q3_master_query_template, /* master_packet */ 0, /* master_len */ rtcw_master_default_protocol, /* master_protocol */ q3_master_default_query, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* STAR TREK: ELITE FORCE MASTER */ STEF_MASTER, /* id */ "EFM", /* type_prefix */ "efm", /* type_string */ "-efm", /* type_option */ "Star Trek: Elite Force", /* game_name */ STEF_SERVER, /* master */ STEF_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "ELITEFORCEMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ q3_master_query_template, /* master_packet */ 0, /* master_len */ stef_master_default_protocol, /* master_protocol */ q3_master_default_query, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* JEDI KNIGHT 3 FORCE MASTER */ JK3_MASTER, /* id */ "JK3M", /* type_prefix */ "jk3m", /* type_string */ "-jk3m", /* type_option */ "Jedi Knight: Jedi Academy", /* game_name */ JK3_SERVER, /* master */ JK3_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "JK3MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ q3_master_query_template, /* master_packet */ 0, /* master_len */ jk3_master_default_protocol, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* HALF-LIFE MASTER */ HL_MASTER, /* id */ "HLM", /* type_prefix */ "hlm", /* type_string */ "-hlm", /* type_option */ /* ## also "-qw" */ "Half-Life Master", /* game_name */ HL_SERVER, /* master */ HL_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_OUTFILE|TF_QUERY_ARG, /* flags */ "", /* game_rule */ "HLMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &new_hl_masterquery_prefix, /* master_packet */ sizeof( new_hl_masterquery_prefix), /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* TRIBES MASTER */ TRIBES_MASTER, /* id */ "TBM", /* type_prefix */ "tbm", /* type_string */ "-tbm", /* type_option */ "Tribes Master", /* game_name */ TRIBES_SERVER, /* master */ TRIBES_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE, /* flags */ "", /* game_rule */ "TRIBESMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &tribes_masterquery,/* master_packet */ sizeof( tribes_masterquery),/* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_tribesmaster_packet,/* packet_func */ }, { /* GAMESPY MASTER */ GAMESPY_MASTER, /* id */ "GSM", /* type_prefix */ "gsm", /* type_string */ "-gsm", /* type_option */ "Gamespy Master", /* game_name */ GAMESPY_PROTOCOL_SERVER, /* master */ GAMESPY_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_TCP_CONNECT | TF_QUERY_ARG | TF_QUERY_ARG_REQUIRED, /* flags */ "", /* game_rule */ "GAMESPYMASTER", /* template_var */ (char*) &gamespy_master_request_prefix, /* status_packet */ sizeof( gamespy_master_request_prefix)-1, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &gamespy_master_validate,/* master_packet */ sizeof( gamespy_master_validate)-1,/* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_gamespy_master_request,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gamespy_master_response,/* packet_func */ }, { /* TRIBES 2 MASTER */ TRIBES2_MASTER, /* id */ "T2M", /* type_prefix */ "t2m", /* type_string */ "-t2m", /* type_option */ "Tribes 2 Master", /* game_name */ TRIBES2_SERVER, /* master */ TRIBES2_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "TRIBES2MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &tribes2_masterquery,/* master_packet */ sizeof( tribes2_masterquery),/* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_tribes2master_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_tribes2master_packet,/* packet_func */ }, { /* DESCENT3 MASTER */ DESCENT3_MASTER, /* id */ "D3M", /* type_prefix */ "d3m", /* type_string */ "-d3m", /* type_option */ /* ## also "-qw" */ "Descent3 Master (PXO)", /* game_name */ DESCENT3_PXO_SERVER, /* master */ DESCENT3_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_MASTER_MULTI_RESPONSE|TF_OUTFILE, /* flags */ "", /* game_rule */ "D3MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*)descent3_masterquery, /* master_packet */ sizeof( descent3_masterquery), /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_descent3master_packet, /* packet_func */ }, { /* STEAM MASTER */ STEAM_MASTER, /* id */ "STM", /* type_prefix */ "stm", /* type_string */ "-stm", /* type_option */ /* ## also "-qw" */ "Steam Master", /* game_name */ A2S_SERVER, /* master */ STEAM_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY|TF_OUTFILE|TF_QUERY_ARG|TF_MASTER_STEAM, /* flags */ "", /* game_rule */ "STEAMMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) &steam_masterquery_template, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_qwmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_qwmaster_packet, /* packet_func */ }, { /* UT2004 MASTER */ UT2004_MASTER, /* id */ "UT2004M", /* type_prefix */ "ut2004m", /* type_string */ "-ut2004m", /* type_option */ "UT2004 Master", /* game_name */ UT2003_SERVER, /* master */ 28902, /* default_port */ 0, /* port_offset */ TF_OUTFILE|TF_QUERY_ARG|TF_TCP_CONNECT, /* flags */ "", /* game_rule */ "UT2004MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_ut2004master_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ut2004master_packet, /* packet_func */ }, { /* HALFLIFE 2 */ A2S_SERVER, /* id */ "A2S", /* type_prefix */ "a2s", /* type_string */ "-a2s", /* type_option */ "Half-Life 2 new", /* game_name */ 0, /* master */ HL2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "gamedir", /* game_rule */ "A2S", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_halflife_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_halflife_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_halflife_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_a2s_request_packet, /* status_query_func */ send_a2s_rule_request_packet, /* rule_query_func */ NULL, /* player_query_func */ deal_with_a2s_packet, /* packet_func */ }, { /* PARIAH */ PARIAH_SERVER, /* id */ "PRS", /* type_prefix */ "prs", /* type_string */ "-prs", /* type_option */ "Pariah", /* game_name */ 0, /* master */ UNREAL_DEFAULT_PORT, /* default_port */ 1, /* port_offset */ TF_U2_NAMES, /* flags */ "gametype", /* game_rule */ "UNREALTOURNAMENT2003", /* template_var */ (char*) &pariah_basicstatus,/* status_packet */ sizeof( pariah_basicstatus),/* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ 0, /* master_query */ display_unreal_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_unreal_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_unreal_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ut2003_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ut2003_packet, /* packet_func */ }, { /* GAMESPY V3 PROTOCOL */ GAMESPY3_PROTOCOL_SERVER, /* id */ "GS3", /* type_prefix */ "gs3", /* type_string */ "-gs3", /* type_option */ "Gamespy V3 Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "GPS3PROTOCOL", /* template_var */ (char*) &gs3_status_query, /* status_packet */ sizeof( gs3_status_query), /* status_len */ (char*) &gs3_player_query, /* player_packet */ sizeof( gs3_player_query), /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_gs2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_gs2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gs3_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gs3_packet, /* packet_func */ }, { /* TEAMSPEAK 2 PROTOCOL */ TS2_PROTOCOL_SERVER, /* id */ "TS2", /* type_prefix */ "ts2", /* type_string */ "-ts2", /* type_option */ "Teamspeak 2", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG_REQUIRED|TF_QUERY_ARG, /* flags */ "N/A", /* game_rule */ "TS2PROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_ts2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_ts2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_ts2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ts2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ts2_packet, /* packet_func */ }, { /* QUAKE 4 */ QUAKE4_SERVER, /* id */ "Q4S", /* type_prefix */ "q4s", /* type_string */ "-q4s", /* type_option */ "Quake 4", /* game_name */ 0, /* master */ QUAKE4_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "fs_game", /* game_rule */ "QUAKE4", /* template_var */ (char*) &doom3_serverinfo, /* status_packet */ sizeof( doom3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_doom3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_doom3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_doom3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_quake4_packet, /* packet_func */ }, { /* QUAKE 4 MASTER */ QUAKE4_MASTER, /* id */ "Q4M", /* type_prefix */ "q4m", /* type_string */ "-q4m", /* type_option */ "Quake 4 Master", /* game_name */ QUAKE4_SERVER, /* master */ QUAKE4_MASTER_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_OUTFILE|TF_QUERY_ARG, /* flags */ "", /* game_rule */ "QUAKE4MASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_quake4master_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_doom3master_packet, /* packet_func */ }, { /* GAMESPY V4 PROTOCOL */ GAMESPY4_PROTOCOL_SERVER, /* id */ "GS4", /* type_prefix */ "gs4", /* type_string */ "-gs4", /* type_option */ "Gamespy V4 Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "GPS4PROTOCOL", /* template_var */ (char*) &gs3_challenge, /* status_packet */ sizeof( gs3_challenge), /* status_len */ (char*) &gs3_challenge, /* player_packet */ sizeof( gs3_challenge), /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_gs2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_gs2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_gs3_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_gs3_packet, /* packet_func */ }, { /* PREY */ PREY_SERVER, /* id */ "PREYS", /* type_prefix */ "preys", /* type_string */ "-preys", /* type_option */ "PREY", /* game_name */ 0, /* master */ PREY_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "fs_game", /* game_rule */ "PREY", /* template_var */ (char*) &doom3_serverinfo, /* status_packet */ sizeof( doom3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_doom3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_doom3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_doom3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_prey_packet, /* packet_func */ }, { /* TRACKMANIA PROTOCOL */ TM_PROTOCOL_SERVER, /* id */ "TM", /* type_prefix */ "tm", /* type_string */ "-tm", /* type_option */ "TrackMania", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG|TF_TM_NAMES, /* flags */ "N/A", /* game_rule */ "TMPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_tm_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_tm_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_tm_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_tm_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_tm_packet, /* packet_func */ }, { /* Enemy Territory : QuakeWars */ ETQW_SERVER, /* id */ "ETQWS", /* type_prefix */ "etqws", /* type_string */ "-etqws", /* type_option */ "QuakeWars", /* game_name */ 0, /* master */ ETQW_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "fs_game", /* game_rule */ "QUAKE4", /* template_var */ (char*) &doom3_serverinfo, /* status_packet */ sizeof( doom3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_doom3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_doom3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_doom3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_etqw_packet, /* packet_func */ }, { /* HAZE PROTOCOL */ HAZE_SERVER, /* id */ "HAZES", /* type_prefix */ "hazes", /* type_string */ "-hazes", /* type_option */ "Haze Protocol", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_SINGLE_QUERY, /* flags */ "gametype", /* game_rule */ "HAZE", /* template_var */ (char*) &haze_status_query, /* status_packet */ sizeof( haze_status_query), /* status_len */ (char*) &haze_player_query, /* player_packet */ sizeof( haze_player_query), /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_gs2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_gs2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_haze_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_haze_packet, /* packet_func */ }, { /* World in Confict PROTOCOL */ WIC_PROTOCOL_SERVER, /* id */ "WICS", /* type_prefix */ "wics", /* type_string */ "-wics", /* type_option */ "World in Conflict", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG_REQUIRED|TF_QUERY_ARG, /* flags */ "N/A", /* game_rule */ "WICPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_wic_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_wic_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_wic_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_wic_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_wic_packet, /* packet_func */ }, { /* openTTD */ OTTD_SERVER, /* id */ "OTTDS", /* type_prefix */ "ottds", /* type_string */ "-ottds", /* type_option */ "OpenTTD", /* game_name */ 0, /* master */ 3979, /* default_port */ 0, /* port_offset */ 0, /* flags */ "", /* game_rule */ "OPENTTD", /* template_var */ (char*) &ottd_serverinfo, /* status_packet */ sizeof( ottd_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ (char*) &ottd_serverdetails,/* rule_packet */ sizeof( ottd_serverdetails), /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_q2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_q2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info,/* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ottd_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ottd_packet, /* packet_func */ }, { /* openTTD Master */ OTTD_MASTER, /* id */ "OTTDM", /* type_prefix */ "ottdm", /* type_string */ "-ottdm", /* type_option */ "openTTD Master", /* game_name */ OTTD_SERVER, /* master */ 3978, /* default_port */ 0, /* port_offset */ TF_OUTFILE | TF_QUERY_ARG, /* flags */ "", /* game_rule */ "OTTDMASTER", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ ottd_master_query, /* master_packet */ sizeof(ottd_master_query),/* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_qwmaster, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ send_ottdmaster_request_packet,/* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ottdmaster_packet, /* packet_func */ }, { /* Frontlines-Fuel of War */ FL_SERVER, /* id */ "FLS", /* type_prefix */ "fls", /* type_string */ "-fls", /* type_option */ "Frontlines-Fuel of War", /* game_name */ 0, /* master */ FL_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "gamedir", /* game_rule */ "FLS", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_fl_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_fl_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_fl_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_fl_request_packet, /* status_query_func */ send_fl_rule_request_packet, /* rule_query_func */ NULL, /* player_query_func */ deal_with_fl_packet, /* packet_func */ }, { /* Wolfenstein */ WOLF_SERVER, /* id */ "WOLF", /* type_prefix */ "wolfs", /* type_string */ "-wolfs", /* type_option */ "Wolfenstein", /* game_name */ 0, /* master */ WOLF_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_QUAKE3_NAMES, /* flags */ "fs_game", /* game_rule */ "QUAKE4", /* template_var */ (char*) &doom3_serverinfo, /* status_packet */ sizeof( doom3_serverinfo), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_doom3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_doom3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_doom3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_qwserver_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_wolf_packet, /* packet_func */ }, { /* Teeworlds */ TEE_SERVER, /* id */ "TEE", /* type_prefix */ "tee", /* type_string */ "-tee", /* type_option */ "Teeworlds", /* game_name */ 0, /* master */ 35515, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gametype", /* game_rule */ "TEE", /* template_var */ tee_serverstatus, /* status_packet */ sizeof(tee_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_tee_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_tee_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_tee_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_tee_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_tee_packet, /* packet_func */ }, { /* TEAMSPEAK 3 PROTOCOL */ TS3_PROTOCOL_SERVER, /* id */ "TS3", /* type_prefix */ "ts3", /* type_string */ "-ts3", /* type_option */ "Teamspeak 3", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG_REQUIRED|TF_QUERY_ARG, /* flags */ "N/A", /* game_rule */ "TS3PROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_ts3_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_ts3_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_ts3_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ts3_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ts3_packet, /* packet_func */ }, { /* BATTLEFIELD BAD COMPANY 2 PROTOCOL */ BFBC2_PROTOCOL_SERVER, /* id */ "BFBC2", /* type_prefix */ "bfbc2", /* type_string */ "-bfbc2", /* type_option */ "Battlefield Bad Company 2", /* game_name */ 0, /* master */ BFBC2_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "gametype", /* game_rule */ "BFBC2PROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_bfbc2_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_bfbc2_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_bfbc2_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_bfbc2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_bfbc2_packet, /* packet_func */ }, { /* VENTRILO PROTOCOL */ VENTRILO_PROTOCOL_SERVER, /* id */ "VENTRILO", /* type_prefix */ "ventrilo", /* type_string */ "-vent", /* type_option */ "Ventrilo", /* game_name */ 0, /* master */ VENTRILO_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gametype", /* game_rule */ "VENTRILO", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_ventrilo_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_ventrilo_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_ventrilo_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ventrilo_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ventrilo_packet, /* packet_func */ }, { /* Cube 2/Sauerbraten/Blood Frontier */ CUBE2_SERVER, /* id */ "CUBE2", /* type_prefix */ "cube2", /* type_string */ "-cubes", /* type_option */ "Sauerbraten", /* game_name */ 0, /* master */ CUBE2_DEFAULT_PORT, /* default_port */ 1, /* port_offset */ 0, /* flags */ "", /* game_rule */ "CUBE2", /* template_var */ cube2_serverstatus, /* status_packet */ sizeof(cube2_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_cube2_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_cube2_packet, /* packet_func */ }, { /* MUMBLE PROTOCOL */ MUMBLE_PROTOCOL_SERVER, /* id */ "MUMBLE", /* type_prefix */ "mumble", /* type_string */ "-mumble", /* type_option */ "Mumble", /* game_name */ 0, /* master */ MUMBLE_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gametype", /* game_rule */ "MUMBLEPROTOCOL", /* template_var */ mumble_serverstatus, /* status_packet */ 12, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_mumble_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_mumble_packet, /* packet_func */ }, { /* TERRARIA PROTOCOL */ TERRARIA_PROTOCOL_SERVER, /* id */ "TERRARIA", /* type_prefix */ "terraria", /* type_string */ "-terraria", /* type_option */ "Terraria", /* game_name */ 0, /* master */ TERRARIA_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "gametype", /* game_rule */ "TERRARIPROTOCOL", /* template_var */ terraria_serverstatus, /* status_packet */ sizeof(terraria_serverstatus), /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_mumble_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_terraria_packet, /* packet_func */ }, { /* CRYSIS PROTOCOL */ CRYSIS_PROTOCOL_SERVER, /* id */ "CRYSIS", /* type_prefix */ "crysis", /* type_string */ "-crysis", /* type_option */ "Crysis", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG_REQUIRED|TF_QUERY_ARG, /* flags */ "gamerules", /* game_rule */ "CRYSISPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_crysis_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_crysis_packet, /* packet_func */ }, { /* DIRTYBOMB PROTOCOL */ DIRTYBOMB_PROTOCOL_SERVER, /* id */ "DIRTYBOMB", /* type_prefix */ "dirtybomb", /* type_string */ "-dirtybomb", /* type_option */ "DirtyBomb", /* game_name */ 0, /* master */ DIRTYBOMB_DEFAULT_PORT, /* default_port */ 0, /* port_offset */ 0, /* flags */ "gamerules", /* game_rule */ "DIRYTBOMBPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_dirtybomb_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_dirtybomb_packet, /* packet_func */ }, { /* STARMADE PROTOCOL */ STARMADE_PROTOCOL_SERVER, /* id */ "STARMADE", /* type_prefix */ "starmade", /* type_string */ "-starmade", /* type_option */ "StarMade", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "N/A", /* game_rule */ "STARMADEPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ display_starmade_player_info, /* display_player_func */ display_server_rules, /* display_rule_func */ raw_display_starmade_player_info, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_starmade_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_starmade_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_starmade_packet, /* packet_func */ }, { /* FARMSIM PROTOCOL */ FARMSIM_PROTOCOL_SERVER, /* id */ "FARMSIM", /* type_prefix */ "farmsim", /* type_string */ "-farmsim", /* type_option */ "FarmingSimulator", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT|TF_QUERY_ARG_REQUIRED|TF_QUERY_ARG, /* flags */ "gamerules", /* game_rule */ "FARMSIMPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_farmsim_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_farmsim_packet, /* packet_func */ }, { /* KSP PROTOCOL */ KSP_PROTOCOL_SERVER, /* id */ "KSP", /* type_prefix */ "ksp", /* type_string */ "-ksp", /* type_option */ "Kerbal Space Program", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ TF_TCP_CONNECT, /* flags */ "gamerules", /* game_rule */ "KSPPROTOCOL", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ display_server_rules, /* display_rule_func */ NULL, /* display_raw_player_func */ raw_display_server_rules, /* display_raw_rule_func */ xml_display_player_info, /* display_xml_player_func */ xml_display_server_rules, /* display_xml_rule_func */ send_ksp_request_packet, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ deal_with_ksp_packet, /* packet_func */ }, { Q_UNKNOWN_TYPE, /* id */ "", /* type_prefix */ "", /* type_string */ "", /* type_option */ "", /* game_name */ 0, /* master */ 0, /* default_port */ 0, /* port_offset */ 0, /* flags */ "", /* game_rule */ "", /* template_var */ NULL, /* status_packet */ 0, /* status_len */ NULL, /* player_packet */ 0, /* player_len */ NULL, /* rule_packet */ 0, /* rule_len */ (char*) NULL, /* master_packet */ 0, /* master_len */ NULL, /* master_protocol */ NULL, /* master_query */ NULL, /* display_player_func */ NULL, /* display_rule_func */ NULL, /* display_raw_player_func */ NULL, /* display_raw_rule_func */ NULL, /* display_xml_player_func */ NULL, /* display_xml_rule_func */ NULL, /* status_query_func */ NULL, /* rule_query_func */ NULL, /* player_query_func */ NULL, /* packet_func */ } }; #endif /* QUERY_PACKETS */ /* Structures for keeping information about Quake servers, server * rules, and players. */ struct player; #define FLAG_BROADCAST (1<<1) #define FLAG_PLAYER_TEAMS (1<<2) #define FLAG_DO_NOT_FREE_GAME (1<<3) #define PLAYER_TYPE_NORMAL 1 #define PLAYER_TYPE_BOT 2 #define PLAYER_TYPE_ALIAS 4 #define PLAYER_FLAG_DO_NOT_FREE_TEAM 1 struct player { int number; char *name; int frags; int team; /* Unreal and Tribes only */ char *team_name; /* Tribes, BFRIS only, do not free() */ int connect_time; int shirt_color; int pants_color; char *address; int ping; short flags; short type_flag; /* Tribes 2 only */ int packet_loss; /* Tribes only */ char *tribe_tag; /* Tribes 2 / Quake 4 clan name */ char *skin; char *mesh; /* Unreal only */ char *face; /* Unreal only */ int score; /* BFRIS only */ int ship; /* BFRIS only */ int room; /* BFRIS only */ int deaths; /* Descent3 only */ char *next_info; int n_info; struct info *info; struct info **last_info; int missing_rules; struct player *next; }; struct rule { char *name; char *value; struct rule *next; }; struct info { char *name; char *value; struct info *next; }; extern char *qstat_version; extern char *DOWN; extern char *SYSERROR; extern char *TIMEOUT; extern char *MASTER; extern char *SERVERERROR; extern char *HOSTNOTFOUND; extern int n_retries; extern struct timeval packet_recv_time; #define DEFAULT_RETRIES 3 #define DEFAULT_RETRY_INTERVAL 500 /* milli-seconds */ #define MAXFD_DEFAULT 20 #define SORT_GAME 1 #define SORT_PING 2 extern int first_sort_key; extern int second_sort_key; #define SECONDS 0 #define CLOCK_TIME 1 #define STOPWATCH_TIME 2 #define DEFAULT_TIME_FMT_RAW SECONDS #define DEFAULT_TIME_FMT_DISPLAY CLOCK_TIME extern int time_format; extern int color_names; extern int show_errors; extern int get_player_info; extern int get_server_rules; extern int no_port_offset; /* Definitions for the original Quake network protocol. */ #define PACKET_LEN 0xffff /* Quake packet formats and magic numbers */ struct qheader { unsigned char flag1; unsigned char flag2; unsigned short length; unsigned char op_code; }; #define Q_NET_PROTOCOL_VERSION 3 #define HEXEN2_NET_PROTOCOL_VERSION 4 #define Q_CCREQ_CONNECT 0x01 #define Q_CCREP_ACCEPT 0x81 #define Q_CCREP_REJECT 0x82 #define Q_CCREP_SERVER_INFO 0x83 #define Q_CCREP_PLAYER_INFO 0x84 #define Q_CCREP_RULE_INFO 0x85 #define Q_DEFAULT_SV_MAXSPEED "320" #define Q_DEFAULT_SV_FRICTION "4" #define Q_DEFAULT_SV_GRAVITY "800" #define Q_DEFAULT_NOEXIT "0" #define Q_DEFAULT_TEAMPLAY "0" #define Q_DEFAULT_TIMELIMIT "0" #define Q_DEFAULT_FRAGLIMIT "0" /* Definitions for the QuakeWorld network protocol */ /* #define QW_GET_SERVERS 'c' */ #define QW_SERVERS 'd' #define HL_SERVERS 'f' /* HL master: send 'a', master responds with a small 'l' packet containing the text "Outdated protocol" HL master: send 'e', master responds with a small 'f' packet HL master: send 'g', master responds with a small 'h' packet containing name of master server HL master: send 'i', master responds with a small 'j' packet */ #define QW_GET_USERINFO 'o' #define QW_USERINFO 'p' #define QW_GET_SEENINFO 'u' #define QW_SEENINFO 'v' #define QW_NACK 'm' #define QW_NEWLINE '\n' #define QW_RULE_SEPARATOR '\\' #define QW_REQUEST_LENGTH 20 int is_default_rule( struct rule *rule); char *xform_name( char*, struct qserver *server); char *quake_color( int color); char *play_time( int seconds, int show_seconds); char *ping_time( int ms); char *get_qw_game( struct qserver *server); /* * Query status and packet handling functions */ int cleanup_qserver( struct qserver *server, int force); void change_server_port( struct qserver *server, unsigned short port, int force ); int server_info_packet( struct qserver *server, struct q_packet *pkt, int datalen ); int player_info_packet( struct qserver *server, struct q_packet *pkt, int datalen ); int rule_info_packet( struct qserver *server, struct q_packet *pkt, int datalen ); int time_delta( struct timeval *later, struct timeval *past); char * strherror( int h_err); int connection_refused(); int connection_would_block(); int connection_reset(); void add_file( char *filename); int add_qserver( char *arg, server_type* type, char *outfilename, char *query_arg); struct qserver* add_qserver_byaddr( unsigned int ipaddr, unsigned short port, server_type* type, int *new_server); void init_qserver( struct qserver *server, server_type* type); int bind_qserver( struct qserver *server); int bind_sockets(); void send_packets(); struct qserver * find_server_by_address( unsigned int ipaddr, unsigned short port); void add_server_to_hash( struct qserver *server); #define NO_FLAGS 0 #define NO_VALUE_COPY 1 #define CHECK_DUPLICATE_RULES 2 #define NO_KEY_COPY 4 #define COMBINE_VALUES 8 #define OVERWITE_DUPLICATES 16 struct player* get_player_by_number( struct qserver *server, int player_number ); struct rule* add_rule( struct qserver *server, char *key, char *value, int flags) ; struct player* add_player( struct qserver *server, int player_number ); struct info* player_add_info( struct player *player, char *key, char *value, int flags ); void players_set_teamname( struct qserver *server, int teamid, char *teamname ); /* * Output template stuff */ int read_qserver_template( char *filename); int read_rule_template( char *filename); int read_header_template( char *filename); int read_trailer_template( char *filename); int read_player_template( char *filename); int have_server_template(); int have_header_template(); int have_trailer_template(); void template_display_server( struct qserver *server); void template_display_header(); void template_display_trailer(); void template_display_players( struct qserver *server); void template_display_player( struct qserver *server, struct player *player); void template_display_rules( struct qserver *server); void template_display_rule( struct qserver *server, struct rule *rule); /* * Host cache stuff */ int hcache_open( char *filename, int update); void hcache_write( char *filename); void hcache_invalidate(); void hcache_validate(); unsigned long hcache_lookup_hostname( char *hostname); char * hcache_lookup_ipaddr( unsigned long ipaddr); void hcache_write_file( char *filename); void hcache_update_file(); unsigned int swap_long_from_little( void *l); unsigned short swap_short_from_little( void *l); float swap_float_from_little( void *f); /** \brief write four bytes in little endian order */ void put_long_little(unsigned val, char* buf); /* * Exported Globals */ extern int show_game_port; #define NA_INT -32767 #define NO_PLAYER_INFO 0xffff #define NO_SERVER_RULES NULL #define FORCE 1 #define NO_FORCE 0 #endif qstat-2.15/mumble.h0000644000175000017500000000066412420765615011166 00000000000000/* * qstat * by Steve Jankowski * * Mumble protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_MUMBLE_H #define QSTAT_MUMBLE_H #include "qserver.h" // Packet processing methods query_status_t deal_with_mumble_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_mumble_request_packet( struct qserver *server ); #endif qstat-2.15/farmsim.h0000644000175000017500000000067012420765615011340 00000000000000/* * qstat * by Steve Jankowski * * Crysis protocol * Copyright 2012 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_FARMSIM_H #define QSTAT_FARMSIM_H #include "qserver.h" // Packet processing methods query_status_t deal_with_farmsim_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_farmsim_request_packet( struct qserver *server ); #endif qstat-2.15/ChangeLog0000644000175000017500000000117012420765614011276 00000000000000Sun Feb 23 10:52:18 PST 2003 Added $SCORE for player score Fixed XML escaping bugs Fixed repeated rule values from UT2003 servers Fixed excessive retries to UT2003 servers that set minplayers Fixed reported # players for UT2003 server that set minplayers Changed sof2m default protocol to 2004 (SOF 1.02) Tue Jan 7 16:24:57 PST 2003 Fixed manual compile instructions in COMPILE.txt Updated RTCW master protocol from 58 to 60 Added support for All-Seeing Eye protocol (-eye) [still need to write documentation] Fixed rare divide by zero displaying ping time Added information about UT2003 master server lists to info/UT2003.txt qstat-2.15/contrib.cfg0000644000175000017500000000220112420765614011641 00000000000000# QStat config file # # The following game types were contributed by QStat users. # To use, copy them into your qstat.cfg or add "-f contrib.cfg" to you # qstat command line. gametype aps new extend gps name = Alien vs Predator 2 default port = 27888 template var = AVP2 game rule = gamename end gametype uts new extend uns name = Unreal Tournament default port = 7777 template var = UNREALTOURNAMENT game rule = gametype end gametype sms new extend gps name = Serious Sam default port = 25601 template var = SERIOUSSAM game rule = gametype end gametype gos new extend gps name = Global Operations default port = 28672 template var = GLOBALOPS game rule = gamedir end gametype j2s new extend q3s name = Jedi Knight 2 default port = 28070 template var = JEDIKNIGHT2 game rule = gamename end gametype dks new extend gps name = Daikatana default port = 27992 template var = DAIKATANA game rule = gamedir end gametype vcs new extend gps name = V8 Supercar Challange default port = 16700 template var = V8SUPERCAR game rule = gamedir end qstat-2.15/ts2.h0000644000175000017500000000065512420765614010414 00000000000000/* * qstat * by Steve Jankowski * * Teamspeak 2 protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_TS2_H #define QSTAT_TS2_H #include "qserver.h" // Packet processing methods query_status_t deal_with_ts2_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_ts2_request_packet( struct qserver *server ); #endif qstat-2.15/debug.h0000644000175000017500000000323212420765614010764 00000000000000/* * qstat * by Steve Jankowski * * debug helper functions * Copyright 2004 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_DEBUG_H #define QSTAT_DEBUG_H #include #include "qstat.h" #ifdef DEBUG #include #ifdef _WIN32 void _debug(const char* file, int line, const char* function, int level, const char* fmt, ...); #define debug(level,fmt,...) \ if( level <= get_debug_level() ) \ _debug(__FILE__,__LINE__,__FUNCTION__,level,fmt,__VA_ARGS__) #else void _debug(const char* file, int line, const char* function, int level, const char* fmt, ...) GCC_FORMAT_PRINTF(5, 6); #define debug(level,fmt,rem...) \ if( level <= get_debug_level() ) \ _debug(__FILE__,__LINE__,__FUNCTION__,level,fmt,##rem) #endif // _WIN32 #else #define debug(...) #endif // DEBUG void dump_packet(const char* buf, int buflen); #ifdef ENABLE_DUMP #ifndef _WIN32 #include #include #else #ifdef _MSC_VER #define ssize_t SSIZE_T #define uint32_t UINT32 #endif #endif #include #include int do_dump; ssize_t send_dump(int s, const void *buf, size_t len, int flags); #ifndef QSTAT_DEBUG_C #define send(s, buf, len, flags) send_dump(s, buf, len, flags) #endif #endif /** report a packet decoding error to stderr */ void malformed_packet(const struct qserver* server, const char* fmt, ...) GCC_FORMAT_PRINTF(2, 3); int get_debug_level (void); void set_debug_level (int level); void print_packet( struct qserver *server, const char *buf, int buflen ); void output_packet( struct qserver *server, const char *buf, int buflen, int to ); #endif qstat-2.15/qstatdoc.html0000644000175000017500000022175512420765614012251 00000000000000 QStat 2.10 documentation

NAME

qstat - Get statistics from on-line game servers

SYNOPSIS

qstat [options ...] [-f file] [-of|-af output-file] [-server-option host[:port]]
[-raw delimiter] [-default server-type] host[:port[-port_max]] ...

Version 2.10

DESCRIPTION

QStat is a command-line program that displays information about Internet game servers. The servers are either down, non-responsive, or running a game. For servers running a game, the server name, map name, current number of players, and response time are displayed. Server rules and player information may also be displayed.

Games supported include Quake, QuakeWorld, Hexen II, Quake II, HexenWorld, Unreal, Half-Life, Sin, Shogo, Tribes, Tribes 2, Quake III: Arena, BFRIS, Kingpin, and Heretic II, Unreal Tournament, Soldier of Fortune, Rogue Spear, Redline, Turok II, Blood 2, Descent 3, Drakan, KISS, Nerf Arena Blast, Rally Master, Terminous, Wheel of Time, and Daikatana and many more. Note for Tribes 2: QStat only supports Tribes 2 builds numbered 22075 or higher. Note for Ghost Recon QStat only supports GhostRecon patch 1.2, 1.3, 1.4, Desert Siege, and Island Thunder.

Some games use query protocols compatible with an existing game. These servers can be queried using the flags for the compatible game. For instance, Turok2 should work using the -uns flag. Unreal Tournament is also supported by the -uns but is not really a different game. You can distinguish Unreal Tournament games with the "minnetver" server rule (standard Unreal servers have a "mingamever" server rule).

The Quake servers can be divided into two categories: POQS (Plain Old Quake Server) and QuakeWorld. Quake shareware, Quake commercial (from CD), winquake, winded, unixded, and Hexen II are all POQS. The various versions of QuakeWorld and Quake II use a QuakeWorld type server. The distinction is based on network protocol used to query the servers, and affects the kind of information available for display.

The different server types can be queried simultaneously. If QStat detects that this is being done, the output is keyed by the type of server being displayed. See DISPLAY OPTIONS.

The game server may be specified as an IP address or a hostname. Servers can be listed on the command-line or, with the use of the -f option, a text file.

DISPLAY MODES

One line will be displayed for each server queried. The first component of the line will be the server's address as given on the command-line or the file. This can be used as a key to match input addresses to server status. Server rules and player information are displayed under the server info, indented by one tab stop.

QStat supports three additional display modes: raw, templates, and XML. In raw mode, the server information is displayed using simple delimiters and no formatting. This mode is good for programs that parse and reformat QStat's output. The template mode uses text files to layout the server information within existing text. This is ideal for generating web pages. The XML mode outputs server information wrapped in simple XML tags. The raw mode is enabled using the -raw option, template output is enabled using -Ts, and XML output is enabled with -xml.

GAME OPTIONS

These options select which servers to query and what game type they are running. Servers are specified by IP address (for example: 199.2.18.4) or hostname. Servers can be listed on the command-line or in a file (see option -f.) The game type of a server can be specified with its address, or a default game type can be set for all addresses that don't have a game type.

The following table shows the command-line option and type strings for the supported game types. The type string is used with the -default option and in files with the -f option.

OptionType StringDefault PortGame Server
-qsqs26000Quake
-h2sh2s26900Hexen II
-qwsqws27500QuakeWorld
-hwshws26950HexenWorld
-q2sq2s27910Quake II
-unsuns7777Unreal
-ut2sut2s7777Unreal Tournament 2003
-ut2004mut2004m28902Unreal Tournament 2004 Master requires CD Key
-hlshls27015Half-Life
-snssns22450Sin
-sgssgs27888Shogo: Mobile Armor Division
-tbstbs28001Starsiege: Tribes
-t2st2s28000Tribes 2
-qwmqwm27000QuakeWorld master
-hwmhwm26900HexenWorld master
-q2mq2m27900Quake II master
-hlmhlm27010Half-Life master
-stmstm27010Half-Life master (Steam)
-tbmtbm28000Tribes master
-t2mt2m28002Tribes 2 master
-q3sq3s27960Quake III
-q3mq3m27950Quake III master
-dm3sdm3s27666Doom 3
-dm3mdm3m27650Doom 3 master
-bfsbfs44001BFRIS
-kpskps31510Kingpin
-hrshrs28910Heretic II
-sfssfs28910Soldier of Fortune
-gsmgsm28900Gamespy master
-gpsgps-Game using "Gamespy style" protocol
-gpsgs2-Game using "Gamespy2 style" protocol
-d3md3m3445Descent 3 PXO master
-d3pd3p2092Descent 3, PXO server
-d3sd3s2092Descent 3, LAN server
-d3gd3g20142Descent 3, Gamespy protocol
-rwsrws27960Return to Castle Wolfestein
-rwmrwm27950Return to Castle Wolfestein master
-efsefs27960Star Trek: Elite Force
-efmefm27953Star Trek: Elite Force master
-efsefs29070Jedi Knight: Jedi Academy
-efmefm29060Jedi Knight: Jedi Academy master
-grsgrs2346Ghost Recon
-etqwsetqws27733QuakeWars server

The command-line options can be specified multiple times, one for each server to be queried.

Configuration Files

The games supported by QStat can be customized with configuration files. The query parameters of built-in game types can be modified and new games can be defined.

For built-in game types, certain parameters can be modified. The parameters are limited to the master server protocol and master server query string.

New game types can be defined as a variation on an existing game type. Most new games use a Quake 3 or Gamespy/Unreal based network engine. These games can already be queried using -q3s or -gps, but they don't have game specific details such as the correct default port, the game name, and the correct "game" or "mod" server rule. And, mostly importantly, they don't get their own game type string (e.g. q3s, rws, t2s). All of these details can be specified in the QStat config file.

QStat comes with a default configuration file called 'qstat.cfg'. If this file is found in the directory where qstat is run, the file will be loaded. Configuration files can also be specified with the QSTAT_CONFIG environment variable and the -cfg command-line option. See Appendix B for a description of the configuration file format.

Descent 3

Support for Descent 3 is a bit fragmented. There are three different protocols for getting status information from a Descent 3 server: PXO, LAN, and Gamespy. If the server was acquired from the PXO master server, then the PXO protocol is used. If the server is running on the local LAN (not reporting to a master server), then the LAN protocol should be used. Finally, if the server's Gamespy query port is known (default is 20142) then the Gamespy protcol can be used. The gamespy protocol can be used on servers listed in the PXO master.

Each protocol reports different information. The Gamespy protocol provides player names, frags, deaths, and ping. The PXO and LAN protocols only provide player names.

The ideal solution would be a PXO server list paired with each server's gamespy query port. Most servers will use the default gamespy query port, unless there are multiple servers on the same machine. A possible approach is to get the server list from the PXO master like this:

qstat -d3m,outfile gt.pxo.net,d3pxo.txt
Then convert the file from "d3p" to "d3g" and remove the port numbers:
sed -e 's/d3p/d3g/' -e 's/:.*$//' d3pxo.txt > d3gs.txt
Then run the servers in d3gs.txt with -f:
qstat -f d3gs.txt
This technique will retrieve the full player info for servers using the default gamespy query port.

Broadcast Queries

QStat has limited support for broadcast queries. Broadcast queries use one network packet to find all the game servers on a local network. A broadcast returns servers of one type on one port. You may only broadcast to networks to which you computer is directly attached (ie. local networks).

A broadcast query is specified by prefixing an address with a '+' (plus sign). The address should be 255.255.255.255 or a valid broadcast address for your local network. On Unixes, 'ifconfig -a' will display the broadcast address for all attached networks.

Port Ranges

Broadcast Queries can scan a range of ports to find game servers that don't run on the default port. Specify the minimum and maximum port of a range separated by a dash.

Query Arguments

Some game types support customized server queries. For example, many master servers can return a select list of servers based on the mod, number of players, or region. Each query can be customized differently.

Server queries are customized by attaching query arguments to the server type option. Each argument is separated by a comma (','). The argument has a name followed by an optional value separated with an equal-sign ('='). The general format looks like this:

-server-option,query-arg[=arg-value][, ...]
See the Master Server sections below for more examples.
General Query Arguments
The follow query arguments can be applied to any server type.
Query ArgumentDescription
showgameportAlways display the game port in QStat output. If the query port was different from the game port, then the query port will be saved in the "_queryport" server rule. This is the same as the -showgameport command-line option, but only applies to one server query.
gpShort-hand for showgameport.
noportoffsetDo not apply the "status port offset" when sending the server query. Some games use different ports for game play and status queries (for example, Unreal, Medal of Honor, etc). QStat will normally add an offset to the game port to find the query port. But not all servers use the standard offset. This option allows QStat to query servers where the query port is known. The server address should be an IP address and a query port (not the game port). This is the same as the -noportoffset command-line option, but only applies to one server query.
qpShort-hand for noportoffset.

Some examples of the general query arguments.

qstat -uns,noportoffset 1.2.3.4:7787
ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
1.2.3.4:7787        0/16      Kansas    119 / 0       Example server
The default Unreal game port is 7777 and the query port is usually at offset 1 (port 7778). But this server has a different query port. Note that qstat displays the query port. To display the game port instead:
qstat -uns,noportoffset,showgameport 1.2.3.4:7787
ADDRESS           PLAYERS      MAP   RESPONSE TIME    NAME
1.2.3.4:7777        0/16      Kansas    119 / 0       Example server
Another common usage for "showgameport" is with broadcast queries:
qstat -uns,showgameport +255.255.255.255

Master Servers

Master server addresses don't change very often, but some times they go off-line. The following is a table of some of the master servers I know about.

GameMaster Servers
QuakeWorldsatan.idsoftware.com (ports 27000, 27002, 27003, 27004, 27006), 204.182.161.2, 194.217.251.40, 203.34.140.1, 200.245.221.200, 194.87.251.3
Quake IIsatan.idsoftware.com, q2master.planetquake.com
Half-Life (hlm)half-life.west.won.net, half-life.east.won.net
Half-Life (stm)steam1.steampowered.com:27010, steam2.steampowered.com:27010
Tribestribes.dynamix.com
Quake IIImaster3.idsoftware.com
Doom 3idnet.ua-corp.com
Gamespymaster0.gamespy.com
Tribes 2211.233.32.77:28002, 217.6.160.205:28002
Descent 3gt.pxo.net
Return to Castle Wolfensteinwolfmaster.idsoftware.com
Star Trek: Elite Forcemaster.stef1.ravensoft.com
UT2004ut2004master1.epicgames.com, ut2004master2.epicgames.com, ut2004master3.epicgames.com

Gamespy Master

Access to the gamespy masters has been disabled by Gamespy Inc.

Server lists can be fetched from Gamespy masters by using the gsm game type. A query argument is required to use the Gamespy master. This extra argument indicates which server list to get from the master. The query argument can be one of the QStat supported game types or any other string that will fetch a server list. The following game types can be used as query arguments: qws, q2s, q3s, tbs, uns, sgs, hls, kps, hrs, sfs. For each of the game types, QStat will fetch the appropriate server list and get status from each server.

The query argument can also be any string that the Gamespy master responds to. Most of these games support a "standard" server status protocol that I'll call the "Gamespy status protocol". Not surprisingly, it is almost identical to the Unreal server status protocol. This means that QStat can support any game that supports this protocol. In QStat these games are queried using the gps game type. Through experimentation I've found the following query arguments.

Query ArgumentGame
roguespearRainbow Six: Rogue Spear
redlineRedline Racer
turok2Turok 2: Seeds of Evil
blood2Blood 2: The Chosen
drakanDrakan: Order of the Flame
kissKISS Psycho Circus: The Nightmare Child
nerfarenaNerf Arena Blast
rallyRally Masters: Michelin Race Of Champions
terminousTerminous (?)
wotThe Wheel of Time
daikatanaDaikatana

Tribes 2 Master

The Tribes 2 master server supports a number of filtering options. You can set these filters with QStat by appending query arguments to the server type. The general syntax is:
t2m,query-arg=value, ...
Query ArgumentValuesDescription
gamemod pathMod path the server is using. The mod path of unaltered servers is "base". Use query=types to get the list of known game types.
missionBounty, Capture the Flag, CnH, Deathmatch, Hunters, Rabbit, Siege, TeamHuntersMission type the server is currently running. Use query=types to get the list of known mission types.
minplayers0 - 255Servers with fewer players than this will not be returned.
maxplayers1 - 255Servers with more players than this will not be returned.
regionslist of regions or 0xhex-value Limit servers to those in the given geographical regions. See Region List table. The regionlist is sent as a bit mask to the Tribes 2 master. If you know the bit mask for a region QStat doesn't support, you can specify the bitmask directly by supplying a hex value: regions=0x11.
buildbuild version # Only return servers matching this build version number. [4/20/2001] This filter only seems to work if the build version # is 22337. If the filter is 22228, then the master returns 0 servers. This appears to be a bug in the T2 master.
statuslist of dedicated, linux, nopassword
or 0xhex-value
Limit servers to those with these status flags set. The list is one or more status flags separated by colons (':'). To filter on dedicated Linux servers, specify status=dedicated:linux
If you know a status flag that QStat doesn't support, you can specify the status flags directly by supplying a hex value: status=0x3
maxbots0 - 255Servers with more bots than this will not be returned.
mincpu0 - 65535Servers with lower CPU speed than this will not be returned.
querytypesGet the list of game and mission types. This is not a filter but a different master request. Using this query argument overrides any other query arguments. The list of game and mission types known to the master server will be displayed. In raw mode, the first line is the list of game types and the second line is the list of mission types. There is no output template support for game and mission lists.
Region List
The region list is one or more region arguments separated by colons (':'). For example, to filter on North American servers specify regions=naeast:nawest

Region ArgumentGeography
naeastNorth America East
nawestNorth America West
saSouth America
ausAustralia
asiaAsia
eurEurope

The Tribes 2 master query arguments can be used on the command-line or in a server list file (via the -f option). If the values contain spaces, be sure to quote the arguments for your shell. The second example below demonstrates this usage for most common shells. To query for Capture the Flag servers that have more than 6 players:
qstat -t2m,mission=Capture the Flag,minplayers=6 master-server-ip
qstat -t2m,mission="Capture the Flag",minplayers=6 master-server-ip
If you want to do this in a server list file, that would look like this:
t2m,mission=Capture the Flag,minplayers=6 master-server-ip
Master server filters can be combined with the "outfile" option. Just put outfile some where in the query argument list and put the name of the output file after the master IP address:
t2m,outfile,mission=Siege,minplayers=4 master-server-ip,siegeservers.txt
Warning: There is a bug in the 22075 build of Tribes 2 that doesn't return the game name. For those builds, QStat will use the game info in place of the game name. The bug is fixed in the 22228 build. In fixed servers, the game info can be found in the "info" server rule.

Half-Life Master

The Half-Like master server supports a number of filtering options. You can set these filters with QStat by appending query arguments to the server type. The general syntax is:
hlm,query-arg=value, ...
Query ArgumentValuesDescription
gamemod pathServers running this "mod".
mapmap nameServers running this map.
statuslist of dedicated, linux, notempty, notfull Limit servers to those matching this status. The list is one or more status flags separated by colons (':'). To filter on dedicated servers that are not empty, specify status=dedicated:notempty
See the Tribes 2 master server above for example usage.

Half-Life Master (Steam)

The Half-Life steam master server supports a number of filtering options different from the old WON master.
stm,query-arg=value, ...
Query ArgumentValuesDescription
gamemod pathServers running this "mod".
mapmap nameServers running this map.
regionname or number of regionGeographical Area of the server. You can specify the name or number of the region:
  • 0: US East coast
  • 1: US West coast
  • 2: South America
  • 3: Europe
  • 4: Asia
  • 5: Australia
  • 6: Middle East
  • 7: Africa
statuslist of dedicated, linux, notempty, notfull, secure, proxy Limit servers to those matching this status. The list is one or more status flags separated by colons (':'). To filter on dedicated servers that are not empty, specify status=dedicated:notempty
See the Tribes 2 master server above for example usage.

Doom 3 Master

The Doom 3 master server supports a number of filtering options. You can set these filters with QStat by appending query arguments to the server type. The general syntax is:
dm3m,query-arg=value, ...
Query ArgumentValuesDescription
statuscolon separated list of password, nopassword, notfull, notfullnotempty Limit servers to those matching this status. The list is one or more status flags separated by colons (':'). To filter on servers without password that are not full, specify status=nopassword:notfull
gametypeone of dm, tdm or tourney limit servers to those mathing the specified gametype
See the Tribes 2 master server above for example usage.
A special option is a number major.minor which specifies the protocol version.

UT2004 Master

The UT2004 master server supports a number of filtering options. You can set these filters with QStat by appending query arguments to the server type. The general syntax is:
ut2004m,query-arg=value, ...
Query Argument Values Description
cdkey path to the UT2004 cdkey file You MUST specify a valid CD key to be able to query the master server
status colon separated list of password, nopassword, notfull, notempty, standard, nostandard, nobots, stats, nostats, weaponstay, noweaponstay, transloc, notransloc Limit servers to those matching this status. The list is one or more status flags separated by colons (':'). To filter on standard servers without password that are not full, specify status=standard:nopassword:notfull
gametype any UT2004 gametype, e.g. xMutantGame limit servers to those mathing the specified gametype
mutator colon separated list of Mutators. limit servers to those running the specified mutators. Prepend a dash to include servers that do NOT run the specified mutator
You may need to specify at least one filter option like status or gametype for the master to actually return any server.
Example:
qstat -ut2004m,cdkey=/usr/local/games/ut2004/System/cdkey,status=nostandard ut2004master1.epicgames.com:28902

Option Usage

-cfg configuration-file
Load the QStat configuration file. New game types defined in the config file can be used in subsequent command-line options.
-server-option host[:port]
Query game server host for status. The GAME OPTIONS table lists the available server-options and their default port.
-nocfg Ignore qstat configuration loaded from any default location (see Appendix B for a list of default locations). Must be the first option on the command-line. Use this option to have complete control over the configured game types.
-master-server-option host[:port]
Query a game master for its server list and then query all the servers. The GAME OPTIONS table lists the available master-server-options and their default port.
-master-server-option,outfile host[:port],file
Query a game master for its server list and store it in file. If the master cannot be contacted, then file is not changed. If file is - (a single dash), then stdout is used. The GAME OPTIONS table lists the available master-server-options and their default port.
-gsm,query-argument host[:port]
Query a Gamespy master for a server list and then query all the servers. The Gamespy Master section details the supported values for query-argument.
-gsm,query-argument,outfile host[:port],file
Query a Gamespy master for a server list and store it in file. If the master cannot be contacted, then file is not changed. If file is - (a single dash), then stdout is used. The Gamespy Master section details the supported values for query-argument.
-q3m,query-argument host[:port]
Query a Quake 3 Arena master for a protocol-specific server list and then query all the servers. The query-argument should be a Quake 3 protocol version. Protocol version 48 is Quake 3 version 1.27, protocol 46 is Quake 3 version 1.25, protocol 45 is Quake 3 1.17, protocol 43 is Quake 3 version 1.11. The default is protocol version 48.
-q3m,query-argument,outfile host[:port],file
Query a Quake 3 Arena master for a protocol-specific server list and store it in file. The query-argument should be a Quake 3 protocol version. Protocol version 46 is Quake 3 version 1.25, protocol 45 is Quake 3 1.17, protocol 43 is Quake 3 version 1.11. The default is protocol version 45.
-f file
Read host addresses from the given file. If file is -, then read from stdin. Multiple -f options may be used. The file should contain host names or IP addresses separated by white-space (tabs, new-lines, spaces, etc). If an address is preceded by a server type string, then QStat queries the address according to the server type. Otherwise QS is assumed, unless -default is used. The GAME OPTIONS table lists the available server type strings and their default port.
-default type-string
Set the default server type for addresses where the type is not obvious. This affects the addresses at the end of the qstat command-line and those in a file not prefixed by a server type (see -f). The GAME OPTIONS table lists the available server type strings and their default port.
-noportoffset
Do not apply the "status port offset" when sending server queries. Some games use different ports for game play and status queries (for example, Unreal, Medal of Honor, etc). QStat will normally add an offset to the game port to find the query port. But not all servers use the standard offset. This option allows QStat to query servers where the query port is known. The server addresses should be an IP address and a query port (not the game port). This is the same as the noportoffset server query argument, but applies to all servers being queried.

INFO OPTIONS

-R
Fetch and display server rules.
-P
Fetch and display player information.

DISPLAY OPTIONS

The QStat output should be self explanatory. However, the type of information returned is different between game types. If QStat queries multiple server types, then each server status line is prefixed with its type string. The GAME OPTIONS table lists the available type strings.

-of file
Write output to file instead of stdout or the console. file is over written if it already exists.
-af file
Like -of, but append to the file. If file does not exist, it is created.
-u
Only display hosts that are up and running a game server. Does not affect template output.
-nf
Do not display full servers. Does not affect template output.
-ne
Do not display empty servers. Does not affect template output.
-nh
Do not display header line (does not apply to raw or template output.)
-cn
Display color names instead of numbers. This is the default. Only applies to Quake, QuakeWorld, Hexen II, and HexenWorld.
-ncn
Display color numbers instead of color names. This is the default for -raw mode. Only applies to Quake, QuakeWorld, Hexen II, and HexenWorld.
-hc
Display colors in #rrggbb format. This is nice for HTML output. Only applies to Quake, QuakeWorld, Hexen II, and HexenWorld.
-nx
Perform name transforms. Transform game specific player and server name escape sequences into more readable text. This setting is ON by default.
-nnx
No name transforms. Do not transform player and server names. Option -utf8 implies -nnx.
-tc
Display time in clock format (DhDDmDDs). This is the default.
-tsw
Display time in stop-watch format (DD:DD:DD).
-ts
Display time in seconds. This is the default for -raw mode.
-pa
Display player addresses. This is the default for -raw mode. Only available for Quake and Hexen II.
-sort sort-keys
Sort servers and/or players. Servers and players are sorted according to sort-keys. Lower case sort keys are for servers and upper case keys are for players. The following sort keys are supported:
  • p - Sort by ping
  • g - Sort by game (mod)
  • i - Sort by IP address
  • h - Sort by hostname
  • n - Sort by number of players
  • l - Sort by list order
  • P - Sort by player ping
  • F - Sort by frags
  • T - Sort by team

The 'l' (ell) sort key displays servers in the order they were provided to qstat. For example, the order in which they are listed on the command-line or in a file. The 'l' sort key cannot be combined with other server sort keys, but it can be be combined with player sort keys. If the 'l' sort key is used with other sort keys, then the 'l' sort key is ignored.

-hpn
Display player names in hex.
-old
Use pre-qstat 1.5 display style.
-raw delimiter
Display data in "raw" mode. The argument to -raw is used to separate columns of information. All information returned by the game server is displayed.
POQS output -- General server information is displayed in this order: command-line arg (IP address or host name), server name, server address (as returned by Quake server), protocol version, map name, maximum players, current players, average response time, number of retries. Server rules are displayed on one line as rule-name=value. If significant packet loss occurs, rules may be missing. Missing rules are indicated by a "?" as the last rule. Player information is displayed one per line: player number, player name, player address, frags, connect time, shirt color, pants color. A blank line separates each set of server information.
QuakeWorld and HexenWorld server output -- General server information is displayed in this order: command-line arg (IP address or host name), server name, map name, maximum players, current players, average response time, number of retries, game (mod). Server rules are displayed on one line as rule-name=value. Player information is displayed one per line: player number, player name, frags, connect time, shirt color, pants color, ping time (milliseconds), skin name. A blank line separates each set of server information.
All master server output -- Master server information is displayed in this order: command-line arg (IP address or host name), number of servers. No other information is displayed about master servers.
Quake II, Quake III, Half-Life, Sin, BFRIS, Kingpin, Heretic II, Unreal, Tribes 2, and Shogo server output -- General server information and server rules are the same as a QuakeWorld server. The player information varies for each game:
  • Quake II/III, Sin, Kingpin, Heretic II, Shogo: player name, frags, ping time
  • Half-Life: player name, frags, connect time
  • Tribes: player name, frags, ping time, team number, packet loss
  • Tribes 2: player name, frags, team number, team name, player type, tribe tag
  • Unreal: player name, frags, ping time, team number, skin, mesh, face
  • BFRIS: player number, ship, team name, ping time, score, frags, player name
  • Descent 3: player name, frags, deaths, ping time, team
Ping time is in milli-seconds. Connect time is in seconds. A blank line separates each set of server information.
Ghost Recon server output -- General server information and server rules are the detailed in the GhostRecon.txt file. Servers queried using the "Gamespy style" protocol use the same raw output format as Unreal servers.

-raw,game delimiter
Same as -raw but adds the game or mod name as the last item of server info.
-raw-arg
When used with -raw, always display the server address as it appeared in a file or on the command-line. Note that when -H is used with -raw, the first field of the raw output could be a hostname if the server IP address was resolved. This can make matching up input servers addresses with raw output lines fairly difficult. When -raw-arg is also used, an additional field, the unresolved server address, is added at the beginning of all raw output lines.
-progress,count
Print a progress meter. Displays total servers processed, including timeouts and down servers. The meter is just a line of text that writes over itself with <cr>. Handy for interactive use when you are redirecting output to a file (the meter is printed on stderr).
By default, the progress meter is updated for every server. The updates can be limited by appending ,count to the option where count is a number. The meter will be updated every count servers. For example, -progress,10 will update every ten servers.
-Tserver file
-Tplayer file
-Trule file
-Theader file
-Ttrailer file
Output templates. Each template should be a text file containing QStat variables that are substituted for results from the server query. The -Tserver flag must present to enable template output. The other -T flags are optional. The server template is output once for each server queried. The player template, if present, is output once for each player (if -P is also used). The rule template is output once for each server rule (the -R option may be required for some game types). The header template is output once before any servers are output. The trailer template is output once after all servers are output. See Appendix A for the output template formatting and variables.
NOTE: All of of the -T flags may be abbreviated with two characters: -Ts, -Tp, -Tr, -Th, and -Tt.
-htmlnames
Colorize Quake 3 and Tribes 2 player names using html font tags. Enabled by default if $HTML is used in an output template.
-nohtmlnames
Do not colorize Quake 3 and Tribes 2 player names even if $HTML is used in an output template. The $HTMLPLAYERNAME variable will always colorize player names.
-htmlmode
Convert <, >, and & to the equivalent HTML entities. This is the same as $HTML in an output template, but works for raw display mode. Using -htmlmode with -xml will result in double-escaping.
-carets
Display carets in Quake 3 player names. Carets are used for colorized player names and are remove by default. This option has no effect if -htmlnames is enabled.
-xml
Output server information wrapped in XML tags.
-utf8
Use the UTF-8 character encoding for XML output.
-showgameport
Always display the game port in QStat output. If the query port was different from the game port, then the query port will be saved in the "_queryport" server rule. This is the same as the showgameport server query argument, but applies to all server queries.
-errors
Display errors.
-d
Enable debug options. By default, enables printing of all received packets to stderr.

SEARCH OPTIONS

-H
Resolve IP addresses to host names. Use with caution as many game servers do not have registered host names. QStat may take up to a minute to timeout on each unregistered IP address. The duration of the timeout is controlled by your operating system. Names are resolved before attempting to query any servers.
-Hcache cache-file
Cache host name and IP address resolutions in cache-file. If the file does not exist, it is created. If -Hcache is used without -H, then the cache is only used for host to IP address resolution. WARNING A host cache file should not be shared by QStat programs running at the same time. If you run several QStats at the same time, each should have its own cache file.
-interval seconds
Interval in seconds between server retries. Specify as a floating point number. Default interval is 0.5 seconds. This option does not apply to master servers (see -mi.)
-mi seconds
Interval in seconds between master server retries. Specify as a floating point number. Default interval is 2 seconds.
-retry number
Number of retries. QStat will send this many packets to a host before considering it non-responsive. Default is 3 retries.
-maxsimultaneous number
Number of simultaneous servers to query. Unix systems have an operating system imposed limit on the number of open sockets per process. This limit varies between 32 and 100 depending on the platform. On Windows 95 and Windows NT, the "select" winsock function limits the number of simultaneous queries to 64. These limits can be increased by minor changes to the code, but the change is different for each platform. Default is 20 simultaneous queries. This option may be abbreviated -maxsim.
-timeout seconds
Total run time in seconds before giving up. Default is no timeout.

NETWORK OPTIONS

-srcport port-number | port-range
Specify the source ports for sending packets. The ports can be a single number or a range. A range is two numbers separated by a dash ('-'). The numbers should be positive and less than 65535. Use this option to get through a firewall that has source port restrictions. Set -srcport to the range of ports allowed by the firewall.

Example: If your firewall will allow outgoing UDP packets on ports 26000-30000, the qstat option would be -srcport 26000-30000

Note: The number of source ports given should be greater than or equal to the -maxsim (defaults to 20). The number of source ports will limit the number of simultaneous server queries.

-srcip IP-address
Specify a local IP address from which to send packets. This is useful on machines that have multiple IP addresses where the source IP of a packet is checked by the receiver. Normally this option is never needed.

NOTES

The response time is a measure of the expected playability of the server. The first number is the server's average time in milli-seconds to respond to a request packet from QStat. The second number is the total number of retries required to fetch the displayed information. More retries will cause the average response time to be higher. The response time will be more accurate if more requests are made to the server. For POQS, a request is made for each server rule and line of player information. So setting the -P and -R options will result in a more accurate response time. Quake and Hexen II are POQS. For most other game servers, QStat makes just one request to retrieve all the server status information, including server rules and player status. The -P and -R options do not increase the number of requests to the server. Half-Life supports three different requests for information; general status, players, and server rules. Each requires a separate request packet, so a total of three are used to retrieve player and rules.

Quake supports a number of control codes for special effects in player names. QStat normalizes the codes into the ASCII character set before display. The graphic codes are not translated except the orange brackets (hex 90, 10, 91, and 11) which are converted to '[' and ']'. Use the hex-player-names option -hpn to see the complete player name.

POQS do not return version information. But some small amount of info can be gathered from the server rules. The noexit rule did not appear until version 1.01. The Quake II server rules include a "version" key that contains the id build number. Recent releases of QuakeWorld have a "*version" key in the server rules. Unreal servers include a "gamever" key in the server rules that contains the server version without the decimal point. Most other game servers include some kind of version info in the server rules.

EXAMPLES

The following is an example address file that queries a QuakeWorld master, several Hexen II servers, some POQS, and a few Quake II servers.

QWM 192.246.40.12:27004
H2S 207.120.210.4
H2S 204.145.225.124
H2S 207.224.190.21
H2S 165.166.140.154
H2S 203.25.60.3
QS 207.25.198.110
QS 206.154.207.104
QS 205.246.42.31
QS 128.164.136.171
Q2S sm.iquest.net
Q2S 209.39.134.5
Q2S 209.39.134.3

If the above text were in a file called QSERVER.TXT, then the servers could be queried by running:
qstat -f QSERVER.TXT

IMPLEMENTATION NOTES

QStat sends packets to each host and waits for return packets. After some interval, another packet is sent to each host which has not yet responded. This is done several times before the host is considered non-responsive. QStat can wait for responses from up to 20 hosts at a time. For host lists longer than that, QStat checks more hosts as results are determined.

The following applies only applies to POQS. If QStat exceeds the maximum number of retries when fetching server information, it will give up and try to move on to the next information. This means that some rules or player info may occasionally not appear. Player info may also be missing if a player drops out between getting the general server info and requesting the player info. If QStat times out on one rule request, no further rules can be fetched. This is a side-effect of the Quake protocol design.

The number of available file descriptors limits the number of simultaneous servers that can be checked. QStat reuses file descriptors so it can never run out. The macro MAXFD in qstat.c determines how many file descriptors will be simultaneously opened. Raise or lower this value as needed. The default is 20 file descriptors.

Operating systems which translate ICMP Bad Port (ICMP_PORT_UNREACHABLE) into a ECONNREFUSED will display some hosts as DOWN. These hosts are up and connected to the network, but there is no program on the port. Solaris 2.5 and Irix 5.3 correctly support ICMP_PORT_UNREACHABLE, but Solaris 2.4 does not. See page 442 of "Unix Network Programming" by Richard Stevens for a description of this ICMP behavior.

Operating systems without correct ICMP behavior will just report hosts without Quake servers as non-responsive. Windows NT and Windows 95 don't seem to support this ICMP.

For hosts with multiple IP addresses, QStat will only send packets to the first address returned from the name service.

QStat supports Unreal version 2.15 or greater.

BUGS

PORTABILITY

UNIX - QStat has been compiled and tested on Solaris 2.x, Irix 5.3/6.2/6.3/6.4, FreeBSD 2.2/3.0, BSDi, HP-UX 10.20/11.0, and various flavors of Linux.

WINDOWS - The Windows version of QStat (win32/qstat.exe) runs on Windows 95 and Windows NT as a console application. On Windows 95 and NT 4.0, short-cuts can be used to set the arguments to qstat. On Windows NT 3.51, use a batch file.

OS/2 - An OS/2 binary is no longer included. Try contacting Per Hammer for an OS/2 Warp binary. per@mindbend.demon.co.uk.

VMS - The source includes a VMS patch from John Ross Hunt. This patch was tested on QStat 2.0b, but has not been tested on the current version. See COMPILE.txt for instructions.

VERSION

This is QStat version 2.10 The QStat webpage is updated for each new version and contains links to Quake server listings and pages about the Quake and Unreal network protocols. The page can be found at
http://www.qstat.org

Quake, Quake II, QuakeWorld, and Quake III created by id Software. Hexen II, HexenWorld, and Heretic II created by Raven Software. Unreal created by Epic Games. Half-Life created by Valve Software. Sin created by Ritual Entertainment. Shogo: Mobile Armor Division was created by Monolith Productions Inc. Tribes and Tribes 2 created by Dynamix, Inc. BFRIS created by Aegis Simulation Technologies. Kingpin created by Xatrix Entertainment Inc.

AUTHOR

Steve Jankowski
steve@qstat.org

COPYRIGHT

Copyright © 1996,1997,1998,1999,2000,2001,2002 by Steve Jankowski

LICENSE

QStat is covered by the terms of the Artistic License. The license terms can be found in LICENSE.txt of the QStat package.


APPENDIX A - Output Templates

QStat output templates provide greater control of the appearance of server status information. The results of a server query can be organized, formatted, and wrapped within any other text. The most obvious use is to generate HTML for web pages. However, it could also generate custom output for redisplay within another tool.

There are four output templates:
TemplateOption 
server-TsOutput once for each server queried. (required)
player-TpOutput once for each player. Must be used with -P. Invoked by the $PLAYERTEMPLATE variable.
rule-TrOutput once for each server rule. Invoked by the $RULETEMPLATE variable.
header-ThOutput once before any servers are queried.
trailer-TtOutput once after all servers are output.

The server template must be specified to enable template output. The other templates are optional.

Each output template is a file containing text and QStat variables. The text is output unchanged by QStat, but the variables are processed and replaced by QStat. Most variables are replaced by values from a queried server. Some variables have hardcoded values, and some generate no output, but affect how the template is processed.

Variables are grouped according to the templates where they can be used. General variables may be used in any of the templates. Server variables may be used in the server or player templates. Player variables may be used in the player template. Expression variables may only be used with the $IF and $IFNOT variables. If a variable is used where it doesn't make sense, it is ignored and generates no output.

Variables are specified using one of several syntaxes:

    $VAR
    $VAR:OPTION
    $(VAR)
    $(VAR:OPTION)
    $(VAR:OPTION(ARGUMENT))
The syntax used does not affect the output. However using the $() syntax is somewhat more readable when the text gets cluttered. If you want the variable to be followed immediately by text, then the $() syntax must be used.

Download considerations

If you are generating output to be downloaded, then you'll want to make your output as small as possible. In the case of HTML, you can reduce the size of your pages by excluding stuff.
  • Remove unneeded spaces (indenting and newlines)
  • Remove unneeded end tags. The HTML spec says the following tags can always be left out: </TD> </TR> </TH>
  • When creating a table, "width" modifiers are only needed on one cell of a column. Put them on the cells of the first row of the table.

    Display options

    The display options -u, -ne, and -nf have no affect on template output. Use the $IF:UP, $IF:ISEMPTY, and $IF:ISFULL conditions to accomplish the same thing.

    General Variables

    $QSTATURLOutput the web address of the QStat home page.
    $QSTATVERSIONOutput the version of QStat being run.
    $QSTATAUTHOROutput the name of the QStat programmer.
    $QSTATAUTHOREMAILOutput the email address of the QStat programmer.
    $HTMLEnable HTML friendly string output. Server results may include characters that have special meaning in HTML. These are replaced by equivalent SGML entities. QStat converts '<', '>', and '&' to '&lt;', '&gt;', and '&amp;'. Use this variable once in the header template.
    $CLEARNEWLINESConvert line feeds and carriage returns into spaces. Applies to all variables that output strings. Use this variable once in the header template.
    $RULENAMESPACESAllow spaces in rule names. Use this variable once in the header template.
    $IFConditional output. If the variable option is "true," the template is output up to a matching $ENDIF variable. If the variable option is "false," the template is ignored until after a matching $ENDIF. See Conditional Options for a list of supported conditional options.
    $IFNOTConditional output. Same as $IF, but the opposite sense.
    $ENDIFEnd conditional output. There must be one $ENDIF for each $IF and $IFNOT within a template.
    $NOWOutput the current local time.
    $TOTALSERVERSThe total number of servers to be queried.
    $TOTALUPThe number of servers up and running.
    $TOTALNOTUPThe number of servers either DOWN or TIMEOUT.
    $TOTALPLAYERSThe number of players found on all servers.
    $TOTALMAXPLAYERSThe sum of the maximum player values for all servers.
    $TOTALUTILIZATIONThe ratio of $TOTALPLAYERS to $TOTALMAXPLAYERS expressed as a percentage (a number between 0 and 100). Reports how full the servers are.
    $\Ignore the next newline. Not really a variable, but a way to curtail the output of extra newlines. Saves space in the output while the template remains readable. Must be the last thing on the line.
    $DEFAULTTYPEThe full name of the default server type specified with -default.

    Server Variables

    $HOSTNAMEOutput the host name of the server if known, otherwise the server address as given to QStat.
    $SERVERNAMEOutput the name of the server.
    $PINGThe time in milli-seconds to get a response from the server. If the server is DOWN or TIMEOUT, nothing is output.
    $PLAYERSThe number of players on the server.
    $MAXPLAYERSThe maximum number of players allowed on the server.
    $MAPThe name of the map being played.
    $GAMEThe name of the game being played. This is usually the name of the "mod" run by the server.
    $GAMETYPEThe type of game being played. Only applies to Quake 3. Typical values are Free For All, Capture the Flag, and Arena.
    $RETRIESThe number of retries needed to get the server status. This is a measure of packet loss.
    $IPADDRThe IP address of the server. Does not include the port number.
    $PORTThe port the server is running on.
    $ARGThe server address as given to QStat.
    $TYPEOutput one of the following depending on the server type:
        Quake
        Quake II
        Quake II Master
        QuakeWorld
        QuakeWorld Master
        Hexen II
        HexenWorld
        Unreal
        Unreal Tournament 2003
        Half-Life
        Half-Life Master
        Sin
        Tribes
        Tribes Master
        Tribes 2
        Tribes 2 Master
        Shogo: Mobile Armor Division
        Quake III: Arena
        Quake III Master
        BFRIS
        Kingpin
        Heretic II
        Soldier of Fortune
        Gamespy Master
        Gamespy Protocol
    
    If the server type is not known, nothing is output.
    $TYPESTRINGThe server's type string (see GAME OPTIONS table.)
    $TYPEPREFIXThe server's type prefix (same as $TYPESTRING but in all-caps.)
    $RULE:nameThe value of a server rule. If the rule is not returned by the server, nothing is output. Must be used with the -R flag. Server rule names can include any alpha-numeric character plus '*', '_', '.', or ' ' (space). The use of space in a rule name will require use of the parenthesized format: $(RULE:name)
    $ALLRULESOutput all the server rules in the format name=value separated by commas. Must be used with the -R flag.
    $PLAYERTEMPLATEInvoke the player template. The player template is output once for each player on the server. Must be used with the -P flag.
    $RULETEMPLATEInvoke the rule template. The rule template is output once for each server rule.

    Player Variables

    The player template is only invoked if $PLAYERTEMPLATE is used in the server template.

    $PLAYERNAMEThe name of the player. If -htmlnames or $HTML is used, then HTML color font tags will be added for Quake 3 and Tribes 2 player names. If $HTML is used but -nohtmlnames is set, then player names will not be colorized.
    $HTMLPLAYERNAMEThe name of the player with HTML color font tags. Only Quake 3 and Tribes 2 are supported.
    $FRAGSThe number of frags scored.
    $DEATHSDescent 3 - The number of times player has died. Ghost Recon - Indicates if the player is dead. Only available for Descent 3 or Ghost Recon.
    $PLAYERPINGThe player's ping time to the server. This value is not available from Half-Life or Ghost Recon servers.
    $CONNECTTIMEHow long the player has been playing. This value is only available from Quake, QuakeWorld, Hexen II, and Half-Life servers.
    $SKINThe name of the player's skin texture. This value is not available from ?? and Ghost Recon servers.
    $MESHThe name of the player's mesh (model). This value is only available from Unreal servers.
    $FACEThe name of the player's face texture. This value is only available from Unreal version 405+ servers.
    $SHIRTCOLORColor of the player's shirt. This value is only available from Quake, QuakeWorld, and Hexen II servers.
    $PANTSCOLORColor of the player's pants. This value is not available from Quake, QuakeWorld, and Hexen II servers.
    $PLAYERIPThe IP address of the player's computer. This value is only available from Quake and Hexen II servers.
    $TEAMNUMThe player's team number. This value is only available from Unreal, Tribes, Tribes 2 and Ghost Recon servers.
    $TEAMNAMEThe player's team name. This value is only available from Tribes and Tribes 2 servers.
    $TRIBETAGThe player's tribe tag. This value is only available from Tribes 2 servers.
    $PLAYERSTATIDThe player's global statistics id. This value is only available from Unreal Tournament 2003 servers.
    $PACKETLOSSThe player's packet loss. This value is only available from Tribes servers.
    $COLORNUMBERSDisplay $SHIRTCOLOR and $PANTSCOLOR as numbers. Equivalent to -ncn command-line option. No output.
    $COLORNAMESDisplay $SHIRTCOLOR and $PANTSCOLOR using color names. Equivalent to -cn command-line option. No output.
    $COLORRGBDisplay $SHIRTCOLOR and $PANTSCOLOR using #rrggbb format. Equivalent to -hc command-line option. No output.
    $TIMESECONDSDisplay $CONNECTTIME as number of seconds. Equivalent to -ts command-line option. No output.
    $TIMECLOCKDisplay $CONNECTTIME in clock format (DhDDmDDs). Equivalent to -tc command-line option. No output.
    $TIMESTOPWATCHDisplay $CONNECTTIME in stop-watch format (DD:DD:DD). Equivalent to -tsw command-line option. No output.

    Rule Variables

    The rule template is only invoked if $RULETEMPLATE is used in the server template. The rule template supports equality tests on rule names and values. See RULENAME and RULEVALUE under Conditional Options.

    $RULENAMEThe server rule name.
    $RULEVALUEThe server rule value.

    Conditional Options

    These options maybe used with the $IF and $IFNOT variables. For example, to display player information, the following could be used in the server template:

        $(IF:PLAYERS)$(IF:FLAG(-P))
        The server has $(PLAYERS) players:
        $(PLAYERTEMPLATE)
        $(ENDIF)$(ENDIF)
    
    The template between the $IF and $ENDIF variables will only be displayed if the server has one or more players and the -P flag was given to QStat.

    GAMETrue if the server is running a "mod."
    PLAYERSTrue if the server has one or more players.
    QUAKETrue if the server is running Quake (the original).
    QUAKE2True if the server is running Quake II.
    Q2MASTERTrue if the server is a Quake II master.
    QUAKEWORLDTrue if the server is running QuakeWorld.
    QWMASTERTrue if the server is a QuakeWorld master.
    HEXEN2True if the server is running Hexen II.
    HEXENWORLDTrue if the server is running HexenWorld.
    UNREALTrue if the server is running Unreal.
    UNREALTOURNAMENT2003True if the server is running Unreal Tournament 2003.
    HALFLIFETrue if the server is running Half-Life.
    HLMASTERTrue if the server is a Half-Life master.
    SINTrue if the server is running Sin.
    TRIBESTrue if the server is running Tribes.
    TRIBESMASTERTrue if the server is a Tribes master.
    TRIBES2True if the server is running Tribes 2.
    TRIBES2MASTERTrue if the server is a Tribes 2 master.
    SHOGOTrue if the server is running Shogo.
    QUAKE3True if the server is running Quake III.
    Q3MASTERTrue if the server is a Quake III master.
    BFRISTrue if the server is running BFRIS.
    KINGPINTrue if the server is running Kingpin.
    HERETIC2True if the server is running Heretic II.
    SOLDIEROFFORTUNETrue if the server is running Soldier of Fortune.
    DESCENT3True if the server is running Descent 3.
    GAMESPYMASTERTrue if the server is a Gamespy Master.
    GAMESPYPROTOCOLTrue if the server is running a "Gamespy style" status protocol.
    RULE(name)True if the rule name is set on the server. Server rule names can include any alpha-numeric character plus '*', '_', or '.'. If $RULENAMESPACES is enabled, then rule names may contain a ' ' (space).
    FLAG(name)True if the flag name was used on the QStat command-line. The only flag names supported are: -H, -P, and -R. Any other flag name returns false.
    UPTrue if the server is up and running.
    DOWNTrue if the server is known to be not running. This is true if the server computer returns an ICMP indicating that nothing is running on the port. Only supported by some operating systems.
    TIMEOUTTrue if the server never responded to a status query.
    HOSTNOTFOUNDTrue if the host name lookup failed.
    ISEMPTYTrue if the server has no players.
    ISMASTERTrue if this is a master server.
    ISFULLTrue if the server has the maximum players.
    ISTEAMTrue if the player is a team. Only available with Tribes and Tribes 2 servers. Only applies to the player template.
    ISBOTTrue if the player is a bot. Only available with Tribes 2 servers. Only applies to the player template.
    ISALIASTrue if the player is using an alias. Only available with Tribes 2 servers. Only applies to the player template.
    TRIBETAGTrue if the player has a tribe tag. Only available with Tribes 2 servers. Only applies to the player template.
    RULENAMETrue if the rule name matches the variable argument. For example $(IF:RULENAME(version)) will be true when the rule template is outputing a "version" server rule. Only applies to the rule template.
    RULEVALUETrue if the rule value matches the variable argument. For example $(IF:RULEVALUE(1)) will be true when the rule template is outputing a server rule whose value is "1". Only applies to the rule template.
    DEATHSTrue if the player has recorded DEATHS in Descent 3 or if the player is dead in Ghost Recon. NOTE if the Ghost Recon player has spawns available they can go from dead to alive.

    APPENDIX B - QStat Configuration File

    QStat configuration files modify built-in game types or create new game types. New command-line options and template variables are created for new game types.

    Please refer to the default configuration file for examples. The default configuration file qstat.cfg can be found in the QStat package.

    Config File Load Order

    QStat will load one default configuration file and zero or more command-line configuration files. The default configuration file will be the first readable file found by the following search.
    1. File named in $QSTAT_CONFIG environment variable.
    2. Unix: $HOME/.qstatrc
      Windows: $HOME/qstat.cfg
    3. Unix: sysconfdir/qstat.cfg
      Windows: location-of-qstat.exe/qstat.cfg
    The default configuration file will be loaded before reading any command-line parameters. Configuration files specified on the command line will be merged with the contents of the default config file. In the case of duplicate game types, the command-line config files will be used. The QStat package includes a qstat.cfg that defines several new game types. If you want to use these game types, you need to place the file where it can be found by the default config file search. Or use the -cfg option.
    Unix Note: The sysconfdir is determined when qstat is compiled. For Unix compiles, the QStat makefiles default to /etc. To compile with a different sysconfdir, set SYSCONFDIR when compiling with gmake. For example, to set sysconfdir to /usr/local/etc
    % gmake SYSCONFDIR=/usr/local/etc
    Windows Note: The location-of-qstat.exe is the directory where the QStat executable (qstat.exe) is located. Just put the default qstat.cfg in the same directory as qstat.exe.

    General Syntax

    QStat configuration files describe game types using "stanzas". A stanza begins with a "gametype" line and is followed by several parameter lines ending with an "end" line. The general syntax looks like this:
    gametype type-string (modify | new extend type-string)
        parameter-name = parameter-value
        ...
    end
    
    The text in bold are keywords that must be used as shown.

    Parameter names are one or more words separated by spaces. The supported parameters and their meaning are listed in Gametype Parameters. Extra white space before, after and within a parameter name is ignored. An equal sign ('=') must separate the parameter name and the parameter value. There can be one parameter setting per line.

    Parameter values are one more characters or escape sequences. Leading and trailing spaces are ignored. All characters are used as-is except for backslash ('\') which begins an escape sequence.

    \\A single backslash ('\')
    \nA newline (ASCII char 10)
    \rA carriage return (ASCII char 13)
    \(space) A space (ASCII char 32). This escape should be entered as two characters: backslash followed by one space.
    \xHHA single character represented by the two-digit hexadecimal code. The hex digits H must be 0-9, A-F, or a-f.
    \DDDA single character represented by the three-digit octal code. The octal digits D must be 0-7.

    Defining New Game Types

    New game types are defined with the new keyword.
    gametype new-type-string new extend existing-type-string
        parameter-name = parameter-value
        ...
    end
    
    The new-type-string must not be a built-in type string. If a new gametype is defined multiple times in configuration files, only the last definition is used. The existing-type-string can be any built-in or configuration defined game type. However, QStat has the best support for extending Q3S, Q2S, GPS, UNS, and Q3M game types.

    The new game type has command-line option, type string and type prefix derived from new-type-string. The case of new-type-string is ignored. The command-line option and type string are always lower-case and the type prefix is always upper case.

    The new game type starts with the same parameters as the existing-type-string except for the type string itself. Game type parameters are set by the following parameter setting lines. Some parameters may only be used with master server and some only with game servers.

    We suggest that new-type-strings be as short as possible and end with an 's' for game servers and an 'm' for master servers. New game types should, but are not required to, set the name, default port, and template var parameters. The template var should be all upper-case and should not contain any spaces.

    Modifying Game Types

    Existing game types can be modified to update their query parameters.
    gametype existing-type-string modify
        parameter-name = parameter-value
        ...
    end
    
    The existing-type-string can be a built-in game type or a configuration defined game type.

    Only certain parameters can be modified: master protocol, master query, and master packet.

    Request Packets

    The request packets used for game server queries can be set with status packet, status2 packet, player packet, and rule packet. Request packets for master servers can be set with the master packet parameter.

    A request packet can only be set if the extended game type uses the same type of request packet. If a game type only uses the status packet, then an extending game type can only set the status packet.

    Request packet typically contain binary characters (those beyond the printable ASCII character set). These can be specified using the hex and octal character escapes.

    If the master packet parameter is set, the master protocol and master query parameters will be ignored.

    Game Type Parameters

    nameSets the name of the game type. Should be the full game name as used by the publisher.
    flagsset the query flags. Bitwise OR of the following constants:
    • TF_SINGLE_QUERY
    • TF_OUTFILE
    • TF_MASTER_MULTI_RESPONSE
    • TF_TCP_CONNECT
    • TF_QUERY_ARG
    • TF_QUERY_ARG_REQUIRED
    • TF_QUAKE3_NAMES
    • TF_TRIBES2_NAMES
    • TF_SOF_NAMES
    • TF_U2_NAMES
    • TF_RAW_STYLE_QUAKE
    • TF_RAW_STYLE_TRIBES
    • TF_RAW_STYLE_GHOSTRECON
    • TF_NO_PORT_OFFSET
    • TF_SHOW_GAME_PORT
    default portDefault network port used by the status protocol.
    status port offsetOffset of the status/query port from the game port.
    game ruleThe server rule containing the name of the game style or game mod.
    template varThe template variable used to test whether a server is of this game type.
    status packetThe status request packet. This is the first packet sent to a server of this game type.
    status2 packetThe second status request packet. If the server responded to the first status packet, then this packet is sent, but only if player or rule info is needed (command-line options -P or -R).
    player packetThe player request packet. Requests player information.
    rule packetThe rule request packet. Requests server rule information.
    master for gametypeSets the type of game returned by this master. The value must be a built-in or configuration defined game type.
    master protocolThe protocol number to use in the master request. The master server will respond with servers that match the protocol number. The numbers change with each version of the game that uses an incompatible network protocol. The master protocol is used mainly with Quake 3 based games.

    The master request packet will combine the master protocol and master query values.

    master queryThe query string to use in the master request. The master query string provides additional filtering for the master server.

    The default master request packet will combine the master protocol and master query values.

    master packetThe master request packet. Requests a server list from the master server. If master packet is set, master protocol and master query are ignored.
    qstat-2.15/packet_manip.h0000644000175000017500000000117412420765614012334 00000000000000/* * qstat * by Steve Jankowski * * Packet module * Copyright 2005 Steven Hartland based on code by Steve Jankowski * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_PACKETS_H #define QSTAT_PACKETS_H #include "qstat.h" int combine_packets( struct qserver *server ); int add_packet( struct qserver *server, unsigned int pkt_id, int pkt_index, int pkt_max, int datalen, char *data, int calc_max ); int next_sequence(); SavedData* get_packet_fragment( int index ); unsigned combined_length( struct qserver *server, int pkt_id ); unsigned packet_count( struct qserver *server ); #endif qstat-2.15/md5.c0000644000175000017500000003113312420765614010357 00000000000000/* Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. L. Peter Deutsch ghost@aladdin.com */ /* $Id: md5.c 375 2012-04-20 12:51:31Z stevenhartland $ */ /* Independent implementation of MD5 (RFC 1321). This code implements the MD5 Algorithm defined in RFC 1321, whose text is available at http://www.ietf.org/rfc/rfc1321.txt The code is derived from the text of the RFC, including the test suite (section A.5) but excluding the rest of Appendix A. It does not include any code or documentation that is identified in the RFC as being copyrighted. The original and principal author of md5.c is L. Peter Deutsch . Other authors are noted in the change history that follows (in reverse chronological order): 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order either statically or dynamically; added missing #include in library. 2002-03-11 lpd Corrected argument list for main(), and added int return type, in test program and T value program. 2002-02-21 lpd Added missing #include in test program. 2000-07-03 lpd Patched to eliminate warnings about "constant is unsigned in ANSI C, signed in traditional"; made test program self-checking. 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). 1999-05-03 lpd Original version. */ #include "md5.h" #include #undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ #ifdef ARCH_IS_BIG_ENDIAN # define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) #else # define BYTE_ORDER 0 #endif #define T_MASK ((md5_word_t)~0) #define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) #define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) #define T3 0x242070db #define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) #define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) #define T6 0x4787c62a #define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) #define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) #define T9 0x698098d8 #define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) #define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) #define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) #define T13 0x6b901122 #define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) #define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) #define T16 0x49b40821 #define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) #define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) #define T19 0x265e5a51 #define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) #define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) #define T22 0x02441453 #define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) #define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) #define T25 0x21e1cde6 #define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) #define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) #define T28 0x455a14ed #define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) #define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) #define T31 0x676f02d9 #define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) #define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) #define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) #define T35 0x6d9d6122 #define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) #define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) #define T38 0x4bdecfa9 #define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) #define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) #define T41 0x289b7ec6 #define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) #define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) #define T44 0x04881d05 #define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) #define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) #define T47 0x1fa27cf8 #define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) #define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) #define T50 0x432aff97 #define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) #define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) #define T53 0x655b59c3 #define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) #define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) #define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) #define T57 0x6fa87e4f #define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) #define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) #define T60 0x4e0811a1 #define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) #define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) #define T63 0x2ad7d2bb #define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) static void md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) { md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = pms->abcd[3]; md5_word_t t; #if BYTE_ORDER > 0 /* Define storage only for big-endian CPUs. */ md5_word_t X[16]; #else /* Define storage for little-endian or both types of CPUs. */ md5_word_t xbuf[16]; const md5_word_t *X; #endif { #if BYTE_ORDER == 0 /* * Determine dynamically whether this is a big-endian or * little-endian machine, since we can use a more efficient * algorithm on the latter. */ static const int w = 1; if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ #endif #if BYTE_ORDER <= 0 /* little-endian */ { /* * On little-endian machines, we can process properly aligned * data without copying it. */ if (!((data - (const md5_byte_t *)0) & 3)) { /* data are properly aligned */ X = (const md5_word_t *)data; } else { /* not aligned */ memcpy(xbuf, data, 64); X = xbuf; } } #endif #if BYTE_ORDER == 0 else /* dynamic big-endian */ #endif #if BYTE_ORDER >= 0 /* big-endian */ { /* * On big-endian machines, we must arrange the bytes in the * right order. */ const md5_byte_t *xp = data; int i; # if BYTE_ORDER == 0 X = xbuf; /* (dynamic only) */ # else # define xbuf X /* (static only) */ # endif for (i = 0; i < 16; ++i, xp += 4) xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); } #endif } #define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) /* Round 1. */ /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ #define F(x, y, z) (((x) & (y)) | (~(x) & (z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + F(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 7, T1); SET(d, a, b, c, 1, 12, T2); SET(c, d, a, b, 2, 17, T3); SET(b, c, d, a, 3, 22, T4); SET(a, b, c, d, 4, 7, T5); SET(d, a, b, c, 5, 12, T6); SET(c, d, a, b, 6, 17, T7); SET(b, c, d, a, 7, 22, T8); SET(a, b, c, d, 8, 7, T9); SET(d, a, b, c, 9, 12, T10); SET(c, d, a, b, 10, 17, T11); SET(b, c, d, a, 11, 22, T12); SET(a, b, c, d, 12, 7, T13); SET(d, a, b, c, 13, 12, T14); SET(c, d, a, b, 14, 17, T15); SET(b, c, d, a, 15, 22, T16); #undef SET /* Round 2. */ /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ #define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + G(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 1, 5, T17); SET(d, a, b, c, 6, 9, T18); SET(c, d, a, b, 11, 14, T19); SET(b, c, d, a, 0, 20, T20); SET(a, b, c, d, 5, 5, T21); SET(d, a, b, c, 10, 9, T22); SET(c, d, a, b, 15, 14, T23); SET(b, c, d, a, 4, 20, T24); SET(a, b, c, d, 9, 5, T25); SET(d, a, b, c, 14, 9, T26); SET(c, d, a, b, 3, 14, T27); SET(b, c, d, a, 8, 20, T28); SET(a, b, c, d, 13, 5, T29); SET(d, a, b, c, 2, 9, T30); SET(c, d, a, b, 7, 14, T31); SET(b, c, d, a, 12, 20, T32); #undef SET /* Round 3. */ /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ #define H(x, y, z) ((x) ^ (y) ^ (z)) #define SET(a, b, c, d, k, s, Ti)\ t = a + H(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 5, 4, T33); SET(d, a, b, c, 8, 11, T34); SET(c, d, a, b, 11, 16, T35); SET(b, c, d, a, 14, 23, T36); SET(a, b, c, d, 1, 4, T37); SET(d, a, b, c, 4, 11, T38); SET(c, d, a, b, 7, 16, T39); SET(b, c, d, a, 10, 23, T40); SET(a, b, c, d, 13, 4, T41); SET(d, a, b, c, 0, 11, T42); SET(c, d, a, b, 3, 16, T43); SET(b, c, d, a, 6, 23, T44); SET(a, b, c, d, 9, 4, T45); SET(d, a, b, c, 12, 11, T46); SET(c, d, a, b, 15, 16, T47); SET(b, c, d, a, 2, 23, T48); #undef SET /* Round 4. */ /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ #define I(x, y, z) ((y) ^ ((x) | ~(z))) #define SET(a, b, c, d, k, s, Ti)\ t = a + I(b,c,d) + X[k] + Ti;\ a = ROTATE_LEFT(t, s) + b /* Do the following 16 operations. */ SET(a, b, c, d, 0, 6, T49); SET(d, a, b, c, 7, 10, T50); SET(c, d, a, b, 14, 15, T51); SET(b, c, d, a, 5, 21, T52); SET(a, b, c, d, 12, 6, T53); SET(d, a, b, c, 3, 10, T54); SET(c, d, a, b, 10, 15, T55); SET(b, c, d, a, 1, 21, T56); SET(a, b, c, d, 8, 6, T57); SET(d, a, b, c, 15, 10, T58); SET(c, d, a, b, 6, 15, T59); SET(b, c, d, a, 13, 21, T60); SET(a, b, c, d, 4, 6, T61); SET(d, a, b, c, 11, 10, T62); SET(c, d, a, b, 2, 15, T63); SET(b, c, d, a, 9, 21, T64); #undef SET /* Then perform the following additions. (That is increment each of the four registers by the value it had before this block was started.) */ pms->abcd[0] += a; pms->abcd[1] += b; pms->abcd[2] += c; pms->abcd[3] += d; } void md5_init(md5_state_t *pms) { pms->count[0] = pms->count[1] = 0; pms->abcd[0] = 0x67452301; pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; pms->abcd[3] = 0x10325476; } void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) { const md5_byte_t *p = data; int left = nbytes; int offset = (pms->count[0] >> 3) & 63; md5_word_t nbits = (md5_word_t)(nbytes << 3); if (nbytes <= 0) return; /* Update the message length. */ pms->count[1] += nbytes >> 29; pms->count[0] += nbits; if (pms->count[0] < nbits) pms->count[1]++; /* Process an initial partial block. */ if (offset) { int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); memcpy(pms->buf + offset, p, copy); if (offset + copy < 64) return; p += copy; left -= copy; md5_process(pms, pms->buf); } /* Process full blocks. */ for (; left >= 64; p += 64, left -= 64) md5_process(pms, p); /* Process a final partial block. */ if (left) memcpy(pms->buf, p, left); } void md5_finish(md5_state_t *pms, md5_byte_t digest[16]) { static const md5_byte_t pad[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; md5_byte_t data[8]; int i; /* Save the length before padding. */ for (i = 0; i < 8; ++i) data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); /* Pad to 56 bytes mod 64. */ md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); /* Append the length. */ md5_append(pms, data, 8); for (i = 0; i < 16; ++i) digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); } static const char hexchar[] = "0123456789abcdef"; char* md5_hex(const char *bytes, int nbytes) { char out[33]; char* o = out+32; char digest[16]; char *digestp = digest + 16; md5_state_t md5; out[32] = '\0'; md5_init(&md5); md5_append(&md5, (unsigned char*)bytes, nbytes); md5_finish(&md5, (unsigned char*)digest); do { *--o = hexchar[*--digestp&0x0F]; *--o = hexchar[(*digestp>>4)&0x0F]; } while(o != out); return strdup(out); } qstat-2.15/tee.h0000644000175000017500000000065712420765614010463 00000000000000/* * qstat * by Steve Jankowski * * Teeworlds protocol * Copyright 2008 ? Emiliano Leporati * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_TEE_H #define QSTAT_TEE_H #include "qserver.h" // Packet processing methods query_status_t deal_with_tee_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_tee_request_packet( struct qserver *server ); #endif qstat-2.15/a2s.c0000644000175000017500000003672512420765615010374 00000000000000/* * qstat * by Steve Jankowski * * New Half-Life2 query protocol * Copyright 2005 Ludwig Nussel * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #endif #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" #define A2S_GETCHALLENGE "\xFF\xFF\xFF\xFF\x57" #define A2S_CHALLENGERESPONSE 0x41 #define A2S_INFO "\xFF\xFF\xFF\xFF\x54Source Engine Query" #define A2S_INFORESPONSE_HL1 0x6D #define A2S_INFORESPONSE_HL2 0x49 #define A2S_PLAYER "\xFF\xFF\xFF\xFF\x55" #define A2S_PLAYERRESPONSE 0x44 #define A2S_PLAYER_INVALID_CHALLENGE "\xFF\xFF\xFF\xFF\x55\xFF\xFF\xFF\xFF" #define A2S_RULES "\xFF\xFF\xFF\xFF\x56" #define A2S_RULESRESPONSE 0x45 struct a2s_status { unsigned sent_challenge : 1; unsigned have_challenge : 1; unsigned sent_info : 1; unsigned have_info : 1; unsigned sent_player : 1; unsigned have_player : 1; unsigned sent_rules : 1; unsigned have_rules : 1; unsigned challenge; unsigned char type; }; query_status_t send_a2s_request_packet(struct qserver *server) { struct a2s_status* status = (struct a2s_status*)server->master_query_tag; if(qserver_send_initial(server, A2S_INFO, sizeof(A2S_INFO)) == -1) { return DONE_FORCE; } status->sent_info = 1; status->type = 0; if(get_server_rules || get_player_info) server->next_rule = ""; // trigger calling send_a2s_rule_request_packet return INPROGRESS; } query_status_t send_a2s_rule_request_packet(struct qserver *server) { struct a2s_status* status = (struct a2s_status*)server->master_query_tag; if(!get_server_rules && !get_player_info) { return DONE_FORCE; } if (server->retry1 < 0) { debug(3, "too may retries"); return DONE_FORCE; } while( 1 ) { if(!status->have_challenge) { debug(3, "sending challenge"); // Challenge Request was broken so instead we use a player request with an invalid // challenge which prompts the server to send a valid challenge // This was fixed as of the update 2009-08-26 //char buf[sizeof(A2S_PLAYER)-1+4] = A2S_PLAYER; //memcpy( buf + sizeof(A2S_PLAYER)-1, &status->challenge, 4 ); //if( SOCKET_ERROR == qserver_send_initial(server, buf, sizeof(buf)) ) if( SOCKET_ERROR == qserver_send_initial(server, A2S_GETCHALLENGE, sizeof(A2S_GETCHALLENGE)-1) ) { return SOCKET_ERROR; } status->sent_challenge = 1; break; } else if(get_server_rules && !status->have_rules) { char buf[sizeof(A2S_RULES)-1+4] = A2S_RULES; memcpy(buf+sizeof(A2S_RULES)-1, &status->challenge, 4); debug(3, "sending rule query"); if( SOCKET_ERROR == qserver_send_initial(server, buf, sizeof(buf)) ) { return SOCKET_ERROR; } status->sent_rules = 1; break; } else if(get_player_info && !status->have_player) { char buf[sizeof(A2S_PLAYER)-1+4] = A2S_PLAYER; memcpy( buf + sizeof(A2S_PLAYER)-1, &status->challenge, 4 ); debug(3, "sending player query"); if( SOCKET_ERROR == qserver_send_initial(server, buf, sizeof(buf)) ) { return SOCKET_ERROR; } status->sent_player = 1; break; } else { debug(3, "timeout"); // we are probably called due to timeout, restart. status->have_challenge = 0; status->have_rules = 0; } } return INPROGRESS; } query_status_t deal_with_a2s_packet(struct qserver *server, char *rawpkt, int pktlen) { struct a2s_status* status = (struct a2s_status*)server->master_query_tag; char* pkt = rawpkt; char buf[16]; char* str; unsigned cnt; 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, "\xFE\xFF\xFF\xFF", 4) ) { // fragmented packet unsigned char pkt_index, pkt_max; unsigned int pkt_id = 1; SavedData *sdata; if(pktlen < 9) goto out_too_short; pkt += 4; // format: // int sequenceNumber // byte packetId // packetId format: // bits 0 - 3 = packets position in the sequence ( 0 .. N - 1 ) // bits 4 - 7 = total number of packets // sequenceId memcpy( &pkt_id, pkt, 4 ); debug( 3, "sequenceId: %d", pkt_id ); pkt += 4; // packetId if ( 1 == status->type || 200 > server->protocol_version ) { // HL1 format // The lower four bits represent the number of packets (2 to 15) and // the upper four bits represent the current packet starting with 0 pkt_max = ((unsigned char)*pkt) & 15; pkt_index = ((unsigned char)*pkt) >> 4; debug( 3, "packetid[1]: 0x%hhx => idx: %hhu, max: %hhu", *pkt, pkt_index, pkt_max ); pkt++; pktlen -= 9; } else if ( 2 == status->type ) { // HL2 format // 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; pkt_max = ((unsigned char)*pkt); pkt_index = ((unsigned char)*(pkt+1)); debug( 3, "packetid[2]: 0x%hhx => idx: %hhu, max: %hhu", *pkt, pkt_index, pkt_max ); pkt+=4; pktlen -= 12; } else { malformed_packet( server, "Unable to determine packet format" ); return PKT_ERROR; } // 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( sdata->datalen); 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, "A2S type = %x", *pkt ); switch(*pkt++) { case A2S_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); send_a2s_rule_request_packet(server); break; case A2S_INFORESPONSE_HL1: if(pktlen < 28) goto out_too_short; status->type = 1; // ip:port str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; //server->server_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // server name str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->server_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // map str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->map_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // mod dir str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->game = strdup(pkt); add_rule(server, "gamedir", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // mod description str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "gamename", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; if( pktlen < 7 ) goto out_too_short; // num players server->num_players = (unsigned char)pkt[0]; // max players server->max_players = (unsigned char)pkt[1]; // version sprintf( buf, "%hhu", pkt[2] ); add_rule( server, "version", buf, 0 ); // dedicated add_rule( server, "dedicated", pkt[3] == 'd' ? "1" : "0", 0 ); // os switch( pkt[4] ) { case 'l': add_rule(server, "sv_os", "linux", 0); break; case 'w': add_rule(server, "sv_os", "windows", 0); break; default: buf[0] = pkt[4]; buf[1] = '\0'; add_rule(server, "sv_os", buf, 0); } // password add_rule(server, "password", pkt[5] ? "1" : "0" , 0); pkt += 6; pktlen -= 6; // mod info if ( pkt[0] ) { pkt++; pktlen--; // mod URL str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "mod_url", strdup( pkt ), 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // mod DL str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "mod_dl", strdup( pkt ), 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // mod Empty str = memchr(pkt, '\0', pktlen); pktlen -= str-pkt+1; pkt += str-pkt+1; if( pktlen < 10 ) goto out_too_short; // mod version sprintf( buf, "%u", swap_long_from_little(pkt)); add_rule( server, "mod_ver", buf, 0 ); pkt += 4; pktlen -= 4; // mod size sprintf( buf, "%u", swap_long_from_little(pkt)); add_rule( server, "mod_size", buf, 0 ); pkt += 4; pktlen -= 4; // svonly add_rule( server, "mod_svonly", ( *pkt ) ? "1" : "0" , 0 ); pkt++; pktlen--; // cldll add_rule( server, "mod_cldll", ( *pkt ) ? "1" : "0" , 0 ); pkt++; pktlen--; } if( pktlen < 2 ) goto out_too_short; // Secure add_rule( server, "secure", *pkt ? "1" : "0" , 0 ); pkt++; pktlen--; // Bots sprintf( buf, "%hhu", *pkt ); add_rule( server, "bots", buf, 0 ); pkt++; pktlen--; status->have_info = 1; server->retry1 = n_retries; server->next_player_info = server->num_players; break; case A2S_INFORESPONSE_HL2: if(pktlen < 1) goto out_too_short; status->type = 2; snprintf(buf, sizeof(buf), "%hhX", *pkt); add_rule(server, "protocol", buf, 0); ++pkt; --pktlen; // server name str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->server_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // map str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->map_name = strdup(pkt); pktlen -= str-pkt+1; pkt += str-pkt+1; // mod str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; server->game = strdup(pkt); add_rule(server, "gamedir", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // description str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "gamename", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; if(pktlen < 9) goto out_too_short; // pkt[0], pkt[1] steam appid server->protocol_version = (unsigned short)*pkt; server->num_players = (unsigned char)pkt[2]; server->max_players = (unsigned char)pkt[3]; // pkt[4] number of bots sprintf( buf, "%hhu", pkt[4] ); add_rule( server, "bots", buf, 0 ); add_rule(server, "dedicated", pkt[5]?"1":"0", 0); if(pkt[6] == 'l') { add_rule(server, "sv_os", "linux", 0); } else if(pkt[6] == 'w') { add_rule(server, "sv_os", "windows", 0); } else { buf[0] = pkt[6]; buf[1] = '\0'; add_rule(server, "sv_os", buf, 0); } if(pkt[7]) { snprintf(buf, sizeof(buf), "%hhu", (unsigned char)pkt[7]); add_rule(server, "password", buf, 0); } if(pkt[8]) { snprintf(buf, sizeof(buf), "%hhu", (unsigned char)pkt[8]); add_rule(server, "secure", buf, 0); } pkt += 9; pktlen -= 9; // version str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "version", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; // EDF if ( 1 <= pktlen ) { unsigned char edf = *pkt; debug(1, "EDF: 0x%02hhx", edf); pkt++; pktlen--; if ( edf & 0x80 ) { // game port unsigned short gameport; if(pktlen < 2) goto out_too_short; gameport = swap_short_from_little( pkt ); sprintf( buf, "%hu", gameport ); add_rule( server, "game_port", buf, 0 ); change_server_port( server, gameport, 0 ); pkt += 2; pktlen -= 2; } if (edf & 0x10) { // SteamId (long long) if (pktlen <8 ) { goto out_too_short; } pkt += 8; pktlen -= 8; } if ( edf & 0x40 ) { // spectator port unsigned short spectator_port; if(pktlen < 3) goto out_too_short; spectator_port = swap_short_from_little( pkt ); sprintf( buf, "%hu", spectator_port ); add_rule( server, "spectator_port", buf, 0 ); pkt += 2; pktlen -= 2; // spectator server name str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "spectator_server_name", pkt, 0); pktlen -= str-pkt+1; pkt += str-pkt+1; } if ( edf & 0x20 ) { // Keywords str = memchr(pkt, '\0', pktlen); if(!str) goto out_too_short; add_rule(server, "game_tags", pkt, 0); if (strncmp(pkt, "rust", 4) == 0) { // Rust is comma seperated tags char *keyword = strtok(pkt, ","); while (keyword != NULL) { if (strncmp(keyword, "cp", 2) == 0) { // current players override server->num_players = atoi(keyword+2); } else if (strncmp(keyword, "mp", 2) == 0) { // max players override server->max_players = atoi(keyword+2); } keyword = strtok(NULL, ","); } } pktlen -= str-pkt+1; pkt += str-pkt+1; } if (edf & 0x01) { // GameId (long long) if (pktlen <8 ) { goto out_too_short; } pkt += 8; pktlen -= 8; } } status->have_info = 1; server->retry1 = n_retries; server->next_player_info = server->num_players; break; case A2S_RULESRESPONSE: if(pktlen < 2) goto out_too_short; cnt = (unsigned char)pkt[0] + ((unsigned char)pkt[1]<<8); 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 A2S_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; idx = *pkt++; --pktlen; 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 = %s", idx, name ); p = add_player(server, server->n_player_info); if(p) { p->name = strdup(name); p->frags = swap_long_from_little(pkt); p->connect_time = swap_float_from_little(pkt+4); } pktlen -= 8; pkt += 8; } #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; } // vim: sw=4 ts=4 noet qstat-2.15/bfbc2.h0000644000175000017500000000070312420765615010655 00000000000000/* * qstat * by Steve Jankowski * * Battlefield Bad Company 2 protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_BFBC2_H #define QSTAT_BFBC2_H #include "qserver.h" // Packet processing methods query_status_t deal_with_bfbc2_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_bfbc2_request_packet( struct qserver *server ); #endif qstat-2.15/tm.c0000644000175000017500000002106512420765615010316 00000000000000/* * qstat * by Steve Jankowski * * Gamespy query protocol * Copyright 2005 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms * */ #include #ifndef _WIN32 #include #include #endif #include #include #include #include "debug.h" #include "qstat.h" #include "packet_manip.h" #define TM_XML_PREFIX "\n\nsystem.multicall\n\n" #define TM_XML_SUFFIX "\n" #define TM_SERVERINFO "methodNameGetServerOptionsparams\nmethodNameGetCurrentChallengeInfoparams\n" #define TM_PLAYERLIST "methodNameGetPlayerListparams1000\n" #define TM_AUTH_TEMPLATE "\nmethodNameAuthenticate\nparams\n%s\n%s\n" query_status_t send_tm_request_packet( struct qserver *server ) { char buf[2048]; char *xmlp = buf + 8; unsigned int len; char *user = get_param_value( server, "user", NULL ); char *password = get_param_value( server, "password", NULL ); if ( ! server->protocol_version ) { // No seen the version yet wait // register_send here to ensure that timeouts function correctly return register_send( server ); } // build the query xml len = sprintf( xmlp, TM_XML_PREFIX ); if ( user != NULL && password != NULL ) { len += sprintf( xmlp + len, TM_AUTH_TEMPLATE, user, password ); } else { // Default to User / User len += sprintf( xmlp + len, TM_AUTH_TEMPLATE, "User", "User" ); } // Always get Player info otherwise player count is invalid // TODO: add more calls to get full player info? server->flags |= TF_PLAYER_QUERY|TF_RULES_QUERY; len += sprintf( xmlp + len, TM_SERVERINFO ); len += sprintf( xmlp + len, TM_PLAYERLIST ); len += sprintf( xmlp + len, TM_XML_SUFFIX ); // First 4 bytes is the length of the request memcpy( buf, &len, 4 ); // Second 4 bytes is the handle identifier ( id ) memcpy( buf+4, &server->challenge, 4 ); // prep the details we need for multi packet responses // we expect at least 1 packet response server->saved_data.pkt_max = 1; return send_packet( server, buf, len + 8 ); } query_status_t deal_with_tm_packet( struct qserver *server, char *rawpkt, int pktlen ) { char *s; char *pkt = rawpkt; char *key = NULL, *value = NULL, *tmpp = NULL; char fullname[256]; struct player *player = NULL; int pkt_max = server->saved_data.pkt_max; unsigned total_len, expected_len; int method_response = 1; debug( 2, "processing..." ); s = rawpkt; // We may get the setup handle and the protocol version in one packet we may not // So we continue to parse if we see the handle if ( 4 <= pktlen && 0 == memcmp( pkt, "\x0b\x00\x00\x00", 4 ) ) { // setup handle identifier // greater 2^31 = XML-RPC, less = callback server->challenge = 0x80000001; if ( 4 == pktlen ) { return 0; } pktlen -= 4; pkt += 4; } if ( 11 <= pktlen && 1 == sscanf( pkt, "GBXRemote %d", &server->protocol_version ) ) { // Got protocol version send request send_tm_request_packet( server ); return 0; } if ( 8 <= pktlen && 0 == memcmp( pkt+4, &server->challenge, 4 ) ) { // first 4 bytes = the length // Note: We use pkt_id to store the length of the expected packet // this could cause loss but very unlikely unsigned long len; memcpy( &len, rawpkt, 4 ); // second 4 bytes = handle identifier we sent in the request if ( 8 == pktlen ) { // split packet // we have at least one more packet coming if ( ! add_packet( server, len, 0, 2, pktlen, rawpkt, 1 ) ) { // fatal error e.g. out of memory return -1; } return 0; } else { // ensure the length is stored server->saved_data.pkt_id = (int)len; s += 8; } } total_len = combined_length( server, server->saved_data.pkt_id ); expected_len = server->saved_data.pkt_id; debug( 2, "total: %d, expected: %d\n", total_len, expected_len ); if ( total_len < expected_len + 8 ) { // we dont have a complete response add the packet int last, new_max; if ( total_len + pktlen >= expected_len + 8 ) { last = 1; new_max = pkt_max; } else { last = 0; new_max = pkt_max + 1; } if ( ! add_packet( server, server->saved_data.pkt_id, pkt_max - 1, new_max, pktlen, rawpkt, 1 ) ) { // fatal error e.g. out of memory return -1; } if ( last ) { // we are the last packet run combine to call us back return combine_packets( server ); } return 0; } 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); } // Terminate the packet data pkt = (char*)malloc( pktlen + 1 ); if ( NULL == pkt ) { debug( 0, "Failed to malloc memory for packet terminator\n" ); return MEM_ERROR; } memcpy( pkt, rawpkt, pktlen ); pkt[pktlen] = '\0'; //fprintf( stderr, "S=%s\n", s ); s = strtok( pkt + 8, "\015\012" ); while ( NULL != s ) { //fprintf( stderr, "S=%s\n", s ); if ( 0 == strncmp( s, "", 14 ) ) { key = s + 14; tmpp = strstr( key, "" ); if ( NULL != tmpp ) { *tmpp = '\0'; } s = strtok( NULL, "\015\012" ); value = NULL; continue; } else if ( NULL != key && 0 == strncmp( s, "", 7 ) ) { // value s += 7; if ( 0 == strncmp( s, "", 8 ) ) { // String value = s+8; tmpp = strstr( s, "" ); } else if ( 0 == strncmp( s, "", 4 ) ) { // Int value = s+4; tmpp = strstr( s, "" ); } else if ( 0 == strncmp( s, "", 9 ) ) { // Boolean value = s+9; tmpp = strstr( s, "" ); } else if ( 0 == strncmp( s, "", 8 ) ) { // Double value = s+8; tmpp = strstr( s, "" ); } // also have struct and array but not interested in those if ( NULL != tmpp ) { *tmpp = '\0'; } if ( NULL != value ) { debug( 4, "%s = %s\n", key, value ); } } else if ( 0 == strncmp( s, "", 9 ) && 3 > method_response ) { // end of method response method_response++; } if ( NULL != value && NULL != key ) { switch( method_response ) { case 1: // GetServerOptions response if ( 0 == strcmp( "Name", key ) ) { server->server_name = strdup( value ); } else if ( 0 == strcmp( "CurrentMaxPlayers", key ) ) { server->max_players = atoi( value ); } else { sprintf( fullname, "server.%s", key ); add_rule( server, fullname, value, NO_FLAGS); } break; case 2: // GetCurrentChallengeInfo response if ( 0 == strcmp( "Name", key ) ) { server->map_name = strdup( value ); } else { sprintf( fullname, "challenge.%s", key ); add_rule( server, fullname, value, NO_FLAGS); } break; case 3: // GetPlayerList response // Player info if ( 0 == strcmp( "Login", key ) ) { player = add_player( server, server->n_player_info ); server->num_players++; } else if ( NULL != player ) { if ( 0 == strcmp( "NickName", key ) ) { player->name = strdup( value ); } else if ( 0 == strcmp( "PlayerId", key ) ) { //player->number = atoi( value ); } else if ( 0 == strcmp( "TeamId", key ) ) { player->team = atoi( value ); } else if ( 0 == strcmp( "IsSpectator", key ) ) { player->flags = player->flags & 1; } else if ( 0 == strcmp( "IsInOfficialMode", key ) ) { player->flags = player->flags & 2; } else if ( 0 == strcmp( "LadderRanking", key ) ) { player->score = atoi( value ); } } break; } value = NULL; } s = strtok( NULL, "\015\012" ); } free( pkt ); if ( 0 == strncmp( rawpkt + pktlen - 19, "", 17 ) ) { // last packet seen return DONE_FORCE; } return INPROGRESS; } qstat-2.15/info/0000755000175000017500000000000012420766316010540 500000000000000qstat-2.15/info/Makefile.am0000644000175000017500000000003712420765614012514 00000000000000EXTRA_DIST = $(wildcard *.txt) qstat-2.15/info/Makefile.in0000644000175000017500000002541112420766264012532 00000000000000# Makefile.in generated by automake 1.14.1 from Makefile.am. # @configure_input@ # Copyright (C) 1994-2013 Free Software Foundation, Inc. # This Makefile.in is free software; the Free Software Foundation # gives unlimited permission to copy and/or distribute it, # with or without modifications, as long as this notice is preserved. # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY, to the extent permitted by law; without # even the implied warranty of MERCHANTABILITY or FITNESS FOR A # PARTICULAR PURPOSE. @SET_MAKE@ VPATH = @srcdir@ am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' am__make_running_with_option = \ case $${target_option-} in \ ?) ;; \ *) echo "am__make_running_with_option: internal error: invalid" \ "target option '$${target_option-}' specified" >&2; \ exit 1;; \ esac; \ has_opt=no; \ sane_makeflags=$$MAKEFLAGS; \ if $(am__is_gnu_make); then \ sane_makeflags=$$MFLAGS; \ else \ case $$MAKEFLAGS in \ *\\[\ \ ]*) \ bs=\\; \ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ esac; \ fi; \ skip_next=no; \ strip_trailopt () \ { \ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ }; \ for flg in $$sane_makeflags; do \ test $$skip_next = yes && { skip_next=no; continue; }; \ case $$flg in \ *=*|--*) continue;; \ -*I) strip_trailopt 'I'; skip_next=yes;; \ -*I?*) strip_trailopt 'I';; \ -*O) strip_trailopt 'O'; skip_next=yes;; \ -*O?*) strip_trailopt 'O';; \ -*l) strip_trailopt 'l'; skip_next=yes;; \ -*l?*) strip_trailopt 'l';; \ -[dEDm]) skip_next=yes;; \ -[JT]) skip_next=yes;; \ esac; \ case $$flg in \ *$$target_option*) has_opt=yes; break;; \ esac; \ done; \ test $$has_opt = yes am__make_dryrun = (target_option=n; $(am__make_running_with_option)) am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) pkgdatadir = $(datadir)/@PACKAGE@ pkgincludedir = $(includedir)/@PACKAGE@ pkglibdir = $(libdir)/@PACKAGE@ pkglibexecdir = $(libexecdir)/@PACKAGE@ am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd install_sh_DATA = $(install_sh) -c -m 644 install_sh_PROGRAM = $(install_sh) -c install_sh_SCRIPT = $(install_sh) -c INSTALL_HEADER = $(INSTALL_DATA) transform = $(program_transform_name) NORMAL_INSTALL = : PRE_INSTALL = : POST_INSTALL = : NORMAL_UNINSTALL = : PRE_UNINSTALL = : POST_UNINSTALL = : build_triplet = @build@ host_triplet = @host@ subdir = info DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(install_sh) -d CONFIG_HEADER = $(top_builddir)/gnuconfig.h CONFIG_CLEAN_FILES = CONFIG_CLEAN_VPATH_FILES = AM_V_P = $(am__v_P_@AM_V@) am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) am__v_P_0 = false am__v_P_1 = : AM_V_GEN = $(am__v_GEN_@AM_V@) am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) am__v_GEN_0 = @echo " GEN " $@; am__v_GEN_1 = AM_V_at = $(am__v_at_@AM_V@) am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) am__v_at_0 = @ am__v_at_1 = SOURCES = DIST_SOURCES = am__can_run_installinfo = \ case $$AM_UPDATE_INFO_DIR in \ n|no|NO) false;; \ *) (install-info --version) >/dev/null 2>&1;; \ esac am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ AMTAR = @AMTAR@ AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ AUTOCONF = @AUTOCONF@ AUTOHEADER = @AUTOHEADER@ AUTOMAKE = @AUTOMAKE@ AWK = @AWK@ CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ ECHO_C = @ECHO_C@ ECHO_N = @ECHO_N@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ GREP = @GREP@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ LDFLAGS = @LDFLAGS@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ LTLIBOBJS = @LTLIBOBJS@ MAKEINFO = @MAKEINFO@ MKDIR_P = @MKDIR_P@ OBJEXT = @OBJEXT@ PACKAGE = @PACKAGE@ PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ PACKAGE_NAME = @PACKAGE_NAME@ PACKAGE_STRING = @PACKAGE_STRING@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ SET_MAKE = @SET_MAKE@ SHELL = @SHELL@ STRIP = @STRIP@ VERSION = @VERSION@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ abs_top_srcdir = @abs_top_srcdir@ ac_ct_CC = @ac_ct_CC@ am__include = @am__include@ am__leading_dot = @am__leading_dot@ am__quote = @am__quote@ am__tar = @am__tar@ am__untar = @am__untar@ bindir = @bindir@ build = @build@ build_alias = @build_alias@ build_cpu = @build_cpu@ build_os = @build_os@ build_vendor = @build_vendor@ builddir = @builddir@ datadir = @datadir@ datarootdir = @datarootdir@ docdir = @docdir@ dvidir = @dvidir@ exec_prefix = @exec_prefix@ host = @host@ host_alias = @host_alias@ host_cpu = @host_cpu@ host_os = @host_os@ host_vendor = @host_vendor@ htmldir = @htmldir@ includedir = @includedir@ infodir = @infodir@ install_sh = @install_sh@ libdir = @libdir@ libexecdir = @libexecdir@ localedir = @localedir@ localstatedir = @localstatedir@ mandir = @mandir@ mkdir_p = @mkdir_p@ oldincludedir = @oldincludedir@ pdfdir = @pdfdir@ prefix = @prefix@ program_transform_name = @program_transform_name@ psdir = @psdir@ sbindir = @sbindir@ sharedstatedir = @sharedstatedir@ srcdir = @srcdir@ sysconfdir = @sysconfdir@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ EXTRA_DIST = $(wildcard *.txt) all: all-am .SUFFIXES: $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) @for dep in $?; do \ case '$(am__configure_deps)' in \ *$$dep*) \ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ && { if test -f $@; then exit 0; else break; fi; }; \ exit 1;; \ esac; \ done; \ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign info/Makefile'; \ $(am__cd) $(top_srcdir) && \ $(AUTOMAKE) --foreign info/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ *config.status*) \ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ *) \ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ esac; $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(top_srcdir)/configure: $(am__configure_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(ACLOCAL_M4): $(am__aclocal_m4_deps) cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh $(am__aclocal_m4_deps): tags TAGS: ctags CTAGS: cscope cscopelist: distdir: $(DISTFILES) @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ list='$(DISTFILES)'; \ dist_files=`for file in $$list; do echo $$file; done | \ sed -e "s|^$$srcdirstrip/||;t" \ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ case $$dist_files in \ */*) $(MKDIR_P) `echo "$$dist_files" | \ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ sort -u` ;; \ esac; \ for file in $$dist_files; do \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -d $$d/$$file; then \ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ if test -d "$(distdir)/$$file"; then \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ fi; \ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ else \ test -f "$(distdir)/$$file" \ || cp -p $$d/$$file "$(distdir)/$$file" \ || exit 1; \ fi; \ done check-am: all-am check: check-am all-am: Makefile installdirs: install: install-am install-exec: install-exec-am install-data: install-data-am uninstall: uninstall-am install-am: all-am @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am installcheck: installcheck-am install-strip: if test -z '$(STRIP)'; then \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ install; \ else \ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ fi mostlyclean-generic: clean-generic: distclean-generic: -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) maintainer-clean-generic: @echo "This command is intended for maintainers to use" @echo "it deletes files that may require special tools to rebuild." clean: clean-am clean-am: clean-generic mostlyclean-am distclean: distclean-am -rm -f Makefile distclean-am: clean-am distclean-generic dvi: dvi-am dvi-am: html: html-am html-am: info: info-am info-am: install-data-am: install-dvi: install-dvi-am install-dvi-am: install-exec-am: install-html: install-html-am install-html-am: install-info: install-info-am install-info-am: install-man: install-pdf: install-pdf-am install-pdf-am: install-ps: install-ps-am install-ps-am: installcheck-am: maintainer-clean: maintainer-clean-am -rm -f Makefile maintainer-clean-am: distclean-am maintainer-clean-generic mostlyclean: mostlyclean-am mostlyclean-am: mostlyclean-generic pdf: pdf-am pdf-am: ps: ps-am ps-am: uninstall-am: .MAKE: install-am install-strip .PHONY: all all-am check check-am clean clean-generic cscopelist-am \ ctags-am distclean distclean-generic distdir dvi dvi-am html \ html-am info info-am install install-am install-data \ install-data-am install-dvi install-dvi-am install-exec \ install-exec-am install-html install-html-am install-info \ install-info-am install-man install-pdf install-pdf-am \ install-ps install-ps-am install-strip installcheck \ installcheck-am installdirs maintainer-clean \ maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ pdf-am ps ps-am tags-am uninstall uninstall-am # Tell versions [3.59,3.63) of GNU make to not export all variables. # Otherwise a system limit (for SysV at least) may be exceeded. .NOEXPORT: qstat-2.15/info/GhostRecon.txt0000644000175000017500000001435512420765614013304 00000000000000Ghost Recon - QStat notes ------------------------- The following Server Stats are pulled from the Ghost Recon Server - NOTE many other stats continue to work as normal due to the base qstat program. $SERVERNAME The name of the GR Server. $PLAYERS The number of Players that are playing, oberving or in the Lobby (note the ignoreserverplayer Argument above) $MAXPLAYERS The maximum players that the server will allow playing, oberving or in the Lobby (note the ignoreserverplayer Argument above) $MAP The Name of the MAP that is being used (NOTE not the Mission) $GAME The Mods that the server is running. Ex: mp1; is the Desert Seige Mod $(RULE:error) If an error occured there may be some detail here. IF the problm occurred very early in the interpretation then $SERVERNAME will hold the details. $(RULE:mission) The name of the Mission that the server is running. $(RULE:gamemode) What is the Game Mode that the server is in. Known values are COOP, TEAM and SOLO $(RULE:missiontype) What is the Mission Type. Known Values are: Mission, Firefight, Recon, Hamburger Hill, Last Man Standing, Sharpshooter, Search And Rescue, Domination, and Seige. $(RULE:dedicated) Is this server Dedicated; Yes or No. $(RULE:status) What is the Playing Status of the Server, values are Playing, Joining or Debrief. $(RULE:gametime) What is the Time limit for the Game. Values are 00:00, 05:00, 10:00, 15:00 20:00, 25:00, 30:00, 45:00 and 60:00. The 00:00 is for an unlimited game. The format of this uses the -ts, -tc and -tsw command line options. $(RULE:timeplayed) How long has this game been playing. The format of this uses the -ts, -tc and -tsw command line options. $(RULE:remainingtime) How much time is left in this game. The format of this uses the -ts, -tc and -tsw command line options. $(RULE:version) What is the Version number reported by the server. Patch 1.2 = 10.1010A, Patch 1.3 = 11.101A $(RULE:spawntype) What type of spawn is in use. Known Values are None, Infinite, Individual and Team. $(RULE:spawncount) How many spawns are allowed. Enhancment possibility to add $(IF:SPAWN) to filter out when spawntype is none. $(RULE:restrict) What Weapon restrictions are in force for the server. $(RULE:password) Does the Server have a join password defined Yes or No. $(RULE:ti) Is the server using the Threat Indicator. $(RULE:motd) What is the Message Of The Day - Note these can be quite big. $(RULE:patch) What is the patch level of the GR Server. $(RULE:usestarttime) Is the server configured to start a game after "starttimeset" (Yes) OR does everyone need to click on ready (no). $(RULE:starttimeset) What time is configured to automatically start the next round. $(RULE:debrieftime) How long does the server wait at the Debrief screen after a mission. $(RULE:respawnmin) How long must a dead player wait before he can repawn. $(RULE:respawnmax) What is the longest time that a user has to respawn. $(RULE:respawnsafe) How long after respawn is a player invulnerable/cannot damage others. $(RULE:allowobservers) Does the server allow observers? Yes or No $(RULE:startwait) How long untill the automatic start timer forces the next game to start. $(RULE:iff) What Identification - Friend or Foe is configured. None, Reticule or Names $PLAYERNAME What is the Players Name. $TEAMNUM What Team Number is the Player On. Known Values are 1,2,3,4,5. 1 is Team BLUE, 2 is Team Read, 3 is Team Yellow, 4 is Team Green, 5 is Unassigned (observer or in lobby) $TEAMNAME What is the Name of the Team, see above. $DEATHS What is the health of this player. 0 Alive, 1 Dead. Note if the player has spawns remaining this can change from 1 back to 0. Enhancement possibility to add $HEALTH or $(RULE:health). Hopefully RSE/UBI will add the Deaths, Frags, and Ping to the availible information. If this happens then it would be better to have a $HEALTH $(IF:DEATHS) and $(IFNOT:DEATHS) A Test to see if the player is dead. Usefull in this constuct: $(IF:DEATHS)Dead$(ENDIF)$(IFNOT:DEATHS)Alive$(ENDIF) Ghost Recon communicates on two UDP ports and one TCP stream. Normally TCP is on port 2346 and carries the game dialog. This is the port number that is mentioned in the game so we use it and apply an offset to get the port number for status queries. Port 2347 gives some high level server stats and 2348 gives fairly low level server stats. QStat is designed around a single port per server so the 2348 port is used. One down side to this is the lack of many meaningful detail player stats (Deaths, frags, hit percentage, ping etc.). I imagines that some of these are availible in the TCP stream but that would be difficult to add to a program like QStat. The Ghost Recon packets are variable structures with a lot of string lengths. This requires fairly defensive programming as Red Storm Entertainment is not forthcoming with any details. This release adds support for the GhostRecon game. Number one note is that Red Storm and UBI do not provide the information that many Quake based users expect. Specifically they do not make Frags, Deaths Connect Time or Pings availible - at least not as far as I can tell. That said there are quite a few things that are availible and allow a server administrator to make the status of his or her server available to the public via the web. This change uses all undocumented interfaces to the Ghost Recon server so will most likely break when you install a patch. It has been tested against the Desert Seige update and several public servers. It should work against the 1.2, 1.3, and 1.4 patches and Island Thunder add-on to Ghost Recon. The Ghost Recon game type is GRS. For command-line queries, use -grs There is one query argument to this server, ignoreserverplayer. This option controls whether the first player is ignored. Ghost Recon requires that the dedicated server program take up one of the player slots (always the first slot). The ignoreserverplayer option defaults to 'yes', so the "server player" will normally not be seen. If you are running a non-dedicated server, then set ignoreserverplayer to 'no' like this: -grs,ignoreserverplayer=no Otherwise you would not be able to display your own stats. Ghost Recon support provided by Bob Marriott. qstat-2.15/info/UT2003.txt0000644000175000017500000000374212420765614012064 00000000000000Unreal Tournament 2003 servers can be queried with the Gamespy style protocol (-gps) or with the native UT2003 protocol (-ut2s). The query port offset for Gamespy is usually 10. The query port offset for the native UT2003 protocol is always 1. The gamespy response returns a team name for each player, the UT2S response does not. Don't be concerned because the team name is the same for all players, and seems to be map name followed by the string ".xTeamRoster" Probably a bug in the UT2003 gamespy support. The UT2S response includes a player global statistics id. The gamespy response does not. However, this id is zero for all players on both demo and retail servers. I guess they don't have global stats implemented. The protocols return similar but different servers rules. In UT2S the rule names are all lower-case. In gamespy, they are mixed-case. Some of the rules overlap, but each returns info not available from the other protocol. In the UT2S response, the "Mutator" rule (the only one with mixed-case) may appear multiple times. If you use $(RULE:Mutator) only the value of the first Mutator will be output. UT2003 servers frequently do not return information for all of the players. I don't know why. UT2003 master server lists are available from Epic Games. Here's the description from the Unreal Technology page: --------------------- We have made server lists available via HTTP for both demo and full version UT2003 servers so that 3rd party server query tools can add UT2003 support. http://ut2003master.epicgames.com/serverlist/full-all.txt http://ut2003master.epicgames.com/serverlist/demo-all.txt These URLs contain a tab-separated list of server IP, game port and query port for all servers in our master server. The query port is the port number the server is listening on for UDP queries. The query format and response is exactly the same as UT 1. The source code to the game server's query responder is in the UdpGameSpyQuery UnrealScript class. --------------------- qstat-2.15/info/a2s.txt0000644000175000017500000001231612420765614011711 00000000000000Server Queries The Source engine allows you to query information from a running game server using UDP/IP packets. This document describes the packet formats and protocol to access this data. Basic Data Types All server queries consist of 5 basic types of data packed together into a data stream. All types are little endian. Name Description byte 8 bit character short 16 bit signed integer long 32 bit signed integer float 32 bit float value string variable length byte field, terminated by 0x00 Query Types The server responds to 4 queries: • A2S_SERVERQUERY_GETCHALLENGE - Returns a challenge number for use in the player and rules query. • A2S_INFO - Basic information about the server. • A2S_PLAYER - Details about each player on the server. • A2S_RULES - The rules the server is using. Queries should be sent in UDP packets to the listen port of the server, which is typically port 27015. A2S_SERVERQUERY_GETCHALLENGE Request format Challenge values are required for A2S_PLAYER and A2S_RULES requests, you can use this request to get one. Note: You can also send A2S_PLAYER and A2S_RULES queries with a challenge value of -1 (0xFF FF FF FF FF FF FF FF) and they will respond with a challenge value to use (using the reply format below). FF FF FF FF 57 Reply format Data Type Comment Type byte Should be equal to 'A' (0x41) Challenge long The challenge number to use Example reply: FF FF FF FF FF 41 32 42 59 45 53 93 43 71 A2S_INFO Request format Server info can be requested by sending the following byte values in a UDP packet to the server. FF FF FF FF 54 53 6F 75 72 63 65 20 45 6E 67 69 6E 65 20 51 75 65 72 79 00 Reply format Data Type Comment Type byte Should be equal to 'I' (0x49) Version byte Network version Hostname string The Servers name Map string The current map being played Game Directory string The Game type Game string A friendly string name for the game type Description AppID short Steam Application number (currently always set to 0) Num players byte The number of players currently on the server Max players byte Maximum allowed players for the server Num of bots byte Number of bot players currently on the server Dedicated byte Set to 1 for dedicated servers OS byte 'l' for Linux, 'w' for Windows Password byte If set to 1 a password is required to join this server Secure byte If set to 1 this server is running VAC Game Version string The version of the game Example reply: FF FF FF FF 49 02 67 61 6D 65 32 78 73 2E 63 6F ....I.game2xs.co 6D 20 43 6F 75 6E 74 65 72 2D 53 74 72 69 6B 65 m.Counter-Strike 20 53 6F 75 72 63 65 20 23 31 00 64 65 5F 64 75 .Source.#1.de_du 73 74 00 63 73 74 72 69 6B 65 00 43 6F 75 6E 74 st.cstrike.Count 65 72 2D 53 74 72 69 6B 65 00 00 00 0B 28 00 64 er-Strike....(.d 6C 00 00 31 2e 31 2e 30 2e 31 36 00 l..1.1.0.16 A2S_PLAYER Request format FF FF FF FF 55 <4 byte challenge number> The challenge number can either be set to -1 (0xFF FF FF FF FF FF FF FF) to have the server reply with S2C_CHALLENGE, or use the value from a previous A2S_SERVERQUERY_GETCHALLENGE request. Reply format The players response has two sections, the initial header: Data Type Comment Type byte Should be equal to 'D' (0x44) Num Players byte The number of players reported in this response Then for each player the following fields are sent: Data Type Comment Index byte The index into [0.. Num Players] for this entry Player Name string Player's name Kills long Number of kills this player has Time connected float The time in seconds this player has been connected A2S_RULES Request format FF FF FF FF 56 <4 byte challenge number> The challenge number can either be set to -1 (0xFF FF FF FF FF FF FF FF) to have the server reply with S2C_CHALLENGE, or use the value from a previous A2S_SERVERQUERY_GETCHALLENGE request. Reply format The rules response has two sections, the initial header: Data Type Comment Type byte Should be equal to 'E' (0x45) Num Rules short The number of rules reported in this response Then for each rule the following fields are sent: Data Type Comment Rule Name string The name of the rule Rule Value string The rules value ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ (C) 2004 Valve Corporation. All rights reserved. Valve, the Valve logo, Half-Life, the Half-Life logo, the Lambda logo, Steam, the Steam logo, Team Fortress, the Team Fortress logo, Opposing Force, Day of Defeat, the Day of Defeat logo, Counter-Strike, the Counter-Strike logo, Source, the Source logo, Hammer and Counter-Strike: Condition Zero are trademarks and/or registered trademarks of Valve Corporation. Microsoft and Visual Studio are trademarks and/or registered trademarks of Microsoft Corporation. All other trademarks are property of their respective owners. qstat-2.15/ksp.h0000644000175000017500000000065312420765614010477 00000000000000/* * qstat * by Steve Jankowski * * KSP query protocol * Copyright 2014 Steven Hartland * * Licensed under the Artistic License, see LICENSE.txt for license terms */ #ifndef QSTAT_KSP_H #define QSTAT_KSP_H #include "qserver.h" // Packet processing methods query_status_t deal_with_ksp_packet( struct qserver *server, char *pkt, int pktlen ); query_status_t send_ksp_request_packet( struct qserver *server ); #endif