mirror of
https://github.com/openmoh/openmohaa.git
synced 2025-04-28 13:47:58 +03:00
Implement multi-master queries and heartbeats (#717)
Implement multi-master server list query and multi-master heartbeats. The server list is fetched from multiple masters to improve redundancy, reliability and performance. This improves multiplayer availability by implementing support for using multiple masters. - The server sends an heartbeat to all masters at once - The client can query up to 4 masters in parallel depending on their rate
This commit is contained in:
parent
08a985d183
commit
cce81cabff
15 changed files with 603 additions and 142 deletions
|
@ -25,12 +25,25 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#include "cl_gamespy.h"
|
||||
#include "q_gamespy.h"
|
||||
|
||||
const char *ServerListGetHost()
|
||||
unsigned int ServerListGetNumMasters()
|
||||
{
|
||||
return Com_GetMasterHost();
|
||||
return Com_GetNumMasterEntries();
|
||||
}
|
||||
|
||||
int ServerListGetMsPort()
|
||||
const char *ServerListGetHost(int index)
|
||||
{
|
||||
return Com_GetMasterQueryPort();
|
||||
master_entry_t entry;
|
||||
Com_GetMasterEntry(index, &entry);
|
||||
|
||||
return entry.host;
|
||||
}
|
||||
|
||||
int ServerListGetMsPort(int index)
|
||||
{
|
||||
master_entry_t entry;
|
||||
Com_GetMasterEntry(index, &entry);
|
||||
|
||||
return entry.queryport;
|
||||
}
|
||||
|
||||
void CL_RestartGamespy_f() {}
|
||||
|
|
|
@ -23,3 +23,5 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
// cl_gamespy.h -- Game-specific client GameSpy code
|
||||
|
||||
#pragma once
|
||||
|
||||
void CL_RestartGamespy_f();
|
||||
|
|
|
@ -77,7 +77,7 @@ lanlist - we are waiting for replies from servers on the LAN
|
|||
querying - the servers on the list are being queried
|
||||
connecting (added in OPM) - socket is currently connecting to the master server
|
||||
*/
|
||||
typedef enum {sl_idle, sl_listxfer, sl_lanlist, sl_querying, sl_connecting} GServerListState;
|
||||
typedef enum {sl_idle, sl_listxfer, sl_lanlist, sl_querying} GServerListState;
|
||||
|
||||
/* Comparision types for the ServerListSort function
|
||||
int - assume the values are int and do an integer compare
|
||||
|
|
|
@ -19,6 +19,24 @@ Fax(714)549-0757
|
|||
for this SDK. It also has a change history for the SDK.
|
||||
|
||||
******/
|
||||
|
||||
/**
|
||||
* The following modifications were made:
|
||||
*
|
||||
* 1) Non-blocking server list sockets. List requests are asynchronous and won't block the game. The only blocking request could be due to DNS resolution.
|
||||
* 2) Server list sockets will timeout after 10 seconds of no reply.
|
||||
* 3) Parallel server list requests.
|
||||
* 3.1) A pool of sockets is initially created
|
||||
* 3.2) The server list connects idling sockets to available masters, afterwards the server list state is set to `sl_listxfer`.
|
||||
* 3.3) The server list sends the list request to connected masters, and receives the data for each.
|
||||
* 3.4) When finished fetching 1 master (got `\final`), the server list state transitions to `sl_querying`.
|
||||
* 3.5) The server list queries all fetched servers. It can still continue fetching list from currently connected masters
|
||||
* but it will not connect to other masters while servers are being queried. It won't be sending more queries if remaining masters replied in under 500 ms.
|
||||
* 3.6) When finished querying all fetched servers, the server list restarts from 3.2 and queries next masters.
|
||||
*
|
||||
* The idea here is to ensure the redundancy of the server list between multiple masters even if the results are combined.
|
||||
* Optionally for best results, the game should return a list of masters from the same community.
|
||||
*/
|
||||
#include "goaceng.h"
|
||||
#include "gserver.h"
|
||||
#if defined(applec) || defined(THINK_C) || defined(__MWERKS__) && !defined(__KATANA__)
|
||||
|
@ -53,13 +71,16 @@ Fax(714)549-0757
|
|||
*
|
||||
* @return const char* The master host
|
||||
*/
|
||||
extern const char *ServerListGetHost();
|
||||
extern int ServerListGetMsPort();
|
||||
extern unsigned int ServerListGetNumMasters();
|
||||
extern const char *ServerListGetHost(int index);
|
||||
extern int ServerListGetMsPort(int index);
|
||||
|
||||
#define MSHOST ServerListGetHost()
|
||||
#define MSPORT ServerListGetMsPort()
|
||||
//#define MSHOST ServerListGetHost(0)
|
||||
//#define MSPORT ServerListGetMsPort(0)
|
||||
#define SERVER_GROWBY 64
|
||||
#define LAN_SEARCH_TIME 3000 //3 sec
|
||||
#define SERVER_QUERY_MAX_PAUSE 500
|
||||
#define INTERNET_SEARCH_TIME 10000 //10 sec
|
||||
#define LIST_NUMKEYBUCKETS 500
|
||||
#define LIST_NUMKEYCHAINS 4
|
||||
|
||||
|
@ -78,6 +99,17 @@ typedef struct
|
|||
} UpdateInfo;
|
||||
|
||||
typedef enum { pi_fieldcount, pi_fields, pi_servers } GParseInfoState;
|
||||
typedef enum { ls_none, ls_connecting, ls_connected } GListSocketState;
|
||||
|
||||
typedef struct GServerListSocketImplementation
|
||||
{
|
||||
SOCKET s;
|
||||
GListSocketState socketstate;
|
||||
char data[2048];
|
||||
int oldlen;
|
||||
gsi_time lastreplytime;
|
||||
GCryptInfo cryptinfo;
|
||||
} *GServerListSocket;
|
||||
|
||||
struct GServerListImplementation
|
||||
{
|
||||
|
@ -95,7 +127,10 @@ struct GServerListImplementation
|
|||
void *instance;
|
||||
char *sortkey;
|
||||
gbool sortascending;
|
||||
SOCKET slsocket;
|
||||
GServerListSocket slsockets;
|
||||
int numslsockets;
|
||||
int startslindex;
|
||||
gsi_time lastsltime;
|
||||
unsigned long lanstarttime;
|
||||
GQueryType querytype;
|
||||
HashTable keylist;
|
||||
|
@ -103,9 +138,10 @@ struct GServerListImplementation
|
|||
// Added in 2.0
|
||||
int numservers;
|
||||
// Added in 2.0
|
||||
GCryptInfo cryptinfo;
|
||||
//GCryptInfo cryptinfo;
|
||||
// Added in OPM
|
||||
int encryptdata;
|
||||
gbool async;
|
||||
|
||||
GParseInfoState pistate;
|
||||
};
|
||||
|
@ -121,7 +157,7 @@ const int querylengths[NUM_QUERYTYPES] = {7,6,7,9,13,8};
|
|||
static void KeyValFree(void *elem);
|
||||
static int KeyValCompareKeyA(const void *entry1, const void *entry2);
|
||||
static int KeyValHashKeyA(const void *elem, int numbuckets);
|
||||
|
||||
static gbool ServerListHasFinishedFetchingList(GServerList serverlist);
|
||||
|
||||
/* ServerListNew
|
||||
----------------
|
||||
|
@ -150,6 +186,19 @@ GServerList ServerListNew(const char *gamename, const char *enginename, const ch
|
|||
list->numservers = 0;
|
||||
// Added in OPM
|
||||
list->encryptdata = 1;
|
||||
list->async = 0;
|
||||
|
||||
list->numslsockets = maxconcupdates / 4;
|
||||
if (list->numslsockets < 1) {
|
||||
list->numslsockets = 1;
|
||||
} else if (list->numslsockets > 4) {
|
||||
// Above 4 seems too much
|
||||
list->numslsockets = 4;
|
||||
}
|
||||
list->slsockets = (GServerListSocket)malloc(sizeof(struct GServerListSocketImplementation) * list->numslsockets);
|
||||
memset(list->slsockets, 0, sizeof(struct GServerListSocketImplementation) * list->numslsockets);
|
||||
list->startslindex = 0;
|
||||
list->lastsltime = current_time();
|
||||
|
||||
SocketStartUp();
|
||||
return list;
|
||||
|
@ -163,6 +212,7 @@ void ServerListFree(GServerList serverlist)
|
|||
ArrayFree(serverlist->servers);
|
||||
TableFree(serverlist->keylist);
|
||||
free(serverlist->updatelist);
|
||||
free(serverlist->slsockets);
|
||||
|
||||
free(serverlist);
|
||||
SocketShutDown();
|
||||
|
@ -205,53 +255,90 @@ static GError FreeUpdateList(GServerList serverlist)
|
|||
}
|
||||
|
||||
//create and connect a server list socket
|
||||
static GError CreateServerListSocket(GServerList serverlist, gbool async)
|
||||
static GError CreateServerListSocket(GServerList serverlist, GServerListSocket slsocket, gbool async)
|
||||
{
|
||||
struct sockaddr_in saddr;
|
||||
struct hostent *hent;
|
||||
int lasterr;
|
||||
int i;
|
||||
int port;
|
||||
const char *host;
|
||||
|
||||
if (serverlist->startslindex >= ServerListGetNumMasters()) {
|
||||
return GE_NODNS;
|
||||
}
|
||||
|
||||
if (slsocket->socketstate != ls_none) {
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
}
|
||||
|
||||
port = ServerListGetMsPort(serverlist->startslindex);
|
||||
host = ServerListGetHost(serverlist->startslindex);
|
||||
|
||||
saddr.sin_family = AF_INET;
|
||||
saddr.sin_port = htons(MSPORT);
|
||||
saddr.sin_addr.s_addr = inet_addr(MSHOST);
|
||||
saddr.sin_port = htons(port);
|
||||
saddr.sin_addr.s_addr = inet_addr(host);
|
||||
if (saddr.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
hent = gethostbyname(MSHOST);
|
||||
hent = gethostbyname(host);
|
||||
if (!hent)
|
||||
return GE_NODNS;
|
||||
saddr.sin_addr.s_addr = *(u_long *)hent->h_addr_list[0];
|
||||
}
|
||||
serverlist->slsocket = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if (serverlist->slsocket == INVALID_SOCKET)
|
||||
slsocket->s = socket ( AF_INET, SOCK_STREAM, IPPROTO_TCP );
|
||||
if (slsocket->s == INVALID_SOCKET)
|
||||
return GE_NOSOCKET;
|
||||
|
||||
if (async) {
|
||||
SetSockBlocking(serverlist->slsocket, 0);
|
||||
SetSockBlocking(slsocket->s, 0);
|
||||
}
|
||||
|
||||
if (connect ( serverlist->slsocket, (struct sockaddr *) &saddr, sizeof saddr ) != 0
|
||||
&& (lasterr = GOAGetLastError(serverlist->slsocket), lasterr != WSAEWOULDBLOCK && lasterr != WSAEINPROGRESS))
|
||||
if (connect ( slsocket->s, (struct sockaddr *) &saddr, sizeof saddr ) != 0
|
||||
&& (lasterr = GOAGetLastError(slsocket->slsocket), lasterr != WSAEWOULDBLOCK && lasterr != WSAEINPROGRESS))
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
return GE_NOCONNECT;
|
||||
}
|
||||
|
||||
slsocket->socketstate = ls_connecting;
|
||||
slsocket->oldlen = 0;
|
||||
slsocket->cryptinfo.offset = -1;
|
||||
slsocket->lastreplytime = current_time();
|
||||
serverlist->startslindex++;
|
||||
|
||||
//else we are connected
|
||||
return 0;
|
||||
|
||||
|
||||
}
|
||||
|
||||
//create and connect a server list sockets
|
||||
static GError CreateServerListForAvailableSockets(GServerList serverlist, gbool async)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < serverlist->numslsockets; i++) {
|
||||
if (serverlist->slsockets[i].socketstate == ls_none) {
|
||||
CreateServerListSocket(serverlist, &serverlist->slsockets[i], async);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//create and connect a server list socket
|
||||
static GError CreateServerListLANSocket(GServerList serverlist)
|
||||
{
|
||||
int optval = 1;
|
||||
GServerListSocket slsocket = &serverlist->slsockets[0];
|
||||
|
||||
serverlist->slsocket = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if (serverlist->slsocket == INVALID_SOCKET)
|
||||
slsocket->s = socket ( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
|
||||
if (slsocket->s == INVALID_SOCKET)
|
||||
return GE_NOSOCKET;
|
||||
if (setsockopt(serverlist->slsocket, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
|
||||
if (setsockopt(slsocket->s, SOL_SOCKET, SO_BROADCAST, (char *)&optval, sizeof(optval)) != 0)
|
||||
return GE_NOSOCKET;
|
||||
|
||||
//else we are ready to broadcast
|
||||
|
@ -271,14 +358,14 @@ static void ServerListModeChange(GServerList serverlist, GServerListState newsta
|
|||
|
||||
// validate us to the master and send a list request
|
||||
#define SECURE "\\secure\\"
|
||||
static GError SendListRequest(GServerList serverlist, char *filter)
|
||||
static GError SendListRequest(GServerList serverlist, GServerListSocket slsocket, char *filter)
|
||||
{
|
||||
char data[256], *ptr, result[64];
|
||||
int len;
|
||||
int i;
|
||||
char *modifier;
|
||||
|
||||
len = recv(serverlist->slsocket, data, sizeof(data) - 1, 0);
|
||||
len = recv(slsocket->s, data, sizeof(data) - 1, 0);
|
||||
if (gsiSocketIsError(len)) {
|
||||
return GE_NOCONNECT;
|
||||
}
|
||||
|
@ -309,7 +396,7 @@ static GError SendListRequest(GServerList serverlist, char *filter)
|
|||
serverlist->enginename, ENGINE_VERSION, result); //validate us
|
||||
}
|
||||
|
||||
len = send ( serverlist->slsocket, data, strlen(data), 0 );
|
||||
len = send ( slsocket->s, data, strlen(data), 0 );
|
||||
if (gsiSocketIsError(len) || len == 0)
|
||||
return GE_NOCONNECT;
|
||||
|
||||
|
@ -330,11 +417,13 @@ static GError SendListRequest(GServerList serverlist, char *filter)
|
|||
sprintf(data, "\\list\\%s\\gamename\\%s\\where\\%s\\final\\", modifier, serverlist->gamename, filter);
|
||||
else
|
||||
sprintf(data, "\\list\\%s\\gamename\\%s\\final\\", modifier, serverlist->gamename);
|
||||
len = send ( serverlist->slsocket, data, strlen(data), 0 );
|
||||
len = send ( slsocket->s, data, strlen(data), 0 );
|
||||
if (gsiSocketIsError(len) || len == 0)
|
||||
return GE_NOCONNECT;
|
||||
|
||||
ServerListModeChange(serverlist, sl_listxfer);
|
||||
if (serverlist->state == sl_idle) {
|
||||
ServerListModeChange(serverlist, sl_listxfer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -349,7 +438,7 @@ static GError SendBroadcastRequest(GServerList serverlist, int startport, int en
|
|||
for (i = startport ; i <= endport ; i += delta)
|
||||
{
|
||||
saddr.sin_port = htons(i);
|
||||
sendto(serverlist->slsocket, "\\status\\",8,0,(struct sockaddr *)&saddr,sizeof(saddr));
|
||||
sendto(serverlist->slsockets[0].s, "\\status\\",8,0,(struct sockaddr *)&saddr,sizeof(saddr));
|
||||
}
|
||||
ServerListModeChange(serverlist, sl_lanlist);
|
||||
serverlist->lanstarttime = current_time();
|
||||
|
@ -379,45 +468,58 @@ GError ServerListUpdate(GServerList serverlist, gbool async)
|
|||
return ServerListUpdate2(serverlist, async, NULL, qt_status);
|
||||
}
|
||||
|
||||
/* ServerListCheckSocketError
|
||||
-------------------------
|
||||
Verify if the server list socket has an error or has timed out, and abort. */
|
||||
GError ServerListCheckSocketError(GServerList serverlist, GServerListSocket slsocket)
|
||||
{
|
||||
int so_error;
|
||||
int len = sizeof(so_error);
|
||||
getsockopt(slsocket->s, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
|
||||
// Abort if the socket has an error or if it connect/recv has timed out
|
||||
if (so_error || current_time() >= slsocket->lastreplytime + INTERNET_SEARCH_TIME) {
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
slsocket->socketstate = ls_none;
|
||||
return GE_NOCONNECT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ServerListStartQuery
|
||||
-------------------------
|
||||
Start querying a GServerList. */
|
||||
GError ServerListStartQuery(GServerList serverlist, gbool async)
|
||||
GError ServerListStartQuery(GServerList serverlist, GServerListSocket slsocket, gbool async)
|
||||
{
|
||||
GError error;
|
||||
int i;
|
||||
|
||||
if (serverlist->state != sl_connecting) {
|
||||
if (slsocket->socketstate != ls_connecting) {
|
||||
return GE_BUSY;
|
||||
}
|
||||
|
||||
if (serverlist->abortupdate) {
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
for(i = 0; i < serverlist->numslsockets; i++) {
|
||||
closesocket(serverlist->slsockets[i].s);
|
||||
serverlist->slsockets[i].s = INVALID_SOCKET;
|
||||
}
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
return GE_NOCONNECT;
|
||||
}
|
||||
|
||||
if (async) {
|
||||
// Abort if the socket is in error
|
||||
int so_error;
|
||||
int len = sizeof(so_error);
|
||||
getsockopt(serverlist->slsocket, SOL_SOCKET, SO_ERROR, &so_error, &len);
|
||||
|
||||
if (so_error) {
|
||||
serverlist->state = sl_idle;
|
||||
return GE_NOCONNECT;
|
||||
}
|
||||
|
||||
// Check for pending data
|
||||
char buf;
|
||||
if (recv(serverlist->slsocket, &buf, 1, MSG_PEEK) == -1) {
|
||||
if (recv(slsocket->s, &buf, 1, MSG_PEEK) == -1) {
|
||||
return GE_BUSY;
|
||||
}
|
||||
}
|
||||
|
||||
serverlist->state = sl_idle;
|
||||
slsocket->socketstate = ls_connected;
|
||||
|
||||
error = SendListRequest(serverlist, serverlist->filter);
|
||||
error = SendListRequest(serverlist, slsocket, serverlist->filter);
|
||||
if (error) return error;
|
||||
if (serverlist->querytype != qt_grouprooms && serverlist->querytype != qt_masterinfo) {
|
||||
error = InitUpdateList(serverlist);
|
||||
|
@ -436,29 +538,38 @@ Start updating a GServerList. */
|
|||
GError ServerListUpdate2(GServerList serverlist, gbool async, char *filter, GQueryType querytype)
|
||||
{
|
||||
GError error;
|
||||
int i;
|
||||
|
||||
if (serverlist->state != sl_idle)
|
||||
return GE_BUSY;
|
||||
|
||||
serverlist->querytype = querytype;
|
||||
error = CreateServerListSocket(serverlist, async);
|
||||
if (error) return error;
|
||||
error = CreateServerListForAvailableSockets(serverlist, async);
|
||||
//if (error) return error;
|
||||
|
||||
serverlist->nextupdate = 0;
|
||||
serverlist->abortupdate = 0;
|
||||
// Added in 2.0
|
||||
serverlist->numservers = ServerListCount(serverlist);
|
||||
// Added in 2.0
|
||||
serverlist->cryptinfo.offset = -1;
|
||||
strncpy(serverlist->filter, filter, sizeof(serverlist->filter));
|
||||
//serverlist->cryptinfo.offset = -1;
|
||||
if (filter) {
|
||||
strncpy(serverlist->filter, filter, sizeof(serverlist->filter));
|
||||
} else {
|
||||
serverlist->filter[0] = 0;
|
||||
}
|
||||
|
||||
serverlist->state = sl_connecting;
|
||||
serverlist->async = async;
|
||||
|
||||
if (async) {
|
||||
// As it's asynchronous, set the state to transfering
|
||||
ServerListModeChange(serverlist, sl_listxfer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ServerListStartQuery(serverlist, async);
|
||||
for(i = 0; i < serverlist->numslsockets; i++) {
|
||||
ServerListStartQuery(serverlist, &serverlist->slsockets[i], async);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -647,7 +758,7 @@ GError ServerListAuxUpdate(GServerList serverlist, const char *ip, int port, gbo
|
|||
return 0;
|
||||
}
|
||||
|
||||
static GError ServerListLANList(GServerList serverlist)
|
||||
static GError ServerListLANList(GServerList serverlist, GServerListSocket slsocket)
|
||||
{
|
||||
struct timeval timeout = {0,0};
|
||||
fd_set set;
|
||||
|
@ -659,11 +770,11 @@ static GError ServerListLANList(GServerList serverlist)
|
|||
while (1) //we break if the select fails
|
||||
{
|
||||
FD_ZERO(&set);
|
||||
FD_SET( serverlist->slsocket, &set);
|
||||
FD_SET( slsocket->s, &set);
|
||||
error = select(FD_SETSIZE, &set, NULL, NULL, &timeout);
|
||||
if (gsiSocketIsError(error) || 0 == error) //no data
|
||||
break;
|
||||
error = recvfrom(serverlist->slsocket, indata, sizeof(indata) - 1, 0, (struct sockaddr *)&saddr, &saddrlen );
|
||||
error = recvfrom(slsocket->s, indata, sizeof(indata) - 1, 0, (struct sockaddr *)&saddr, &saddrlen );
|
||||
if (gsiSocketIsError(error))
|
||||
continue;
|
||||
//we got data, add the server to the list to update
|
||||
|
@ -672,8 +783,8 @@ static GError ServerListLANList(GServerList serverlist)
|
|||
}
|
||||
if (current_time() - serverlist->lanstarttime > LAN_SEARCH_TIME) //done waiting for replies
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
ServerListModeChange(serverlist, sl_querying);
|
||||
}
|
||||
return 0;
|
||||
|
@ -769,10 +880,10 @@ static int ServerListParseInfoList(GServerList serverlist, char *data, int len)
|
|||
}
|
||||
|
||||
//reads the server list from the socket and parses it
|
||||
static GError ServerListReadList(GServerList serverlist)
|
||||
static GError ServerListReadList(GServerList serverlist, GServerListSocket slsocket)
|
||||
{
|
||||
static char data[2048]; //static input buffer
|
||||
static int oldlen = 0;
|
||||
//static char data[2048]; //static input buffer
|
||||
//static int oldlen = 0;
|
||||
fd_set set;
|
||||
struct timeval timeout = {0,0};
|
||||
int len, i;
|
||||
|
@ -781,7 +892,7 @@ static GError ServerListReadList(GServerList serverlist)
|
|||
unsigned short port;
|
||||
|
||||
FD_ZERO(&set);
|
||||
FD_SET(serverlist->slsocket, &set);
|
||||
FD_SET(slsocket->s, &set);
|
||||
#ifndef KGTRN_ACCESS
|
||||
i = select( FD_SETSIZE, &set, NULL, NULL, &timeout );
|
||||
if (i <= 0)
|
||||
|
@ -789,52 +900,57 @@ static GError ServerListReadList(GServerList serverlist)
|
|||
#endif
|
||||
|
||||
//append to data
|
||||
len = recv(serverlist->slsocket, data + oldlen, sizeof(data) - oldlen - 1, 0);
|
||||
len = recv(slsocket->s, slsocket->data + slsocket->oldlen, sizeof(slsocket->data) - slsocket->oldlen - 1, 0);
|
||||
if (gsiSocketIsError(len) || len == 0)
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
oldlen = 0; //clear data so it can be used again
|
||||
ServerListHalt(serverlist);
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
slsocket->socketstate = ls_none;
|
||||
slsocket->oldlen = 0; //clear data so it can be used again
|
||||
//ServerListHalt(serverlist);
|
||||
ServerListModeChange(serverlist, sl_querying);
|
||||
return GE_NOCONNECT;
|
||||
|
||||
}
|
||||
|
||||
if (serverlist->encryptdata && serverlist->cryptinfo.offset != -1) {
|
||||
slsocket->lastreplytime = current_time();
|
||||
serverlist->lastsltime = slsocket->lastreplytime;
|
||||
|
||||
if (serverlist->encryptdata && slsocket->cryptinfo.offset != -1) {
|
||||
// Added in 2.0
|
||||
crypt_docrypt(&serverlist->cryptinfo, data + oldlen, len);
|
||||
crypt_docrypt(&slsocket->cryptinfo, slsocket->data + slsocket->oldlen, len);
|
||||
}
|
||||
|
||||
oldlen += len;
|
||||
slsocket->oldlen += len;
|
||||
|
||||
p = data;
|
||||
p = slsocket->data;
|
||||
|
||||
if (!serverlist->encryptdata) {
|
||||
serverlist->cryptinfo.offset = 0;
|
||||
} else if (serverlist->cryptinfo.offset == -1) {
|
||||
slsocket->cryptinfo.offset = 0;
|
||||
} else if (slsocket->cryptinfo.offset == -1) {
|
||||
// Added in 2.0
|
||||
if (oldlen > (*p ^ 0xEC)) {
|
||||
if (slsocket->oldlen > (*p ^ 0xEC)) {
|
||||
*p ^= 0xEC;
|
||||
len = strlen(serverlist->seckey);
|
||||
for (i = 0; i < len; i++) {
|
||||
p[i + 1] ^= serverlist->seckey[i];
|
||||
}
|
||||
init_crypt_key((unsigned char *)p + 1, *p, &serverlist->cryptinfo);
|
||||
init_crypt_key((unsigned char *)p + 1, *p, &slsocket->cryptinfo);
|
||||
p += *p + 1;
|
||||
crypt_docrypt(&serverlist->cryptinfo, (unsigned char *)p, oldlen - (p - data));
|
||||
crypt_docrypt(&slsocket->cryptinfo, (unsigned char *)p, slsocket->oldlen - (p - slsocket->data));
|
||||
}
|
||||
}
|
||||
|
||||
if (serverlist->cryptinfo.offset != -1)
|
||||
if (slsocket->cryptinfo.offset != -1)
|
||||
{
|
||||
while (p - data <= oldlen - 6)
|
||||
while (p - slsocket->data <= slsocket->oldlen - 6)
|
||||
{
|
||||
if (strncmp(p,"\\final\\",7) == 0 || serverlist->abortupdate)
|
||||
{
|
||||
closesocket(serverlist->slsocket);
|
||||
serverlist->slsocket = INVALID_SOCKET;
|
||||
oldlen = 0; //clear data so it can be used again
|
||||
closesocket(slsocket->s);
|
||||
slsocket->s = INVALID_SOCKET;
|
||||
slsocket->socketstate = ls_none;
|
||||
slsocket->oldlen = 0; //clear data so it can be used again
|
||||
if (serverlist->querytype == qt_grouprooms || serverlist->querytype == qt_masterinfo) {
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
} else {
|
||||
|
@ -842,11 +958,11 @@ static GError ServerListReadList(GServerList serverlist)
|
|||
}
|
||||
return 0; //get out!!
|
||||
}
|
||||
if (oldlen < 6) //no way it could be a full IP, quit
|
||||
if (slsocket->oldlen < 6) //no way it could be a full IP, quit
|
||||
break;
|
||||
|
||||
if (serverlist->querytype == qt_grouprooms || serverlist->querytype == qt_masterinfo) {
|
||||
i = ServerListParseInfoList(serverlist, p, oldlen - (p - data));
|
||||
i = ServerListParseInfoList(serverlist, p, slsocket->oldlen - (p - slsocket->data));
|
||||
if (i < 0) {
|
||||
serverlist->abortupdate = 1;
|
||||
} else if (!i) {
|
||||
|
@ -860,14 +976,14 @@ static GError ServerListReadList(GServerList serverlist)
|
|||
p += 2;
|
||||
// Added in 2.0
|
||||
// Skip adding the server if already exists
|
||||
if (ServerListFindServerMax(serverlist, ip, ntohs(port), serverlist->numservers) == -1) {
|
||||
if (ServerListFindServer(serverlist, ip, ntohs(port)) == -1) {
|
||||
ServerListAddServer(serverlist, ip, ntohs(port), serverlist->querytype);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
oldlen = oldlen - (p - data);
|
||||
memmove(data,p,oldlen); //shift it over
|
||||
slsocket->oldlen = slsocket->oldlen - (p - slsocket->data);
|
||||
memmove(slsocket->data,p,slsocket->oldlen); //shift it over
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
@ -942,14 +1058,30 @@ static GError ServerListQueryLoop(GServerList serverlist)
|
|||
*/
|
||||
serverlist->updatelist[i].currentserver = NULL; //reuse the updatelist
|
||||
}
|
||||
|
||||
|
||||
if (serverlist->abortupdate || (serverlist->nextupdate >= ArrayLength(serverlist->servers) && scount == 0))
|
||||
{ //we are done!!
|
||||
FreeUpdateList(serverlist);
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
if (serverlist->abortupdate) {
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (serverlist->startslindex < ServerListGetNumMasters() || !ServerListHasFinishedFetchingList(serverlist)) {
|
||||
ServerListModeChange(serverlist, sl_listxfer);
|
||||
} else {
|
||||
// No more masters
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (!ServerListHasFinishedFetchingList(serverlist) && current_time() < serverlist->lastsltime + SERVER_QUERY_MAX_PAUSE) {
|
||||
// Make sure to not send out other queries if currently fetching from other lists
|
||||
// to avoid overloading the network
|
||||
return GE_BUSY;
|
||||
}
|
||||
|
||||
//now, send out queries on available sockets
|
||||
for (i = 0 ; i < serverlist->maxupdates && serverlist->nextupdate < ArrayLength(serverlist->servers) ; i++)
|
||||
if (serverlist->updatelist[i].currentserver == NULL) //it's availalbe
|
||||
|
@ -968,31 +1100,96 @@ static GError ServerListQueryLoop(GServerList serverlist)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* ServerListThink
|
||||
/* ServerListThinkSocket
|
||||
------------------
|
||||
For use with Async Updates. This needs to be called every ~10ms for list processing and
|
||||
updating to occur during async server list updates */
|
||||
GError ServerListThink(GServerList serverlist)
|
||||
GError ServerListThinkSocket(GServerList serverlist, GServerListSocket slsocket)
|
||||
{
|
||||
GError socketerror;
|
||||
|
||||
if (slsocket->s == INVALID_SOCKET) {
|
||||
return GE_NOSOCKET;
|
||||
}
|
||||
|
||||
socketerror = ServerListCheckSocketError(serverlist, slsocket);
|
||||
if (socketerror) {
|
||||
return socketerror;
|
||||
}
|
||||
|
||||
switch(slsocket->socketstate)
|
||||
{
|
||||
case ls_connecting:
|
||||
ServerListStartQuery(serverlist, slsocket, 1);
|
||||
break;
|
||||
case ls_connected:
|
||||
//read the data
|
||||
return ServerListReadList(serverlist, slsocket);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (serverlist->state)
|
||||
{
|
||||
case sl_idle: return 0;
|
||||
case sl_listxfer:
|
||||
//read the data
|
||||
return ServerListReadList(serverlist);
|
||||
//return ServerListReadList(serverlist, slsocket);
|
||||
break;
|
||||
case sl_lanlist:
|
||||
return ServerListLANList(serverlist);
|
||||
case sl_querying:
|
||||
//do some queries
|
||||
return ServerListQueryLoop(serverlist);
|
||||
break;
|
||||
case sl_connecting:
|
||||
return ServerListStartQuery(serverlist, 1);
|
||||
break;
|
||||
return ServerListLANList(serverlist, slsocket);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ServerListHasFinishedFetchingList
|
||||
------------------
|
||||
Whether or not the list has finished fetching */
|
||||
static gbool ServerListHasFinishedFetchingList(GServerList serverlist)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < serverlist->numslsockets; i++) {
|
||||
if (serverlist->slsockets[i].s != INVALID_SOCKET) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* ServerListThink
|
||||
------------------
|
||||
For use with Async Updates. This needs to be called every ~10ms for list processing and
|
||||
updating to occur during async server list updates */
|
||||
GError ServerListThink(GServerList serverlist)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < serverlist->numslsockets; i++) {
|
||||
ServerListThinkSocket(serverlist, &serverlist->slsockets[i]);
|
||||
}
|
||||
|
||||
switch(serverlist->state)
|
||||
{
|
||||
case sl_idle:
|
||||
case sl_listxfer:
|
||||
if (!serverlist->abortupdate) {
|
||||
if (serverlist->startslindex < ServerListGetNumMasters()) {
|
||||
CreateServerListForAvailableSockets(serverlist, serverlist->async);
|
||||
} else if (serverlist->state == sl_listxfer && ServerListHasFinishedFetchingList(serverlist)) {
|
||||
ServerListModeChange(serverlist, sl_idle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case sl_querying:
|
||||
//do some queries
|
||||
return ServerListQueryLoop(serverlist);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -23,22 +23,148 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
#pragma once
|
||||
|
||||
#include "q_gamespy.h"
|
||||
#include "../qcommon/qcommon.h"
|
||||
#include "cl_gamespy.h"
|
||||
#include "sv_gamespy.h"
|
||||
|
||||
#define MAX_MASTERS 8
|
||||
#define MASTER_DEFAULT_MSPORT 28900
|
||||
#define MASTER_DEFAULT_HBPORT 27900
|
||||
|
||||
cvar_t *com_master_host[MAX_MASTERS];
|
||||
cvar_t *com_master_msport[MAX_MASTERS];
|
||||
cvar_t *com_master_hbport[MAX_MASTERS];
|
||||
|
||||
master_entry_t entries[MAX_MASTERS];
|
||||
int num_entries = 0;
|
||||
|
||||
static void Com_RestartGameSpy_f(void);
|
||||
|
||||
static qboolean ShouldRefreshMasters()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_MASTERS; i++) {
|
||||
if (com_master_host[i] && com_master_host[i]->latchedString) {
|
||||
return qtrue;
|
||||
}
|
||||
if (com_master_msport[i] && com_master_msport[i]->latchedString) {
|
||||
return qtrue;
|
||||
}
|
||||
if (com_master_hbport[i] && com_master_hbport[i]->latchedString) {
|
||||
return qtrue;
|
||||
}
|
||||
}
|
||||
|
||||
return qfalse;
|
||||
}
|
||||
|
||||
static void CreateMasterVar(int index, const char *host, int msport, int hbport)
|
||||
{
|
||||
assert(index < MAX_MASTERS);
|
||||
|
||||
//
|
||||
// These variables should be modified for testing purposes only.
|
||||
// So prevent them to be saved in the configuration file.
|
||||
//
|
||||
com_master_host[index] = Cvar_Get(va("com_master%d_host", index), host, CVAR_LATCH | CVAR_TEMP);
|
||||
com_master_msport[index] = Cvar_Get(va("com_master%d_msport", index), va("%d", msport), CVAR_LATCH | CVAR_TEMP);
|
||||
com_master_hbport[index] = Cvar_Get(va("com_master%d_hbport", index), va("%d", hbport), CVAR_LATCH | CVAR_TEMP);
|
||||
|
||||
com_master_host[index]->flags &= ~CVAR_ARCHIVE;
|
||||
com_master_msport[index]->flags &= ~CVAR_ARCHIVE;
|
||||
com_master_hbport[index]->flags &= ~CVAR_ARCHIVE;
|
||||
}
|
||||
|
||||
qboolean Com_RefreshGameSpyMasters()
|
||||
{
|
||||
int msIndex = 0;
|
||||
int i;
|
||||
qboolean shouldRestart;
|
||||
|
||||
shouldRestart = ShouldRefreshMasters();
|
||||
|
||||
//
|
||||
// These masters come from the 333networks community and use the same software
|
||||
// that emulate the GameSpy protocol -- see https://333networks.com/
|
||||
// They are managed by different entities, are independent and sync with eachother.
|
||||
//
|
||||
CreateMasterVar(msIndex++, "master.333networks.com", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
CreateMasterVar(msIndex++, "master.errorist.eu", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
CreateMasterVar(msIndex++, "master.noccer.de", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
CreateMasterVar(msIndex++, "master-au.unrealarchive.org", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
CreateMasterVar(msIndex++, "master.frag-net.com", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
|
||||
for (; msIndex < MAX_MASTERS; msIndex++) {
|
||||
CreateMasterVar(msIndex, "", MASTER_DEFAULT_MSPORT, MASTER_DEFAULT_HBPORT);
|
||||
}
|
||||
|
||||
num_entries = 0;
|
||||
|
||||
//
|
||||
// Find and insert valid entries
|
||||
//
|
||||
for (i = 0; i < MAX_MASTER_SERVERS; i++) {
|
||||
master_entry_t *entry = &entries[num_entries];
|
||||
|
||||
if (com_master_host[i]->string && com_master_host[i]->string[0]) {
|
||||
entry->host = com_master_host[i]->string;
|
||||
entry->queryport = com_master_msport[i]->integer;
|
||||
entry->hbport = com_master_hbport[i]->integer;
|
||||
num_entries++;
|
||||
}
|
||||
}
|
||||
|
||||
return shouldRestart;
|
||||
}
|
||||
|
||||
void Com_InitGameSpy()
|
||||
{
|
||||
Com_RefreshGameSpyMasters();
|
||||
|
||||
Cmd_AddCommand("net_gamespy_restart", Com_RestartGameSpy_f);
|
||||
}
|
||||
|
||||
static void Com_RestartGameSpy_f(void)
|
||||
{
|
||||
Com_RefreshGameSpyMasters();
|
||||
|
||||
#ifndef DEDICATED
|
||||
CL_RestartGamespy_f();
|
||||
#endif
|
||||
SV_RestartGamespy_f();
|
||||
}
|
||||
|
||||
unsigned int Com_GetNumMasterEntries()
|
||||
{
|
||||
return num_entries;
|
||||
}
|
||||
|
||||
void Com_GetMasterEntry(int index, master_entry_t *entry)
|
||||
{
|
||||
if (index >= num_entries) {
|
||||
entry->host = NULL;
|
||||
entry->hbport = 0;
|
||||
entry->queryport = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
entry->host = com_master_host[index]->string;
|
||||
entry->queryport = com_master_msport[index]->integer;
|
||||
entry->hbport = com_master_hbport[index]->integer;
|
||||
}
|
||||
|
||||
const char *Com_GetMasterHost()
|
||||
{
|
||||
return "master.333networks.com";
|
||||
return com_master_host[0]->string;
|
||||
}
|
||||
|
||||
int Com_GetMasterQueryPort()
|
||||
{
|
||||
return 28900;
|
||||
return com_master_msport[0]->integer;
|
||||
}
|
||||
|
||||
int Com_GetMasterHeartbeatPort()
|
||||
{
|
||||
return 27900;
|
||||
return com_master_hbport[0]->integer;
|
||||
}
|
||||
|
|
|
@ -24,8 +24,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#pragma once
|
||||
|
||||
void Com_InitGameSpy();
|
||||
#include "../qcommon/q_shared.h"
|
||||
|
||||
typedef struct {
|
||||
const char *host;
|
||||
int queryport;
|
||||
int hbport;
|
||||
} master_entry_t;
|
||||
|
||||
void Com_InitGameSpy();
|
||||
qboolean Com_RefreshGameSpyMasters();
|
||||
|
||||
unsigned int Com_GetNumMasterEntries();
|
||||
void Com_GetMasterEntry(int index, master_entry_t* entry);
|
||||
const char *Com_GetMasterHost();
|
||||
int Com_GetMasterQueryPort();
|
||||
int Com_GetMasterHeartbeatPort();
|
||||
|
|
|
@ -34,8 +34,12 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
static char gamemode[128];
|
||||
static qboolean gcdInitialized = qfalse;
|
||||
static qboolean gcdValid = qfalse;
|
||||
static qboolean gsRunning = qfalse;
|
||||
extern GSIACResult __GSIACResult;
|
||||
|
||||
cvar_t *net_ip = NULL;
|
||||
cvar_t *net_gamespy_port = NULL;
|
||||
|
||||
static const char *SECRET_GS_KEYS[] =
|
||||
{
|
||||
"M5Fdwc",
|
||||
|
@ -255,7 +259,7 @@ static void players_callback(char *outbuf, int maxlen, void *userdata)
|
|||
index,
|
||||
cl->ping
|
||||
);
|
||||
|
||||
|
||||
if (currlen + infolen < maxlen) {
|
||||
strcat(outbuf, infostring);
|
||||
currlen += infolen;
|
||||
|
@ -302,6 +306,12 @@ void SV_ShutdownGamespy()
|
|||
return;
|
||||
}
|
||||
|
||||
if (!gsRunning) {
|
||||
// Added in OPM
|
||||
// Gamespy is not running
|
||||
return;
|
||||
}
|
||||
|
||||
strcpy(gamemode, "exiting");
|
||||
|
||||
if (gcdInitialized) {
|
||||
|
@ -311,12 +321,12 @@ void SV_ShutdownGamespy()
|
|||
|
||||
qr_send_statechanged(NULL);
|
||||
qr_shutdown(NULL);
|
||||
|
||||
gsRunning = qfalse;
|
||||
}
|
||||
|
||||
qboolean SV_InitGamespy()
|
||||
{
|
||||
cvar_t *net_ip;
|
||||
cvar_t *net_gamespy_port;
|
||||
char secret_key[9];
|
||||
const char *secret_gs_key;
|
||||
const char *gs_game_name;
|
||||
|
@ -378,6 +388,8 @@ qboolean SV_InitGamespy()
|
|||
gcdInitialized = qtrue;
|
||||
}
|
||||
|
||||
gsRunning = qtrue;
|
||||
|
||||
return qtrue;
|
||||
}
|
||||
|
||||
|
@ -503,12 +515,57 @@ void SV_GamespyAuthorize(netadr_t from, const char *response)
|
|||
}
|
||||
}
|
||||
|
||||
const char *qr_get_master_host()
|
||||
void SV_RestartGamespy()
|
||||
{
|
||||
return Com_GetMasterHost();
|
||||
if (gsRunning) {
|
||||
//
|
||||
// Reinitialize Gamespy
|
||||
//
|
||||
SV_ShutdownGamespy();
|
||||
SV_InitGamespy();
|
||||
}
|
||||
}
|
||||
|
||||
int qr_get_master_port()
|
||||
void SV_RestartGamespy_f()
|
||||
{
|
||||
return Com_GetMasterHeartbeatPort();
|
||||
SV_RestartGamespy();
|
||||
}
|
||||
|
||||
void SV_TryRestartGamespy()
|
||||
{
|
||||
if (Com_RefreshGameSpyMasters()) {
|
||||
SV_RestartGamespy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (net_gamespy_port && net_gamespy_port->latchedString) {
|
||||
SV_RestartGamespy();
|
||||
return;
|
||||
}
|
||||
|
||||
if (sv_gamespy && sv_gamespy->latchedString) {
|
||||
SV_RestartGamespy();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int qr_get_num_masters()
|
||||
{
|
||||
return Com_GetNumMasterEntries();
|
||||
}
|
||||
|
||||
const char *qr_get_master_host(int index)
|
||||
{
|
||||
master_entry_t entry;
|
||||
Com_GetMasterEntry(index, &entry);
|
||||
|
||||
return entry.host;
|
||||
}
|
||||
|
||||
int qr_get_master_port(int index)
|
||||
{
|
||||
master_entry_t entry;
|
||||
Com_GetMasterEntry(index, &entry);
|
||||
|
||||
return entry.hbport;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "q_gamespy.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
@ -37,6 +39,13 @@ extern const char* GS_GetCurrentGameName();
|
|||
|
||||
void SV_CreateGamespyChallenge(char* challenge);
|
||||
void SV_GamespyAuthorize(netadr_t from, const char* response);
|
||||
void SV_GamespyHeartbeat();
|
||||
void SV_ProcessGamespyQueries();
|
||||
qboolean SV_InitGamespy();
|
||||
void SV_ShutdownGamespy();
|
||||
void SV_RestartGamespy();
|
||||
void SV_RestartGamespy_f();
|
||||
void SV_TryRestartGamespy();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -163,9 +163,11 @@ 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 struct sockaddr_in MasterList[8];
|
||||
static struct sockaddr_in *MasterList = NULL;
|
||||
static char keyvalue[8192];
|
||||
static int MasterCount;
|
||||
static int MasterMaxCount;
|
||||
|
||||
/********
|
||||
PROTOTYPES
|
||||
|
@ -173,6 +175,7 @@ PROTOTYPES
|
|||
static void send_heartbeat(qr_t qrec, int statechanged);
|
||||
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);
|
||||
static int do_connect_multi();
|
||||
void qr_check_queries(qr_t qrec);
|
||||
void qr_check_send_heartbeat(qr_t qrec);
|
||||
|
||||
|
@ -270,7 +273,7 @@ int qr_init(qr_t* qrec,
|
|||
qrec = ¤t_rec;
|
||||
}
|
||||
|
||||
return do_connect(hbsock, MASTER_ADDR, MASTER_PORT, &(*qrec)->hbaddr);
|
||||
return do_connect_multi();
|
||||
}
|
||||
|
||||
void init_qrec(qr_t* qrec,
|
||||
|
@ -339,7 +342,7 @@ int qr_init_socket(qr_t* qrec,
|
|||
qr_players_callback,
|
||||
userdata);
|
||||
|
||||
return do_connect(s, MASTER_ADDR, MASTER_PORT, &(*qrec)->hbaddr);
|
||||
return do_connect_multi();
|
||||
}
|
||||
|
||||
/* qr_process_queries: Processes any waiting queries, and sends a
|
||||
|
@ -445,6 +448,14 @@ void qr_shutdown(qr_t qrec)
|
|||
{
|
||||
gsifree(qrec);
|
||||
}
|
||||
|
||||
if (MasterList) {
|
||||
gsifree(MasterList);
|
||||
MasterList = NULL;
|
||||
}
|
||||
|
||||
MasterCount = 0;
|
||||
|
||||
SocketShutDown();
|
||||
}
|
||||
|
||||
|
@ -469,6 +480,30 @@ static int do_connect(SOCKET sock, char* addr, int port, struct sockaddr_in* hba
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int do_connect_multi()
|
||||
{
|
||||
int i;
|
||||
|
||||
MasterMaxCount = qr_get_num_masters();
|
||||
if (MasterList) {
|
||||
gsifree(MasterList);
|
||||
MasterList = NULL;
|
||||
}
|
||||
|
||||
MasterList = gsimalloc(sizeof(struct sockaddr_in) * MasterMaxCount);
|
||||
MasterCount = 0;
|
||||
|
||||
for(i = 0; i < MasterMaxCount; i++) {
|
||||
struct sockaddr_in hbaddr;
|
||||
if (get_sockaddrin(qr_get_master_host(i), qr_get_master_port(i), &hbaddr, NULL)) {
|
||||
// Valid, add it
|
||||
add_master(&hbaddr);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return a sockaddrin for the given host (numeric or DNS) and port)
|
||||
Returns the hostent in savehent if it is not NULL */
|
||||
int get_sockaddrin(const char* host, int port, struct sockaddr_in* saddr, struct hostent** savehent)
|
||||
|
@ -817,7 +852,7 @@ void add_master(struct sockaddr_in* addr)
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (i == 8) {
|
||||
if (i == MasterMaxCount) {
|
||||
return;
|
||||
} else {
|
||||
MasterList[i] = *addr;
|
||||
|
|
|
@ -65,9 +65,9 @@ as the base port. Generally there is no reason to modify this value.
|
|||
/********
|
||||
DEFINES
|
||||
********/
|
||||
#define MASTER_PORT qr_get_master_port()
|
||||
#define MASTER_PORT qr_get_master_port(0)
|
||||
//#define MASTER_ADDR "master." GSI_DOMAIN_NAME
|
||||
#define MASTER_ADDR qr_get_master_host()
|
||||
#define MASTER_ADDR qr_get_master_host(0)
|
||||
#define FIRST_HB_TIME 30000 /* 30 sec */
|
||||
#define HB_TIME 300000 /* 5 minutes */
|
||||
#define MAX_FIRST_COUNT 10 /* 10 tries = 5 minutes */
|
||||
|
@ -86,8 +86,9 @@ extern char qr_hostname[64];
|
|||
*
|
||||
* @return const char* The full master server address
|
||||
*/
|
||||
extern const char *qr_get_master_host();
|
||||
extern int qr_get_master_port();
|
||||
extern unsigned int qr_get_num_masters();
|
||||
extern const char *qr_get_master_host(int index);
|
||||
extern int qr_get_master_port(int index);
|
||||
|
||||
/********
|
||||
qr_querycallback_t
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue