Implement support for parsing group rooms and master info

This commit is contained in:
smallmodel 2025-02-22 22:13:23 +01:00
parent ebd86b32bd
commit 56d61bdef3
No known key found for this signature in database
GPG key ID: 9F2D623CEDF08512
4 changed files with 191 additions and 12 deletions

View file

@ -85,7 +85,7 @@ stricase - assume the values are strings and do a case insensitive compare */
typedef enum {cm_int, cm_float, cm_strcase, cm_stricase} GCompareMode;
typedef enum {qt_basic, qt_info, qt_rules, qt_players, qt_info_rules, qt_status} GQueryType;
typedef enum {qt_basic, qt_info, qt_rules, qt_players, qt_info_rules, qt_status, qt_grouprooms, qt_masterinfo} GQueryType;
/* Messages that are passed to the ListCallBackFn */
#define LIST_STATECHANGED 1 // ServerListState changed, no parameters

View file

@ -36,6 +36,8 @@ Updated 6-17-99 (DDW)
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);
@ -48,6 +50,60 @@ void ServerFree(void *elem)
free(server);
}
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((int)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((int)server, k);
kvpair.value = (char *)LookupKey((int)server, v);
TableEnter(server->keyvals, &kvpair);
}
if (++curfield < fieldcount) {
v = mytok(0, '\\');
}
}
return server;
}
GServer ServerNew(unsigned long ip, unsigned short port, GQueryType qtype, HashTable keylist)
{
GServer server;

View file

@ -62,6 +62,7 @@ typedef struct
} GEnumData;
void ServerFree(void *elem);
GServer ServerNewData(char **fieldlist, int fieldcount, char *serverdata, GQueryType qtype, HashTable keylist);
GServer ServerNew(unsigned long ip, unsigned short port, GQueryType qtype, HashTable keylist);
void ServerParseKeyVals(GServer server, char *keyvals);
int GStringHash(const void *elem, int numbuckets);

View file

@ -69,7 +69,7 @@ typedef struct
struct sockaddr_in saddr;
} UpdateInfo;
typedef enum { pi_fieldcount, pi_fields, pi_servers } GParseInfoState;
struct GServerListImplementation
{
@ -94,6 +94,7 @@ struct GServerListImplementation
// Added in 2.0
GCryptInfo cryptinfo;
int encryptdata;
GParseInfoState pistate;
};
GServerList g_sortserverlist; //global serverlist for sorting info!!
@ -251,6 +252,7 @@ static GError SendListRequest(GServerList serverlist, char *filter)
char data[256], *ptr, result[64];
int len;
int i;
char *modifier;
len = recv(serverlist->slsocket, data, sizeof(data) - 1, 0);
if (gsiSocketIsError(len))
@ -286,11 +288,23 @@ static GError SendListRequest(GServerList serverlist, char *filter)
if (gsiSocketIsError(len) || len == 0)
return GE_NOCONNECT;
//send the list request
if (serverlist->querytype == qt_grouprooms) {
modifier = "groups";
serverlist->pistate = pi_fieldcount;
} else if (serverlist->querytype == qt_masterinfo) {
modifier = "info2";
serverlist->pistate = pi_fieldcount;
} else {
modifier = "cmp";
}
//send the list request
if (filter)
sprintf(data, "\\list\\cmp\\gamename\\%s\\where\\%s\\final\\", serverlist->gamename, filter);
sprintf(data, "\\list\\%s\\gamename\\%s\\where\\%s\\final\\", modifier, serverlist->gamename, filter);
else
sprintf(data, "\\list\\cmp\\gamename\\%s\\final\\", serverlist->gamename);
sprintf(data, "\\list\\%s\\gamename\\%s\\final\\", modifier, serverlist->gamename);
len = send ( serverlist->slsocket, data, strlen(data), 0 );
if (gsiSocketIsError(len) || len == 0)
return GE_NOCONNECT;
@ -393,6 +407,15 @@ GError ServerListLANUpdate(GServerList serverlist, gbool async, int startsearchp
return 0;
}
//add a new server based on the data
static GServer ServerListAddServerData(GServerList serverlist, char **fieldlist, int fieldcount, char *serverdata, GQueryType qtype)
{
GServer server;
server = ServerNewData(fieldlist, fieldcount, serverdata, qtype, serverlist->keylist);
ArrayAppend(serverlist->servers, &server);
return server;
}
//add the server to the list with the given ip, port
static void ServerListAddServer(GServerList serverlist, unsigned long ip, unsigned short port, GQueryType qtype)
@ -566,9 +589,97 @@ static GError ServerListLANList(GServerList serverlist)
ServerListModeChange(serverlist, sl_querying);
}
return 0;
}
static int CountSlashOffset(char *data, int len, int slashcount)
{
char *p;
for (p = data; slashcount && p != data + len; ++p) {
if (*p == '\\') {
slashcount--;
}
}
if (slashcount) {
return -1;
}
return p - data;
}
//parses and retrieve servers based on fields
static int ServerListParseInfoList(GServerList serverlist, char *data, int len)
{
char *fieldlist[20];
char tempfield[64];
char *tempptr;
static int fieldcount;
int offset;
int i;
GServer server;
switch (serverlist->pistate) {
case pi_fieldcount:
offset = CountSlashOffset(data, len, 3);
if (offset == -1) {
return 0;
}
if (offset < 12) {
return 0;
}
strncpy(tempfield, data + 12, offset - 12);
tempfield[offset - 13] = 0;
fieldcount = atoi(tempfield);
if (fieldcount > 20) {
return -1;
}
serverlist->pistate = pi_fields;
for (i = 0; i < fieldcount; ++i) {
fieldlist[i] = 0;
}
return offset - 1;
case pi_fields:
offset = CountSlashOffset(data, len, 2);
if (offset == -1) {
return 0;
}
strncpy(tempfield, data + 1, offset - 2);
tempfield[offset - 2] = 0;
tempptr = goastrdup(tempfield);
for (i = 0; i < fieldcount; ++i) {
if (!fieldlist[i]) {
fieldlist[i] = tempptr;
if (i == fieldcount - 1) {
serverlist->pistate = pi_servers;
}
return offset - 1;
}
}
return -1;
case pi_servers:
offset = CountSlashOffset(data, len, fieldcount + 1);
if (offset == -1) {
return 0;
}
server = ServerListAddServerData(serverlist, (char **)fieldlist, fieldcount, data, serverlist->querytype);
data[offset - 1] = '\\';
serverlist->CallBackFn(serverlist, 2, serverlist->instance, server, 0);
return offset - 1;
default:
return -1;
}
}
//reads the server list from the socket and parses it
static GError ServerListReadList(GServerList serverlist)
{
@ -641,11 +752,22 @@ static GError ServerListReadList(GServerList serverlist)
}
if (oldlen < 6) //no way it could be a full IP, quit
break;
memcpy(&ip,p,4);
p += 4;
memcpy(&port,p,2);
p += 2;
ServerListAddServer(serverlist,ip, ntohs(port), serverlist->querytype );
if (serverlist->querytype == qt_grouprooms || serverlist->querytype == qt_masterinfo) {
i = ServerListParseInfoList(serverlist, p, oldlen - (p - data));
if (i < 0) {
serverlist->abortupdate = 1;
} else if (!i) {
// finished
break;
}
} else {
memcpy(&ip, p, 4);
p += 4;
memcpy(&port, p, 2);
p += 2;
ServerListAddServer(serverlist, ip, ntohs(port), serverlist->querytype);
}
}
}
oldlen = oldlen - (p - data);