diff --git a/code/gamespy/sv_gqueryreporting.c b/code/gamespy/sv_gqueryreporting.c index 985918ce..3d549504 100644 --- a/code/gamespy/sv_gqueryreporting.c +++ b/code/gamespy/sv_gqueryreporting.c @@ -21,7 +21,7 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /****** -gqueryreporting.h +.c GameSpy Query & Reporting SDK Copyright 2000 GameSpy Industries, Inc @@ -84,15 +84,14 @@ Fax(949)798-4299 INCLUDES ********/ #if defined(applec) || defined(THINK_C) || defined(__MWERKS__) && !defined(__KATANA__) && !defined(__mips64) - #include "::nonport.h" +#include "::nonport.h" #else - #include "nonport.h" +#include "nonport.h" #endif #include "sv_gqueryreporting.h" #include #include - #include #if !defined(UNDER_CE) && !defined(__KATANA__) #include @@ -116,88 +115,78 @@ whether you need this or not. TYPEDEFS ********/ typedef unsigned char uchar; +#if defined(_LINUX) || defined(__linux__) +typedef unsigned int qrsocklen_t; +#else +typedef int qrsocklen_t; +#endif -typedef enum {qtunknown, qtbasic, qtinfo, qtrules, qtplayers, qtstatus, qtpackets, qtecho, qtsecure} query_t; - -struct qr_implementation_s +typedef enum { - SOCKET querysock; - SOCKET hbsock; - char gamename[64]; - char secret_key[128]; - qr_querycallback_t qr_basic_callback; - qr_querycallback_t qr_info_callback; - qr_querycallback_t qr_rules_callback; - qr_querycallback_t qr_players_callback; - unsigned long lastheartbeat; - int queryid; - int packetnumber; - int qport; - char no_query; - struct sockaddr_in master_saddr; - qr_custom_handler_t qr_custom_handler; - void *udata; -}; + qtunknown, + qtbasic, + qtinfo, + qtrules, + qtplayers, + qtstatus, + qtpackets, + qtecho, + qtsecure +} query_t; +typedef struct qr_implementation_s +{ + SOCKET querysock; + SOCKET hbsock; + char gamename[64]; + char secret_key[128]; + qr_querycallback_t qr_basic_callback; + qr_querycallback_t qr_info_callback; + qr_querycallback_t qr_rules_callback; + qr_querycallback_t qr_players_callback; + unsigned long lastheartbeat; + int queryid; + int packetnumber; + int qport; + char no_query; + struct sockaddr_in hbaddr; + qr_cdkey_process_t cdkeyprocess; + void* udata; +}* qr_t; /******** VARS ********/ -static const char *queries[]={"","basic","info","rules","players","status","packets", "echo", "secure"}; +static const char* queries[] = {"", "basic", "info", "rules", "players", "status", "packets", "echo", "secure"}; static struct sockaddr_in hbaddr; -static struct qr_implementation_s static_rec = {INVALID_SOCKET, INVALID_SOCKET}; +struct qr_implementation_s static_rec = {INVALID_SOCKET, INVALID_SOCKET}; static qr_t current_rec = &static_rec; char qr_hostname[64] = MASTER_ADDR; +static struct sockaddr_in MasterList[8]; +static char keyvalue[8192]; +static int MasterCount; + /******** PROTOTYPES ********/ static void send_heartbeat(qr_t qrec, int statechanged); -static void parse_query(qr_t qrec, char *query, struct sockaddr *sender); -static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent); -static int do_connect(SOCKET sock, char *addr, int port, struct sockaddr_in *master_saddr); +static void qr_parse_query(qr_t qrec, char* query, int len, struct sockaddr* sender); +static int do_connect(SOCKET sock, char* addr, int port, struct sockaddr_in* hbaddr); void qr_check_queries(qr_t qrec); void qr_check_send_heartbeat(qr_t qrec); -void init_qrec( - qr_t *qrec, - int baseport, - SOCKET hbsock, - SOCKET querysock, - const char *gamename, - const char *secret_key, - qr_querycallback_t qr_basic_callback, - qr_querycallback_t qr_info_callback, - qr_querycallback_t qr_rules_callback, - qr_querycallback_t qr_players_callback, - void *userdata -) -{ - if (qrec == NULL) - { - current_rec = &static_rec; - } - else - { - current_rec = (qr_t)gsimalloc(sizeof(struct qr_implementation_s)); - *qrec = current_rec; - } - strcpy(current_rec->gamename,gamename); - strcpy(current_rec->secret_key,secret_key); - current_rec->qport = baseport; - current_rec->lastheartbeat = 0; - current_rec->hbsock = hbsock; - current_rec->querysock = querysock; - current_rec->packetnumber = 0; - current_rec->queryid = 1; - current_rec->no_query = 1; - current_rec->udata = userdata; - current_rec->qr_basic_callback = qr_basic_callback; - current_rec->qr_info_callback = qr_info_callback; - current_rec->qr_players_callback = qr_players_callback; - current_rec->qr_rules_callback = qr_rules_callback; - current_rec->qr_custom_handler = NULL; -} +static void init_qrec(qr_t* qrec, + int baseport, + SOCKET hbsock, + SOCKET querysock, + const char* gamename, + const char* secret_key, + qr_querycallback_t qr_basic_callback, + qr_querycallback_t qr_info_callback, + qr_querycallback_t qr_rules_callback, + qr_querycallback_t qr_players_callback, + void* userdata); /****************************************************************************/ /* PUBLIC FUNCTIONS */ @@ -205,262 +194,331 @@ void init_qrec( /* qr_init: Initializes the sockets, etc. Returns an error value if an error occured, or 0 otherwise */ -int qr_init(qr_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key, - qr_querycallback_t qr_basic_callback, - qr_querycallback_t qr_info_callback, - qr_querycallback_t qr_rules_callback, - qr_querycallback_t qr_players_callback, - void *userdata) +int qr_init(qr_t* qrec, + const char* ip, + int baseport, + const char* gamename, + const char* secret_key, + qr_querycallback_t qr_basic_callback, + qr_querycallback_t qr_info_callback, + qr_querycallback_t qr_rules_callback, + qr_querycallback_t qr_players_callback, + void* userdata) { - int lasterror; - struct sockaddr_in saddr; - int saddrlen; - int maxport; - SOCKET querysock; - SOCKET hbsock; + int lasterror; + struct sockaddr_in saddr; + qrsocklen_t saddrlen; + int maxport; + SOCKET querysock; + SOCKET hbsock; - if (qrec != NULL) //init it to empty - *qrec = NULL; - //create our sockets - SocketStartUp(); + if (qrec != NULL) //init it to empty + *qrec = NULL; + //create our sockets + SocketStartUp(); - querysock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); + querysock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); #ifdef TCP_HEARTBEATS - hbsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + hbsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); #else - hbsock = querysock; //share the socket + hbsock = querysock; //share the socket #endif - if (INVALID_SOCKET == querysock || INVALID_SOCKET == hbsock) - { - return E_GOA_WSOCKERROR; - } + if (INVALID_SOCKET == querysock || INVALID_SOCKET == hbsock) { + return E_GOA_WSOCKERROR; + } - maxport = baseport + NUM_PORTS_TO_TRY; - while (baseport < maxport) - { - get_sockaddrin(ip,baseport,&saddr,NULL); - if (saddr.sin_addr.s_addr == htonl(0x7F000001)) //localhost -- we don't want that! - saddr.sin_addr.s_addr = INADDR_ANY; - - - lasterror = bind(querysock, (struct sockaddr *)&saddr, sizeof(saddr)); - if (lasterror == 0) - break; //we found a port - baseport++; - } + lasterror = 0; + maxport = baseport + NUM_PORTS_TO_TRY; + while (baseport < maxport) { + get_sockaddrin(ip, baseport, &saddr, NULL); + if (saddr.sin_addr.s_addr == htonl(0x7F000001)) //localhost -- we don't want that! + saddr.sin_addr.s_addr = INADDR_ANY; - if (lasterror != 0) //we weren't able to find a port - { - return E_GOA_BINDERROR; - } + lasterror = bind(querysock, (struct sockaddr*)&saddr, sizeof(saddr)); + if (lasterror == 0) + break; //we found a port + baseport++; + } + if (lasterror != 0) //we weren't able to find a port + { + return E_GOA_BINDERROR; + } - if (baseport == 0) //we bound it dynamically - { - saddrlen = sizeof(saddr); - lasterror = getsockname(querysock,(struct sockaddr *)&saddr, &saddrlen); - if (lasterror) - return E_GOA_BINDERROR; - baseport = ntohs(saddr.sin_port); - } + if (baseport == 0) //we bound it dynamically + { + saddrlen = sizeof(saddr); + lasterror = getsockname(querysock, (struct sockaddr*)&saddr, &saddrlen); + if (lasterror) + return E_GOA_BINDERROR; + baseport = ntohs(saddr.sin_port); + } - init_qrec( - qrec, - baseport, - hbsock, - hbsock, - gamename, - secret_key, - qr_basic_callback, - qr_info_callback, - qr_rules_callback, - qr_players_callback, - userdata - ); + init_qrec(qrec, + baseport, + hbsock, + querysock, + gamename, + secret_key, + qr_basic_callback, + qr_info_callback, + qr_rules_callback, + qr_players_callback, + userdata); if (!qrec) { qrec = ¤t_rec; } - return do_connect(hbsock, qr_hostname, MASTER_PORT, &(*qrec)->master_saddr); + return do_connect(hbsock, MASTER_ADDR, MASTER_PORT, &(*qrec)->hbaddr); +} +void init_qrec(qr_t* qrec, + int qport, + SOCKET hbsock, + SOCKET querysock, + const char* gamename, + const char* secret_key, + qr_querycallback_t qr_basic_callback, + qr_querycallback_t qr_info_callback, + qr_querycallback_t qr_rules_callback, + qr_querycallback_t qr_players_callback, + void* userdata) +{ + qr_t cr; + + if (qrec == NULL) { + cr = &static_rec; + } else { + *qrec = (qr_t)malloc(sizeof(struct qr_implementation_s)); + cr = *qrec; + } + + strcpy(cr->gamename, gamename); + strcpy(cr->secret_key, secret_key); + + cr->qport = qport; + cr->lastheartbeat = 0; + cr->hbsock = hbsock; + cr->querysock = querysock; + cr->packetnumber = 0; + cr->queryid = 1; + cr->no_query = 1; + cr->udata = userdata; + cr->qr_basic_callback = qr_basic_callback; + cr->qr_info_callback = qr_info_callback; + cr->qr_players_callback = qr_players_callback; + cr->qr_rules_callback = qr_rules_callback; + cr->cdkeyprocess = NULL; +} + +int qr_init_socket(qr_t* qrec, + unsigned int s, + const char* gamename, + const char* secret_key, + qr_querycallback_t qr_basic_callback, + qr_querycallback_t qr_info_callback, + qr_querycallback_t qr_rules_callback, + qr_querycallback_t qr_players_callback, + void* userdata) +{ + if (qrec) { + *qrec = NULL; + } + + SocketStartUp(); + init_qrec(qrec, + 0, + s, + s, + gamename, + secret_key, + qr_basic_callback, + qr_info_callback, + qr_rules_callback, + qr_players_callback, + userdata); + + return do_connect(s, MASTER_ADDR, MASTER_PORT, &(*qrec)->hbaddr); } /* qr_process_queries: Processes any waiting queries, and sends a heartbeat if 5 minutes have elapsed */ void qr_process_queries(qr_t qrec) { - if (qrec == NULL) - qrec = current_rec; - qr_check_send_heartbeat(qrec); - qr_check_queries(qrec); + if (qrec == NULL) + qrec = current_rec; + qr_check_send_heartbeat(qrec); + qr_check_queries(qrec); } - /* qr_process_queries_no_heartbeat: Processes any waiting queries, but never sends heartbeats */ void qr_process_queries_no_heartbeat(qr_t qrec) { - if (qrec == NULL) - qrec = current_rec; - qr_check_queries(qrec); + if (qrec == NULL) + qrec = current_rec; + qr_check_queries(qrec); } - - /* qr_check_queries: Processes any waiting queries */ void qr_check_queries(qr_t qrec) { - static char indata[INBUF_LEN]; //256 byte input buffer - struct sockaddr_in saddr; - int saddrlen = sizeof(struct sockaddr_in); - fd_set set; - struct timeval timeout = {0,0}; - int error; + static char indata[INBUF_LEN]; //256 byte input buffer + struct sockaddr_in saddr; + qrsocklen_t saddrlen = sizeof(struct sockaddr_in); + fd_set set; + struct timeval timeout = {0, 0}; + int error; - if (INVALID_SOCKET == qrec->querysock) - return; //no sockets to work with! + if (0 == qrec->qport) + return; - FD_ZERO ( &set ); - FD_SET ( qrec->querysock, &set ); + FD_ZERO(&set); + FD_SET(qrec->querysock, &set); - while (1) - { - error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); - if (-1 == error || 0 == error) - return; - //else we have data - error = recvfrom(qrec->querysock, indata, INBUF_LEN - 1, 0, (struct sockaddr *)&saddr, &saddrlen); - if (error != -1) - { - indata[error] = '\0'; - parse_query(qrec, indata, (struct sockaddr *)&saddr); - } - } + while (1) { + error = select(FD_SETSIZE, &set, NULL, NULL, &timeout); + if (gsiSocketIsError(error) || error == 0) + return; + //else we have data + error = recvfrom(qrec->querysock, indata, INBUF_LEN - 1, 0, (struct sockaddr*)&saddr, &saddrlen); + if (gsiSocketIsNotError(error)) { + indata[error] = '\0'; + qr_parse_query(qrec, indata, error, (struct sockaddr*)&saddr); + } + } } /* check_send_heartbeat: Perform any scheduled outgoing heartbeats, (every 5 minutes) */ void qr_check_send_heartbeat(qr_t qrec) { - unsigned long tc = current_time(); + unsigned long tc = current_time(); - if (INVALID_SOCKET == qrec->hbsock) - return; //no sockets to work with! + if (INVALID_SOCKET == qrec->hbsock) + return; //no sockets to work with! - //check if we need to send a heartbet - if (tc - qrec->lastheartbeat > HB_TIME || qrec->lastheartbeat == 0 || tc < qrec->lastheartbeat) - send_heartbeat(qrec,0); - else if (qrec->no_query > 0 && tc - qrec->lastheartbeat > FIRST_HB_TIME) - { //check to see if we haven't gotten a query yet - send_heartbeat(qrec, 0); - qrec->no_query++; - if (qrec->no_query > MAX_FIRST_COUNT) - qrec->no_query = 0; //stop trying to get first query - } + //check if we need to send a heartbet + if (tc - qrec->lastheartbeat > HB_TIME || qrec->lastheartbeat == 0 || tc < qrec->lastheartbeat) + send_heartbeat(qrec, 0); + else if (qrec->no_query > 0 + && tc - qrec->lastheartbeat > FIRST_HB_TIME) { //check to see if we haven't gotten a query yet + send_heartbeat(qrec, 0); + qrec->no_query++; + if (qrec->no_query > MAX_FIRST_COUNT) + qrec->no_query = 0; //stop trying to get first query + } } /* qr_send_statechanged: Sends a statechanged heartbeat, call when your gamemode changes */ void qr_send_statechanged(qr_t qrec) { - if (qrec == NULL) - qrec = current_rec; - send_heartbeat(qrec, 1); + if (qrec == NULL) + qrec = current_rec; + send_heartbeat(qrec, 1); +} + +void qr_send_exiting(qr_t qrec) +{ + if (qrec == NULL) + qrec = current_rec; + send_heartbeat(qrec, 2); } /* qr_shutdown: Cleans up the sockets and shuts down */ void qr_shutdown(qr_t qrec) { - if (qrec == NULL) - qrec = current_rec; - if (INVALID_SOCKET != qrec->querysock) - { - closesocket(qrec->querysock); - } - if (INVALID_SOCKET != qrec->hbsock && qrec->hbsock != qrec->querysock) - { - closesocket(qrec->hbsock); - } - qrec->hbsock = INVALID_SOCKET; - qrec->querysock = INVALID_SOCKET; - qrec->lastheartbeat = 0; - if (qrec != &static_rec) //need to gsifree it, it was dynamically allocated - { - gsifree(qrec); - } - SocketShutDown(); + if (qrec == NULL) + qrec = current_rec; + if (INVALID_SOCKET != qrec->querysock && qrec->qport != 0) { + closesocket(qrec->querysock); + } + if (INVALID_SOCKET != qrec->hbsock && qrec->hbsock != qrec->querysock) { + closesocket(qrec->hbsock); + } + qrec->hbsock = INVALID_SOCKET; + qrec->querysock = INVALID_SOCKET; + qrec->lastheartbeat = 0; + if (qrec != &static_rec) //need to gsifree it, it was dynamically allocated + { + gsifree(qrec); + } + SocketShutDown(); } /****************************************************************************/ -static int do_connect(SOCKET sock, char *addr, int port, struct sockaddr_in *master_saddr) +static int do_connect(SOCKET sock, char* addr, int port, struct sockaddr_in* hbaddr) { #ifdef TCP_HEARTBEATS - struct sockaddr_in saddr; + struct sockaddr_in saddr; - get_sockaddrin(addr, port,&saddr,NULL); + get_sockaddrin(addr, port, &saddr, NULL); - if (connect (sock, (struct sockaddr *) &saddr, sizeof(saddr)) == -1) - { - return E_GOA_CONNERROR; - } + if (connect(sock, (struct sockaddr*)&saddr, sizeof(saddr)) == SOCKET_ERROR) { + return E_GOA_CONNERROR; + } + + add_master(&saddr); #else - get_sockaddrin(addr, port, master_saddr, NULL); + get_sockaddrin(addr, port, hbaddr, NULL); + add_master(hbaddr); #endif - return 0; + return 0; } /* Return a sockaddrin for the given host (numeric or DNS) and port) Returns the hostent in savehent if it is not NULL */ -static int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent) +int get_sockaddrin(const char* host, int port, struct sockaddr_in* saddr, struct hostent** savehent) { - struct hostent *hent; - - saddr->sin_family = AF_INET; - saddr->sin_port = htons((unsigned short)port); - if (host == NULL) - saddr->sin_addr.s_addr = INADDR_ANY; - else - saddr->sin_addr.s_addr = inet_addr(host); - - if (saddr->sin_addr.s_addr == INADDR_NONE && strcmp(host,"255.255.255.255") != 0) - { - hent = gethostbyname(host); - if (!hent) - return 0; - saddr->sin_addr.s_addr = *(unsigned int *)hent->h_addr_list[0]; - } - if (savehent != NULL) - *savehent = hent; - return 1; - -} + struct hostent* hent; + char broadcast_t[] = { + '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '.', '2', '5', '5', '\0'}; //255.255.255.255 + hent = 0; + memset(saddr, 0, sizeof(struct sockaddr_in)); + saddr->sin_family = AF_INET; + saddr->sin_port = htons((unsigned short)port); + if (host == NULL) + saddr->sin_addr.s_addr = INADDR_ANY; + else + saddr->sin_addr.s_addr = inet_addr(host); + if (saddr->sin_addr.s_addr == INADDR_NONE && strcmp(host, broadcast_t) != 0) { + hent = gethostbyname(host); + if (!hent) + return 0; + saddr->sin_addr.s_addr = *(u_long*)hent->h_addr_list[0]; + } + if (savehent != NULL) + *savehent = hent; + return 1; +} /* value_for_key: this returns a value for a certain key in s, where s is a string containing key\value pairs. If the key does not exist, it returns NULL. Note: the value is stored in a common buffer. If you want to keep it, make a copy! */ -static char *value_for_key(const char *s, const char *key) +static char* value_for_key(const char* s, const char* key) { - static int valueindex; - char *pos,*pos2; - char keyspec[256]="\\"; - static char value[2][256]; + static int valueindex; + char *pos, *pos2; + char keyspec[256] = "\\"; + static char value[2][256]; - valueindex ^= 1; - strcat(keyspec,key); - strcat(keyspec,"\\"); - pos = strstr(s,keyspec); - if (!pos) - return NULL; - pos += strlen(keyspec); - pos2 = value[valueindex]; - while (*pos && *pos != '\\') - *pos2++ = *pos++; - *pos2 = '\0'; - return value[valueindex]; + valueindex ^= 1; + strcat(keyspec, key); + strcat(keyspec, "\\"); + pos = strstr(s, keyspec); + if (!pos) + return NULL; + pos += strlen(keyspec); + pos2 = value[valueindex]; + while (*pos && *pos != '\\') + *pos2++ = *pos++; + *pos2 = '\0'; + return value[valueindex]; } /*****************************************************************************/ @@ -468,310 +526,322 @@ static char *value_for_key(const char *s, const char *key) #ifndef _GUTIL #define _GUTIL -static void swap_byte ( uchar *a, uchar *b ) +static void swap_byte(uchar* a, uchar* b) { - uchar swapByte; - - swapByte = *a; - *a = *b; - *b = swapByte; + uchar swapByte; + + swapByte = *a; + *a = *b; + *b = swapByte; } -static uchar encode_ct ( uchar c ) +static uchar encode_ct(uchar c) { - if (c < 26) return ('A'+c); - if (c < 52) return ('a'+c-26); - if (c < 62) return ('0'+c-52); - if (c == 62) return ('+'); - if (c == 63) return ('/'); - - return 0; + if (c < 26) + return ('A' + c); + if (c < 52) + return ('a' + c - 26); + if (c < 62) + return ('0' + c - 52); + if (c == 62) + return ('+'); + if (c == 63) + return ('/'); + + return 0; } -void gs_encode ( uchar *ins, int size, uchar *result ) +void gs_encode(uchar* ins, int size, uchar* result) { - int i,pos; - uchar trip[3]; - uchar kwart[4]; - - i=0; - while (i < size) - { - for (pos=0 ; pos <= 2 ; pos++, i++) - if (i < size) trip[pos] = *ins++; - else trip[pos] = '\0'; - kwart[0] = (trip[0]) >> 2; - kwart[1] = (((trip[0]) & 3) << 4) + ((trip[1]) >> 4); - kwart[2] = (((trip[1]) & 15) << 2) + ((trip[2]) >> 6); - kwart[3] = (trip[2]) & 63; - for (pos=0; pos <= 3; pos++) *result++ = encode_ct(kwart[pos]); - } - *result='\0'; + int i, pos; + uchar trip[3]; + uchar kwart[4]; + + i = 0; + while (i < size) { + for (pos = 0; pos <= 2; pos++, i++) + if (i < size) + trip[pos] = *ins++; + else + trip[pos] = '\0'; + kwart[0] = (trip[0]) >> 2; + kwart[1] = (((trip[0]) & 3) << 4) + ((trip[1]) >> 4); + kwart[2] = (((trip[1]) & 15) << 2) + ((trip[2]) >> 6); + kwart[3] = (trip[2]) & 63; + for (pos = 0; pos <= 3; pos++) + *result++ = encode_ct(kwart[pos]); + } + *result = '\0'; } -void gs_encrypt ( uchar *key, int key_len, uchar *buffer_ptr, int buffer_len ) -{ - short counter; - uchar x, y, xorIndex; - uchar state[256]; - - for ( counter = 0; counter < 256; counter++) state[counter] = (uchar) counter; - - x = 0; y = 0; - for ( counter = 0; counter < 256; counter++) - { - y = (key[x] + state[counter] + y) % 256; - x = (x + 1) % key_len; - swap_byte ( &state[counter], &state[y] ); - } - - x = 0; y = 0; - for ( counter = 0; counter < buffer_len; counter ++) - { - x = (x + buffer_ptr[counter] + 1) % 256; - y = (state[x] + y) % 256; - swap_byte ( &state[x], &state[y] ); - xorIndex = (state[x] + state[y]) % 256; - buffer_ptr[counter] ^= state[xorIndex]; - } +void gs_encrypt(uchar* key, int key_len, uchar* buffer_ptr, int buffer_len) +{ + short counter; + uchar x, y, xorIndex; + uchar state[256]; + + for (counter = 0; counter < 256; counter++) + state[counter] = (uchar)counter; + + x = 0; + y = 0; + for (counter = 0; counter < 256; counter++) { + y = (key[x] + state[counter] + y) % 256; + x = (x + 1) % key_len; + swap_byte(&state[counter], &state[y]); + } + + x = 0; + y = 0; + for (counter = 0; counter < buffer_len; counter++) { + x = (x + buffer_ptr[counter] + 1) % 256; + y = (state[x] + y) % 256; + swap_byte(&state[x], &state[y]); + xorIndex = (state[x] + state[y]) % 256; + buffer_ptr[counter] ^= state[xorIndex]; + } } /*****************************************************************************/ #endif /* packet_send: sends a key\value packet. Appends the queryid key\value pair. Clears the buffer */ -static void packet_send(qr_t qrec, struct sockaddr *addr, char *buffer) +static void packet_send(qr_t qrec, struct sockaddr* addr, char* buffer) { - char keyvalue[80]; - - if (strlen(buffer) == 0) - return; //dont need to send an empty one! - qrec->packetnumber++; //packet numbers start at 1 - snprintf(keyvalue,sizeof(keyvalue),"\\queryid\\%d.%d",qrec->queryid, qrec->packetnumber); - strcat(buffer,keyvalue); - sendto(qrec->querysock, buffer, strlen(buffer), 0, addr, sizeof(struct sockaddr_in)); - buffer[0]='\0'; + char keyvalue[80]; + + if (strlen(buffer) == 0) + return; //dont need to send an empty one! + qrec->packetnumber++; //packet numbers start at 1 + snprintf(keyvalue, sizeof(keyvalue), "\\queryid\\%d.%d", qrec->queryid, qrec->packetnumber); + strcat(buffer, keyvalue); + sendto(qrec->querysock, buffer, (int)strlen(buffer), 0, addr, sizeof(struct sockaddr_in)); + buffer[0] = '\0'; } /* buffer_send: appends buffer with newdata. If the combined size would be too large, it flushes buffer first. Space is reserved on the total size to allow for the queryid key\value */ -static void buffer_send(qr_t qrec, struct sockaddr *sender, char *buffer, char *newdata) +static void buffer_send(qr_t qrec, struct sockaddr* sender, char* buffer, char* newdata) { - char *pos, *lastkey; - int bcount = 0; - - if (strlen(buffer) + strlen(newdata) < MAX_DATA_SIZE - 50) - { - strcat(buffer, newdata); - } else - { - if (strlen(newdata) > MAX_DATA_SIZE - 50) //incoming data is too big already! - { - lastkey = pos = newdata; - while (pos - newdata < MAX_DATA_SIZE-50) - { - if ('\\' == *pos) - { - if (bcount % 2 == 0) - lastkey = pos; - bcount++; - } - pos++; - } - if (lastkey == newdata) - return; //endless loop - single key was too big! - *lastkey = '\0'; - buffer_send(qrec,sender, buffer, newdata); - *lastkey = '\\'; - buffer_send(qrec,sender, buffer, lastkey); //send the rest! - } else - { - packet_send(qrec,sender, buffer); - strcpy(buffer,newdata); - } - } + char *pos, *lastkey; + int bcount = 0; + if (strlen(buffer) + strlen(newdata) < MAX_DATA_SIZE - 50) { + strcat(buffer, newdata); + } else { + if (strlen(newdata) > MAX_DATA_SIZE - 50) //incoming data is too big already! + { + lastkey = pos = newdata; + while (pos - newdata < MAX_DATA_SIZE - 50) { + if ('\\' == *pos) { + if (bcount % 2 == 0) + lastkey = pos; + bcount++; + } + pos++; + } + if (lastkey == newdata) + return; //endless loop - single key was too big! + *lastkey = '\0'; + buffer_send(qrec, sender, buffer, newdata); + *lastkey = '\\'; + buffer_send(qrec, sender, buffer, lastkey); //send the rest! + } else { + packet_send(qrec, sender, buffer); + strcpy(buffer, newdata); + } + } } /* send_basic: sends a response to the basic query */ -static void send_basic(qr_t qrec, struct sockaddr *sender, char *outbuf) +static void send_basic(qr_t qrec, struct sockaddr* sender, char* outbuf) { - char keyvalue[BUF_SIZE] = ""; + char keyvalue[BUF_SIZE] = ""; - assert(qrec->qr_basic_callback); - qrec->qr_basic_callback(keyvalue, sizeof(keyvalue), qrec->udata); - buffer_send(qrec,sender, outbuf, keyvalue); + assert(qrec->qr_basic_callback); + qrec->qr_basic_callback(keyvalue, sizeof(keyvalue), qrec->udata); + buffer_send(qrec, sender, outbuf, keyvalue); } /* send_info: sends a response to the info query */ -static void send_info(qr_t qrec, struct sockaddr *sender, char *outbuf) +static void send_info(qr_t qrec, struct sockaddr* sender, char* outbuf) { - char keyvalue[BUF_SIZE] = ""; - - assert(qrec->qr_info_callback); - qrec->qr_info_callback(keyvalue, sizeof(keyvalue), qrec->udata); - buffer_send(qrec,sender, outbuf, keyvalue); + char keyvalue[BUF_SIZE] = ""; + assert(qrec->qr_info_callback); + qrec->qr_info_callback(keyvalue, sizeof(keyvalue), qrec->udata); + buffer_send(qrec, sender, outbuf, keyvalue); } /* send_rules: sends a response to the rules query. */ -static void send_rules(qr_t qrec, struct sockaddr *sender, char *outbuf) +static void send_rules(qr_t qrec, struct sockaddr* sender, char* outbuf) { - char keyvalue[BUF_SIZE] = ""; - - assert(qrec->qr_rules_callback); - qrec->qr_rules_callback(keyvalue, sizeof(keyvalue), qrec->udata); - buffer_send(qrec,sender, outbuf, keyvalue); + char keyvalue[BUF_SIZE] = ""; + assert(qrec->qr_rules_callback); + qrec->qr_rules_callback(keyvalue, sizeof(keyvalue), qrec->udata); + buffer_send(qrec, sender, outbuf, keyvalue); } /* send_players: sends the players and their information.*/ -static void send_players(qr_t qrec, struct sockaddr *sender, char *outbuf) +static void send_players(qr_t qrec, struct sockaddr* sender, char* outbuf) { - char keyvalue[BUF_SIZE] = ""; - - assert(qrec->qr_players_callback); - qrec->qr_players_callback(keyvalue, sizeof(keyvalue), qrec->udata); - buffer_send(qrec,sender, outbuf, keyvalue); - + assert(qrec->qr_players_callback); + qrec->qr_players_callback(keyvalue, sizeof(keyvalue), qrec->udata); + buffer_send(qrec, sender, outbuf, keyvalue); } /* send_echo: bounces the echostr back to sender Note: you should always make sure that your echostr doesn't exceed the MAX_DATA_SIZE*/ -static void send_echo(qr_t qrec, struct sockaddr *sender, char *outbuf,char *echostr) +static void send_echo(qr_t qrec, struct sockaddr* sender, char* outbuf, char* echostr) { - char keyvalue[MAX_DATA_SIZE]; - - if (strlen(echostr) > MAX_DATA_SIZE - 50) - return; - snprintf(keyvalue,sizeof(keyvalue),"\\echo\\%s",echostr); - buffer_send(qrec,sender, outbuf, keyvalue); + char keyvalue[MAX_DATA_SIZE]; + if (strlen(echostr) > MAX_DATA_SIZE - 50) + return; + snprintf(keyvalue, sizeof(keyvalue), "\\echo\\%s", echostr); + buffer_send(qrec, sender, outbuf, keyvalue); } /* send_final: sends the remaining data in outbuf. Appends the final key\value to the end. Also adds validation if required. */ -static void send_final(qr_t qrec, struct sockaddr *sender, char *outbuf,char *validation) +static void send_final(qr_t qrec, struct sockaddr* sender, char* outbuf, char* validation) { - char keyvalue[256]; - char encrypted_val[128]; //don't need to null terminate - char encoded_val[200]; - int keylen; - - if (validation[0]) - { - keylen = strlen(validation); - if (keylen > 128) return; - strcpy(encrypted_val, validation); - gs_encrypt((uchar *)qrec->secret_key, strlen(qrec->secret_key), (uchar *)encrypted_val, keylen); - gs_encode((uchar *)encrypted_val,keylen, (uchar *)encoded_val); - snprintf(keyvalue,sizeof(keyvalue),"\\validate\\%s",encoded_val); - buffer_send(qrec,sender, outbuf, keyvalue); - } - - snprintf(keyvalue,sizeof(keyvalue),"\\final\\"); - buffer_send(qrec,sender, outbuf, keyvalue); - packet_send(qrec,sender, outbuf); -} + char keyvalue[256]; + char encrypted_val[128]; //don't need to null terminate + char encoded_val[200]; + int keylen; + if (validation[0]) { + keylen = (int)strlen(validation); + if (keylen > 128) + return; + strcpy(encrypted_val, validation); + gs_encrypt((uchar*)qrec->secret_key, (int)strlen(qrec->secret_key), (uchar*)encrypted_val, keylen); + gs_encode((uchar*)encrypted_val, keylen, (uchar*)encoded_val); + snprintf(keyvalue, sizeof(keyvalue), "\\validate\\%s", encoded_val); + buffer_send(qrec, sender, outbuf, keyvalue); + } + + snprintf(keyvalue, sizeof(keyvalue), "\\final\\"); + buffer_send(qrec, sender, outbuf, keyvalue); + packet_send(qrec, sender, outbuf); +} /* parse_query: parse an incoming query (which may contain 1 or more individual queries) and reply to each query */ -static void parse_query(qr_t qrec, char *query, struct sockaddr *sender) +static void qr_parse_query(qr_t qrec, char* query, int len, struct sockaddr* sender) { - query_t querytype; - char buffer[MAX_DATA_SIZE]=""; - char *value; - char validation[256] = ""; + int querytype; + char buffer[MAX_DATA_SIZE] = ""; + char* value; + char validation[256] = ""; - if (qrec == NULL) { + if (qrec == NULL) qrec = current_rec; - } - - if (*query == ';') { - // custom handler - if (qrec->qr_custom_handler) { - qrec->qr_custom_handler(query, sender); + if (query[0] == 0x3B) /* a cdkey query */ + { + if (qrec->cdkeyprocess != NULL) { + qrec->cdkeyprocess(query, len, sender); } return; } - qrec->queryid++; - qrec->packetnumber = 0; - if (qrec->no_query > 0) - qrec->no_query = 0; + qrec->queryid++; + qrec->packetnumber = 0; + if (qrec->no_query > 0) + qrec->no_query = 0; - for (querytype = qtbasic; querytype <= qtsecure ; querytype++) - { - if ((value = value_for_key(query, queries[querytype]))) - switch (querytype) - { - case qtbasic: - send_basic(qrec,sender,buffer); - break; - case qtinfo: - send_info(qrec,sender,buffer); - break; - case qtrules: - send_rules(qrec,sender,buffer); - break; - case qtplayers: - send_players(qrec,sender,buffer); - break; - case qtstatus: - send_basic(qrec,sender,buffer); - send_info(qrec,sender,buffer); - send_rules(qrec,sender,buffer); - send_players(qrec,sender,buffer); - break; - case qtpackets: - /*note: "packets" is NOT a real query type. It is simply here to illustrate - how a large query would look if broken into packets */ - send_basic(qrec,sender,buffer); packet_send(qrec,sender, buffer); - send_info(qrec,sender,buffer); packet_send(qrec,sender, buffer); - send_rules(qrec,sender,buffer); packet_send(qrec,sender, buffer); - send_players(qrec,sender,buffer); - break; - case qtecho: - //note: \echo\value is the syntax here - send_echo(qrec,sender,buffer,value); - break; - case qtsecure: - strcpy(validation, value); - break; - case qtunknown: - break; + for (querytype = qtbasic; querytype <= qtsecure; querytype++) { + if ((value = value_for_key(query, queries[querytype]))) + switch (querytype) { + case qtbasic: + send_basic(qrec, sender, buffer); + break; + case qtinfo: + send_info(qrec, sender, buffer); + break; + case qtrules: + send_rules(qrec, sender, buffer); + break; + case qtplayers: + send_players(qrec, sender, buffer); + break; + case qtstatus: + send_basic(qrec, sender, buffer); + send_info(qrec, sender, buffer); + send_rules(qrec, sender, buffer); + send_players(qrec, sender, buffer); + break; + case qtpackets: + /*note: "packets" is NOT a real query type. It is simply here to illustrate how a large query would look if broken into packets */ + send_basic(qrec, sender, buffer); + packet_send(qrec, sender, buffer); + send_info(qrec, sender, buffer); + packet_send(qrec, sender, buffer); + send_rules(qrec, sender, buffer); + packet_send(qrec, sender, buffer); + send_players(qrec, sender, buffer); + break; + case qtecho: + //note: \echo\value is the syntax here + send_echo(qrec, sender, buffer, value); + break; + case qtsecure: + strcpy(validation, value); + break; + case qtunknown: + break; + } + } + send_final(qrec, sender, buffer, validation); +} - } - } - send_final(qrec,sender,buffer,validation); +int get_master_count() +{ + return MasterCount; +} + +void clear_master_list() +{ + memset(MasterList, 0, sizeof(MasterList)); + MasterCount = 0; +} + +void add_master(struct sockaddr_in* addr) +{ + int i; + for (i = 0; i < MasterCount; i++) { + if (memcmp(addr, &MasterList[i], sizeof(MasterList[i])) == 0) { + return; + } + } + if (i == 8) { + return; + } else { + MasterList[i] = *addr; + MasterCount++; + } } /* send_heartbeat: Sends a heartbeat to the gamemaster, adds \statechanged\ if statechanged != 0 */ static void send_heartbeat(qr_t qrec, int statechanged) { - char buf[256]; - int ret; - - snprintf(buf,sizeof(buf),"\\heartbeat\\%d\\gamename\\%s",qrec->qport, qrec->gamename); - if (statechanged) - strcat(buf,"\\statechanged\\"); -#ifdef TCP_HEARTBEATS - ret = send(qrec->hbsock, buf, strlen(buf), 0); - if (ret < 0) /* try to reconnect (tcp only) */ - { - closesocket(qrec->hbsock); - qrec->hbsock = socket(AF_INET, SOCK_STREAM, IPPROTO_UDP); - if (do_connect(qrec->hbsock, qr_hostname, MASTER_PORT) == 0) - send(qrec->hbsock, buf, strlen(buf), 0); /* try again */ - } -#else - ret = sendto(qrec->hbsock, buf, strlen(buf), 0, (const struct sockaddr *)&qrec->master_saddr, sizeof(struct sockaddr_in)); -#endif + char buf[256]; + int ret; + int i; - qrec->lastheartbeat = current_time(); + snprintf(buf, sizeof(buf), "\\heartbeat\\%d\\gamename\\%s", qrec->qport, qrec->gamename); + if (statechanged) + snprintf(&buf[strlen(buf)], sizeof(buf) - strlen(buf), "\\statechanged\\"); + + for (i = 0; i < MasterCount; i++) { + ret = sendto(qrec->hbsock, buf, (int)strlen(buf), 0, (struct sockaddr*)&MasterList[i], sizeof(MasterList[i])); + } + + qrec->lastheartbeat = current_time(); } #ifdef __cplusplus diff --git a/code/gamespy/sv_gqueryreporting.h b/code/gamespy/sv_gqueryreporting.h index 308bff03..5a016b73 100644 --- a/code/gamespy/sv_gqueryreporting.h +++ b/code/gamespy/sv_gqueryreporting.h @@ -49,10 +49,10 @@ ERROR CONSTANTS These constants are returned from qr_init to signal an error condition ***************/ -#define E_GOA_WSOCKERROR 1 -#define E_GOA_BINDERROR 2 -#define E_GOA_DNSERROR 3 -#define E_GOA_CONNERROR 4 +#define E_GOA_WSOCKERROR 1 +#define E_GOA_BINDERROR 2 +#define E_GOA_DNSERROR 3 +#define E_GOA_CONNERROR 4 /********* NUM_PORTS_TO_TRY ---------------- @@ -62,6 +62,20 @@ as the base port. Generally there is no reason to modify this value. ***********/ #define NUM_PORTS_TO_TRY 100 +/******** +DEFINES +********/ +#define MASTER_SERVER_HOST "master.333networks.com" +#define MASTER_PORT 27900 +//#define MASTER_ADDR "master." GSI_DOMAIN_NAME +#define MASTER_ADDR MASTER_SERVER_HOST +#define FIRST_HB_TIME 30000 /* 30 sec */ +#define HB_TIME 300000 /* 5 minutes */ +#define MAX_FIRST_COUNT 10 /* 10 tries = 5 minutes */ +#define MAX_DATA_SIZE 1400 +#define INBUF_LEN 256 +#define BUF_SIZE 1400 + /* The hostname of the master server. If the app resolves the hostname, an IP can be stored here before calling @@ -85,8 +99,9 @@ Simply fill outbuf with the correct data for the query type (consult the sample apps and the GameSpy Developer Spec). outbuf should be a NULL terminated ANSI string. ********/ -typedef void (*qr_querycallback_t)(char *outbuf, int maxlen, void *userdata); -typedef void (*qr_custom_handler_t)(const char *query, struct sockaddr *sender); +typedef void (*qr_querycallback_t)(char* outbuf, int maxlen, void* userdata); + +typedef void (*qr_cdkey_process_t)(char* buf, int len, struct sockaddr* fromaddr); /*********** qr_t @@ -99,8 +114,6 @@ that require it. A single global instance will be used, similar to how the original Developer SDK worked ************/ typedef struct qr_implementation_s *qr_t; - - /************ QR_INIT -------- @@ -125,13 +138,16 @@ This creates/binds the sockets needed for heartbeats and queries/replies. Returns 0 is successful, otherwise one of the E_GOA constants above. ************/ -int qr_init(/*[out]*/qr_t *qrec, const char *ip, int baseport, const char *gamename, const char *secret_key, - qr_querycallback_t qr_basic_callback, - qr_querycallback_t qr_info_callback, - qr_querycallback_t qr_rules_callback, - qr_querycallback_t qr_players_callback, - void *userdata); - +int qr_init(/*[out]*/ qr_t* qrec, + const char* ip, + int baseport, + const char* gamename, + const char* secret_key, + qr_querycallback_t qr_basic_callback, + qr_querycallback_t qr_info_callback, + qr_querycallback_t qr_rules_callback, + qr_querycallback_t qr_players_callback, + void* userdata); /******************* QR_PROCESS_QUERIES @@ -180,20 +196,16 @@ void qr_shutdown(qr_t qrec); void qr_check_queries(qr_t qrec); -/******** -DEFINES -********/ -#define MASTER_PORT 27900 -#define MASTER_ADDR MASTER_SERVER_HOST -#define FIRST_HB_TIME 30000 /* 30 sec */ -#define HB_TIME 300000 /* 5 minutes */ -#define MAX_FIRST_COUNT 10 /* 10 tries = 5 minutes */ -#define MAX_DATA_SIZE 1400 -#define INBUF_LEN 256 -#define BUF_SIZE 1400 -#define MASTER_SERVER_HOST "master.333networks.com" +void qr_send_exiting(qr_t qrec); + +int get_master_count(); + +void clear_master_list(); + +int get_sockaddrin(const char *host, int port, struct sockaddr_in *saddr, struct hostent **savehent); + +void add_master(struct sockaddr_in *addr); #ifdef __cplusplus } #endif -