openmohaa/code/gamespy/gserver.c

404 lines
9.3 KiB
C
Raw Permalink Normal View History

2023-07-27 22:43:51 +02:00
/******
gserver.c
GameSpy C Engine SDK
Copyright 1999 GameSpy Industries, Inc
Suite E-204
2900 Bristol Street
Costa Mesa, CA 92626
(714)549-7689
Fax(714)549-0757
******
Updated 10-15-99 (BGW)
2025-02-28 18:11:09 +01:00
Modified ServerParseKeyVals to actually parse and store empty
values for keys (i.e. "\delete\\" adds key="delete" and value="")
2023-07-27 22:43:51 +02:00
Updated 6-17-99 (DDW)
2025-02-28 18:11:09 +01:00
Added new tokenize function to handle empty values for keys
2023-07-27 22:43:51 +02:00
2025-02-28 18:11:09 +01:00
2023-07-27 22:43:51 +02:00
*******/
#if defined(applec) || defined(THINK_C) || defined(__MWERKS__) && !defined(__KATANA__)
2025-02-28 18:11:09 +01:00
#include "::nonport.h"
2023-07-27 22:43:51 +02:00
#else
2025-02-28 18:11:09 +01:00
#include "../nonport.h"
2023-07-27 22:43:51 +02:00
#endif
#include "goaceng.h"
#include "gserver.h"
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
static int KeyValHashKeyP(const void *elem, int numbuckets);
static int KeyValCompareKeyP(const void *entry1, const void *entry2);
static char *mytok(char *instr, char delim);
static char *LookupKey(GServer server, char *k);
2023-07-27 22:43:51 +02:00
void ServerFree(void *elem)
{
2025-02-28 18:11:09 +01:00
//free a server!
GServer server = *(GServer *)elem;
TableFree(server->keyvals);
free(server);
2023-07-27 22:43:51 +02:00
}
static void ServerSetAddressFromString (GServer server, char *address)
{
char *cpos;
cpos = strchr(address, ':');
if (!cpos) {
return;
}
*cpos = 0;
server->ip = inet_addr(address);
server->port = atoi(cpos + 1);
}
GServer ServerNewData(char **fieldlist, int fieldcount, char *serverdata, GQueryType qtype, HashTable keylist)
{
GServer server;
char *k;
char *v;
int curfield;
GKeyValuePair kvpair;
curfield = 0;
server = (GServer)ServerNew(0, 0, qtype, keylist);
v = mytok(serverdata + 1, '\\');
while (curfield < fieldcount) {
k = fieldlist[curfield];
if (!v) {
v = "";
}
if (!strcmp(k, "ip")) {
ServerSetAddressFromString(server, v);
} else if (qtype == qt_grouprooms && !strcmp(k, "other")) {
for (char *p = v; *p; ++p) {
if (*p == 1) {
*p = '\\';
}
}
ServerParseKeyVals(server, v);
} else {
kvpair.key = (char *)LookupKey(server, k);
kvpair.value = (char *)LookupKey(server, v);
TableEnter(server->keyvals, &kvpair);
}
if (++curfield < fieldcount) {
v = mytok(0, '\\');
}
}
return server;
}
2023-07-27 22:43:51 +02:00
GServer ServerNew(unsigned long ip, unsigned short port, GQueryType qtype, HashTable keylist)
{
2025-02-28 18:11:09 +01:00
GServer server;
int nBuckets, nChains;
server = malloc(sizeof(struct GServerImplementation));
server->ip = ip;
server->port = port;
server->ping = 9999;
server->querytype = qtype;
/* optimize the number of buckets / chains based on query type */
switch (qtype)
{
case qt_basic:
nBuckets = 4;
nChains = 2;
break;
case qt_info:
nBuckets = 6;
nChains = 2;
break;
case qt_players:
case qt_rules:
nBuckets = 8;
nChains = 2;
break;
case qt_info_rules:
case qt_status:
default:
nBuckets = 8;
nChains= 4;
break;
}
server->keyvals = TableNew2(sizeof(GKeyValuePair),nBuckets,nChains, KeyValHashKeyP, KeyValCompareKeyP, NULL);
server->keylist = keylist;
return server;
2023-07-27 22:43:51 +02:00
}
static char *mytok(char *instr, char delim)
{
2025-02-28 18:11:09 +01:00
char *result;
static char *thestr;
if (instr)
thestr = instr;
result=thestr;
while (*thestr && *thestr != delim)
{
thestr++;
}
if (thestr == result)
result = NULL;
if (*thestr) //not the null term
*thestr++ = '\0';
return result;
2023-07-27 22:43:51 +02:00
}
static int CheckValidKey(char *key)
{
2025-02-28 18:11:09 +01:00
const char *InvalidKeys[]={"queryid","final"};
int i;
for (i = 0; i < sizeof(InvalidKeys)/sizeof(InvalidKeys[0]); i++)
{
if (strcmp(key,InvalidKeys[i]) == 0)
return 0;
}
return 1;
2023-07-27 22:43:51 +02:00
}
static char *LookupKey(GServer server, char *k)
{
2025-02-28 18:11:09 +01:00
char **keyindex;
keyindex = (char **)TableLookup(server->keylist,&k);
if (keyindex != NULL)
return *keyindex;
k = strdup(k);
TableEnter(server->keylist,&k);
return k;
2023-07-27 22:43:51 +02:00
}
void ServerParseKeyVals(GServer server, char *keyvals)
{
2025-02-28 18:11:09 +01:00
char *k, *v;
GKeyValuePair kvpair;
k = mytok(++keyvals,'\\'); //skip over starting backslash
while (k != NULL)
{
v = mytok(NULL,'\\');
if (v == NULL)
v = "";
if (CheckValidKey(k))
{
kvpair.key = LookupKey(server, k);
kvpair.value = LookupKey(server, v);
TableEnter(server->keyvals, &kvpair);
}
k = mytok(NULL,'\\');
}
2023-07-27 22:43:51 +02:00
}
/* ServerGetPing
----------------
Returns the ping for the specified server. */
int ServerGetPing(GServer server)
{
2025-02-28 18:11:09 +01:00
return server->ping;
2023-07-27 22:43:51 +02:00
}
/* ServerGetAddress
-------------------
Returns the string, dotted IP address for the specified server */
char *ServerGetAddress(GServer server)
{
2025-02-28 18:11:09 +01:00
return (char *)inet_ntoa(*(struct in_addr*)&server->ip);
2023-07-27 22:43:51 +02:00
}
/* ServerGetInetAddress
-------------------
Returns the IP address for the specified server */
unsigned int ServerGetInetAddress(GServer server)
{
2025-02-28 18:11:09 +01:00
return server->ip;
2023-07-27 22:43:51 +02:00
}
/* ServerGetPort
----------------
Returns the "query" port for the specified server. */
int ServerGetQueryPort(GServer server)
{
2025-02-28 18:11:09 +01:00
return server->port;
2023-07-27 22:43:51 +02:00
}
static GKeyValuePair *ServerRuleLookup(GServer server, char *key)
{
2025-02-28 18:11:09 +01:00
GKeyValuePair kvp;
char **keyindex;
keyindex = (char **)TableLookup(server->keylist, &key);
if (keyindex == NULL)
return NULL; //otherwise, the keyindex->keyindex is valid, so use it to lookup
kvp.key = *keyindex;
return (GKeyValuePair *)TableLookup(server->keyvals, &kvp);
2023-07-27 22:43:51 +02:00
}
/* ServerGet[]Value
------------------
Returns the value for the specified key. */
char *ServerGetStringValue(GServer server, char *key, char *sdefault)
{
2025-02-28 18:11:09 +01:00
GKeyValuePair *kv;
if (strcmp(key,"hostaddr") == 0) //ooh! they want the hostaddr!
return ServerGetAddress(server);
kv = ServerRuleLookup(server,key);
if (!kv)
return sdefault;
return kv->value;
2023-07-27 22:43:51 +02:00
}
int ServerGetIntValue(GServer server, char *key, int idefault)
{
2025-02-28 18:11:09 +01:00
GKeyValuePair *kv;
2023-07-27 22:43:51 +02:00
2025-02-28 18:11:09 +01:00
if (strcmp(key,"ping") == 0) //ooh! they want the ping!
return ServerGetPing(server);
kv = ServerRuleLookup(server,key);
if (!kv)
return idefault;
return atoi(kv->value);
2023-07-27 22:43:51 +02:00
}
double ServerGetFloatValue(GServer server, char *key, double fdefault)
{
2025-02-28 18:11:09 +01:00
GKeyValuePair *kv;
2023-07-27 22:43:51 +02:00
2025-02-28 18:11:09 +01:00
kv = ServerRuleLookup(server,key);
if (!kv)
return fdefault;
return atof(kv->value);
2023-07-27 22:43:51 +02:00
}
char *ServerGetPlayerStringValue(GServer server, int playernum, char *key, char *sdefault)
{
2025-02-28 18:11:09 +01:00
char newkey[32];
sprintf(newkey,"%s_%d",key,playernum);
return ServerGetStringValue(server, newkey, sdefault);
2023-07-27 22:43:51 +02:00
}
int ServerGetPlayerIntValue(GServer server, int playernum, char *key, int idefault)
{
2025-02-28 18:11:09 +01:00
char newkey[32];
sprintf(newkey,"%s_%d",key,playernum);
return ServerGetIntValue(server, newkey, idefault);
2023-07-27 22:43:51 +02:00
}
double ServerGetPlayerFloatValue(GServer server, int playernum, char *key, double fdefault)
{
2025-02-28 18:11:09 +01:00
char newkey[32];
sprintf(newkey,"%s_%d",key,playernum);
return ServerGetFloatValue(server, newkey, fdefault);
2023-07-27 22:43:51 +02:00
}
/* ServerEnumKeys
-----------------
Enumerates the keys/values for a given server by calling KeyEnumFn with each
key/value. The user-defined instance data will be passed to the KeyFn callback */
static void KeyMapF(void *elem, void *clientData)
{
2025-02-28 18:11:09 +01:00
GKeyValuePair *kv = (GKeyValuePair *)elem;
GEnumData *ped = (GEnumData *)clientData;
ped->EnumFn(kv->key, kv->value, ped->instance);
2023-07-27 22:43:51 +02:00
}
void ServerEnumKeys(GServer server, KeyEnumFn KeyFn, void *instance)
{
2025-02-28 18:11:09 +01:00
GEnumData ed;
2023-07-27 22:43:51 +02:00
2025-02-28 18:11:09 +01:00
ed.EnumFn = KeyFn;
ed.instance = instance;
ed.keylist = server->keylist;
TableMap(server->keyvals, KeyMapF, &ed);
2023-07-27 22:43:51 +02:00
}
/***********
* UTILITY FUNCTIONS
**********/
#define MULTIPLIER -1664117991
static int StringHash(char *s, int numbuckets)
{
2025-02-28 18:11:09 +01:00
unsigned long hashcode = 0;
while (*s != 0)
hashcode = hashcode * MULTIPLIER + tolower(*s++);
2023-07-27 22:43:51 +02:00
return (hashcode % numbuckets);
}
int GStringHash(const void *elem, int numbuckets)
{
2025-02-28 18:11:09 +01:00
return StringHash(*(char **)elem, numbuckets);
2023-07-27 22:43:51 +02:00
}
static int KeyValHashKeyP(const void *elem, int numbuckets)
{
2025-02-28 18:11:09 +01:00
return StringHash(((GKeyValuePair *)elem)->key, numbuckets);
2023-07-27 22:43:51 +02:00
}
/* CaseInsensitiveCompare
* ----------------------
* Comparison function passed to qsort to sort an array of
* strings in alphabetical order. It uses strcasecmp which is
* identical to strcmp, except that it doesn't consider case of the
* characters when comparing them, thus it sorts case-insensitively.
*/
int GCaseInsensitiveCompare(const void *entry1, const void *entry2)
{
return strcasecmp(*(char **)entry1,*(char **)entry2);
}
/* keyval
* Compares two gkeyvaluepair
*/
static int KeyValCompareKeyP(const void *entry1, const void *entry2)
{
2025-02-28 18:11:09 +01:00
return ((GKeyValuePair *)entry1)->key - ((GKeyValuePair *)entry2)->key;
2023-07-27 22:43:51 +02:00
}
void GStringFree(void *elem)
{
2025-02-28 18:11:09 +01:00
free(*(char **)elem);
2023-07-27 22:43:51 +02:00
}
/* keyval
* Compares two gkeyvaluepair (case insensative)
*
static int KeyValCompareKeyA(const void *entry1, const void *entry2)
{
2025-02-28 18:11:09 +01:00
return CaseInsensitiveCompare(&((GKeyValuePair *)entry1)->key,
&((GKeyValuePair *)entry2)->key);
2023-07-27 22:43:51 +02:00
}
*/