openmohaa/code/gamespy/Peer/peerSB.c

1113 lines
27 KiB
C
Raw Permalink Normal View History

2023-02-04 21:00:01 +01:00
/*
GameSpy Peer SDK
Dan "Mr. Pants" Schoenblum
dan@gamespy.com
Copyright 1999-2007 GameSpy Industries, Inc
devsupport@gamespy.com
*/
/*************
** INCLUDES **
*************/
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "peerMain.h"
#include "peerOperations.h"
#include "peerSB.h"
#include "peerCallbacks.h"
#include "peerMangle.h"
#include "peerRooms.h"
#include "peerAutoMatch.h"
#include "peerQR.h"
/************
** GLOBALS **
************/
int piSBQueryVersion = QVERSION_QR2;
/**********
** GAMES **
**********/
static void piSBGamesListCallback
(
SBServerListPtr serverlist,
SBListCallbackReason reason,
SBServer server,
void * instance
)
{
PEER peer = (PEER)instance;
PEER_CONNECTION;
#if 0
{
static const char reasonStrings[][32] =
{
"serveradded",
"serverupdated",
"serverdeleted",
"initiallistcomplete",
"disconnected",
"queryerror",
"publicipdetermined"
};
char buffer[256];
sprintf(buffer, "GAMES | LIST | %s", reasonStrings[reason]);
if(server)
sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server));
strcat(buffer, "\n");
OutputDebugString(buffer);
}
#endif
// handle based on the callback reason
switch(reason)
{
case slc_serveradded:
// if it's added call the callback and get it updated
piAddListingGamesCallback(peer, PEERTrue, server, PEER_ADD);
if(!SBServerHasBasicKeys(server))
{
SBBool usequerychallenge = SBFalse;
if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE)
usequerychallenge = SBTrue;
SBQueryEngineUpdateServer(&connection->gameEngine, server, 0, QTYPE_BASIC, usequerychallenge);
}
break;
case slc_serverupdated:
// if it's updated let the app know
piAddListingGamesCallback(peer, PEERTrue, server, PEER_UPDATE);
break;
case slc_serverdeleted:
// if it's deleted, call the callback
if ((server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY|STATE_PENDINGICMPQUERY)) != 0)
SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server);
piAddListingGamesCallback(peer, PEERTrue, server, PEER_REMOVE);
break;
case slc_initiallistcomplete:
// done with the initial list
connection->initialGameList = PEERFalse;
// let the app know
piAddListingGamesCallback(peer, PEERTrue, NULL, PEER_COMPLETE);
break;
case slc_queryerror:
// call the failed callback
piAddListingGamesCallback(peer, PEERFalse, NULL, 0);
break;
case slc_publicipdetermined:
// let the engine know the IP
connection->publicIP = serverlist->mypublicip;
SBQueryEngineSetPublicIP(&connection->gameEngine, serverlist->mypublicip);
break;
default:
break;
}
}
static void piSBGamesEngineCallback
(
SBQueryEnginePtr engine,
SBQueryEngineCallbackReason reason,
SBServer server,
void * instance
)
{
PEER peer = (PEER)instance;
//PEER_CONNECTION;
#if 0
{
static const char reasonStrings[][32] =
{
"updatesuccess",
"updatefailed",
"engineidle"
};
char buffer[256];
sprintf(buffer, "GAMES | ENGINE | %s", reasonStrings[reason]);
if(server)
sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server));
strcat(buffer, "\n");
OutputDebugString(buffer);
}
#endif
// if this is an updated server, call the callback
if(reason == qe_updatesuccess)
piAddListingGamesCallback(peer, PEERTrue, server, PEER_UPDATE);
GSI_UNUSED(engine);
}
PEERBool piSBStartListingGames
(
PEER peer,
const unsigned char * fields,
int numFields,
const char * filter
)
{
char groupFilter[32];
char smartSpyFilter[MAX_FILTER_LEN];
char fullFields[MAX_FIELD_LIST_LEN];
int listLen;
int keyLen;
int i;
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return PEERFalse;
// Stop it if it's going.
/////////////////////////
piSBStopListingGames(peer);
// Clear the list.
//////////////////
SBServerListClear(&connection->gameList);
// Filter by group if in one.
/////////////////////////////
if(connection->groupID)
sprintf(groupFilter, "groupid=%d", connection->groupID);
else
strcpy(groupFilter, "groupid is null");
// Setup the actual filter.
///////////////////////////
if(filter)
{
sprintf(smartSpyFilter, "(%s) AND (", groupFilter);
strzcat(smartSpyFilter, filter, sizeof(smartSpyFilter) - 1);
strcat(smartSpyFilter, ")");
}
else
{
strcpy(smartSpyFilter, groupFilter);
}
// Clear this in case it was set.
/////////////////////////////////
connection->gameEngine.numserverkeys = 0;
// We always set these keys.
////////////////////////////
strcpy(fullFields, "\\hostname\\gamemode");
listLen = (int)strlen(fullFields);
SBQueryEngineAddQueryKey(&connection->gameEngine, HOSTNAME_KEY);
SBQueryEngineAddQueryKey(&connection->gameEngine, GAMEMODE_KEY);
// Build the key list.
//////////////////////
for(i = 0 ; i < numFields ; i++)
{
// Check that we have the space to add the key.
///////////////////////////////////////////////
keyLen = (int)strlen(qr2_registered_key_list[fields[i]]);
if((listLen + keyLen + 1) >= MAX_FIELD_LIST_LEN)
break;
// Add the key.
///////////////
listLen += sprintf(fullFields + listLen, "\\%s", qr2_registered_key_list[fields[i]]);
// Add to the engine query list.
////////////////////////////////
SBQueryEngineAddQueryKey(&connection->gameEngine, fields[i]);
}
// Start updating the list.
///////////////////////////
if(SBServerListConnectAndQuery(&connection->gameList, fullFields, smartSpyFilter, PUSH_UPDATES, 0) != sbe_noerror)
{
piSBStopListingGames(peer);
return PEERFalse;
}
// Doing the initial listing.
/////////////////////////////
connection->initialGameList = PEERTrue;
// Clear the list before they start getting servers.
////////////////////////////////////////////////////
piAddListingGamesCallback(peer, PEERTrue, NULL, PEER_CLEAR);
return PEERTrue;
}
void piSBStopListingGames
(
PEER peer
)
{
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return;
// Stop the listing.
////////////////////
SBServerListDisconnect(&connection->gameList);
// Stop the engine.
///////////////////
SBEngineHaltUpdates(&connection->gameEngine);
// Remove all pending game list callbacks.
//////////////////////////////////////////
piClearCallbacks(peer, PI_LISTING_GAMES_CALLBACK);
}
/***********
** GROUPS **
***********/
static void piSBGroupsListCallback
(
SBServerListPtr serverlist,
SBListCallbackReason reason,
SBServer server,
void * instance
)
{
piOperation * operation;
PEER peer = (PEER)instance;
PEER_CONNECTION;
operation = connection->listingGroupsOperation;
#if 0
{
static const char reasonStrings[][32] =
{
"serveradded",
"serverupdated",
"serverdeleted",
"initiallistcomplete",
"disconnected",
"queryerror",
"publicipdetermined"
};
char buffer[256];
sprintf(buffer, "GROUPS | LIST | %s", reasonStrings[reason]);
if(server)
sprintf(buffer + strlen(buffer), " | %d", ntohl(SBServerGetPublicInetAddress(server)));
strcat(buffer, "\n");
OutputDebugString(buffer);
}
#endif
// handle based on the callback reason
switch(reason)
{
// if it's added call the callback
case slc_serveradded:
{
int groupID = (int)ntohl(SBServerGetPublicInetAddress(server));
//#ifndef GSI_PEER_UNICODE
const char * name = SBServerGetStringValueA(server, "hostname", "(No Name)");
int numWaiting = SBServerGetIntValueA(server, "numwaiting", 0);
int maxWaiting = SBServerGetIntValueA(server, "maxwaiting", 0);
int numGames = SBServerGetIntValueA(server, "numservers", 0);
int numPlaying = SBServerGetIntValueA(server, "numplayers", 0);
//#else
// const unsigned short * name = SBServerGetStringValue(server, L"hostname", L"(No Name)");
// int numWaiting = SBServerGetIntValue(server, L"numwaiting", 0);
// int maxWaiting = SBServerGetIntValue(server, L"maxwaiting", 0);
// int numGames = SBServerGetIntValue(server, L"numservers", 0);
// int numPlaying = SBServerGetIntValue(server, L"numplayers", 0);
//#endif
piAddListGroupRoomsCallback(peer, PEERTrue, groupID, server, name, numWaiting, maxWaiting, numGames, numPlaying, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID);
break;
}
// initial list completion
case slc_initiallistcomplete:
// calling the terminating callback
piAddListGroupRoomsCallback(peer, PEERTrue, 0, NULL, NULL, 0, 0, 0, 0, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID);
piRemoveOperation(peer, operation);
connection->listingGroupsOperation = NULL;
break;
// check for a query error
case slc_queryerror:
// call the failed callback
piAddListGroupRoomsCallback(peer, PEERFalse, 0, NULL, NULL, 0, 0, 0, 0, (peerListGroupRoomsCallback)operation->callback, operation->callbackParam, operation->ID);
piRemoveOperation(peer, operation);
connection->listingGroupsOperation = NULL;
break;
default:
break;
}
GSI_UNUSED(serverlist);
}
PEERBool piSBStartListingGroups
(
PEER peer,
const char * fields
)
{
char fullFields[MAX_FIELD_LIST_LEN + 1];
int len;
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return PEERFalse;
// Stop it if it's going.
/////////////////////////
piSBStopListingGroups(peer);
// Clear the list.
//////////////////
SBServerListClear(&connection->groupList);
// Setup the fields list.
/////////////////////////
strcpy(fullFields, "\\hostname\\numwaiting\\maxwaiting\\numservers\\numplayers");
len = (int)strlen(fullFields);
strzcpy(fullFields + len, fields, (unsigned int)MAX_FIELD_LIST_LEN - len);
// Start updating the list.
///////////////////////////
if(SBServerListConnectAndQuery(&connection->groupList, fullFields, "", SEND_GROUPS, 0) != sbe_noerror)
{
piSBStopListingGroups(peer);
return PEERFalse;
}
return PEERTrue;
}
void piSBStopListingGroups
(
PEER peer
)
{
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return;
// Stop the listing.
////////////////////
SBServerListDisconnect(&connection->groupList);
}
/**************
** AUTOMATCH **
**************/
static PEERBool piIsLocalServer(PEER peer, SBServer server)
{
PEER_CONNECTION;
// check the public ip
if(SBServerGetPublicInetAddress(server) != connection->publicIP)
return PEERFalse;
// check the private ip and port
if(SBServerHasPrivateAddress(server))
{
if(SBServerGetPrivateInetAddress(server) != connection->privateIP)
return PEERFalse;
if(SBServerGetPrivateQueryPort(server) != connection->autoMatchOperation->port)
return PEERFalse;
}
// check the public port
else
{
if(SBServerGetPublicQueryPort(server) != connection->autoMatchOperation->port)
return PEERFalse;
}
return PEERTrue;
}
static int piSBAutoMatchGetServerRating(PEER peer, SBServer server)
{
PEER_CONNECTION;
// ignore the local machine
if(connection->autoMatchReporting && piIsLocalServer(peer, server))
return 0;
// check if it got the keys.
if(!SBServerHasFullKeys(server))
return 0;
// ignore full servers
#ifndef GSI_UNICODE
if(SBServerGetIntValue(server, "numplayers", 0) >= SBServerGetIntValue(server, "maxplayers", 0))
return 0;
#else
if(SBServerGetIntValue(server, L"numplayers", 0) >= SBServerGetIntValue(server, L"maxplayers", 0))
return 0;
#endif
// return the rating for this server
return piCallAutoMatchRateCallback(peer, server);
}
static void piSBAutoMatchCheckUpdatedServer(PEER peer, SBServer server)
{
int rating;
PEER_CONNECTION;
// only do this if we're waiting
if(connection->autoMatchStatus != PEERWaiting)
return;
// if we're already joining a staging room, ignore this
if(connection->enteringRoom[StagingRoom])
return;
// get the rating for this server
rating = piSBAutoMatchGetServerRating(peer, server);
// if it's not acceptable, ignore
if(rating <= 0)
return;
// stop reporting and leave the room
piStopAutoMatchReporting(peer);
piLeaveRoom(peer, StagingRoom, "");
// join the match
if(!piJoinAutoMatchRoom(peer, server))
{
// it's bad news if it failed to start the op
piSetAutoMatchStatus(peer, PEERFailed);
}
}
static void piSBAutoMatchCheckPushedServer(PEER peer, SBServer server)
{
SortInfo info;
int aRating;
PEER_CONNECTION;
// We must be in the waiting or searching phase to rate a server this way
if(connection->autoMatchStatus != PEERWaiting && connection->autoMatchStatus != PEERSearching)
return;
// if we're already joining a staging room, ignore this
if(connection->enteringRoom[StagingRoom])
return;
// Check if this is the only server in our list
if (SBServerListCount(&connection->autoMatchList) == 1)
{
// get the rating for this server
aRating = piSBAutoMatchGetServerRating(peer, server);
// if it's not acceptable, ignore
if(aRating <= 0)
return;
// stop reporting and leave the room
piStopAutoMatchReporting(peer);
piLeaveRoom(peer, StagingRoom, "");
// join the match
if(!piJoinAutoMatchRoom(peer, server))
{
// it's bad news if it failed to start the op
piSetAutoMatchStatus(peer, PEERFailed);
}
}
// otherwise we'll need to run through all the servers
// rate each of them and join the one with the highest rating.
else if (SBServerListCount(&connection->autoMatchList) > 1)
{
int count, i;
SBServer aServer;
// loop through all the servers.
count = SBServerListCount(&connection->autoMatchList);
for(i = (count - 1) ; i >= 0 ; i--)
{
// get the server.
aServer = SBServerListNth(&connection->autoMatchList, i);
// get the rating for this server
aRating = piSBAutoMatchGetServerRating(peer, aServer);
if(aRating <= 0)
{
SBServerListRemoveAt(&connection->autoMatchList, i);
continue;
}
// store this server's rating
SBServerAddIntKeyValue(aServer, PI_AUTOMATCH_RATING_KEY, aRating);
}
// recount
count = SBServerListCount(&connection->autoMatchList);
// no matches?
if(!count)
{
piSetAutoMatchStatus(peer, PEERWaiting);
return;
}
// sort by rating
#ifdef GSI_UNICODE
_tcscpy(info.sortkey, (const unsigned short *)PI_AUTOMATCH_RATING_KEY);
#else
_tcscpy(info.sortkey, PI_AUTOMATCH_RATING_KEY);
#endif
info.comparemode = sbcm_int;
SBServerListSort(&connection->autoMatchList, SBTrue, info);
piStopAutoMatchReporting(peer);
piLeaveRoom(peer, StagingRoom, "");
// join the top rated match
if(!piJoinAutoMatchRoom(peer, SBServerListNth(&connection->autoMatchList, 0)))
{
// it's bad news if it failed to start the op
piSetAutoMatchStatus(peer, PEERFailed);
}
}
}
static void piSBAutoMatchListCallback
(
SBServerListPtr serverlist,
SBListCallbackReason reason,
SBServer server,
void * instance
)
{
PEER peer = (PEER)instance;
PEER_CONNECTION;
#if 0
{
static const char reasonStrings[][32] =
{
"serveradded",
"serverupdated",
"serverdeleted",
"initiallistcomplete",
"disconnected",
"queryerror",
"publicipdetermined"
};
char buffer[256];
sprintf(buffer, "AUTOMATCH | LIST | %s", reasonStrings[reason]);
if(server)
sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server));
strcat(buffer, "\n");
OutputDebugString(buffer);
}
#endif
// handle based on the callback reason
switch(reason)
{
case slc_serveradded:
// If we have the server info, or we already requested it
// just bail
if(server->state & (STATE_FULLKEYS|STATE_PENDINGFULLQUERY))
break;
// If it's behind a firewall, get the keys from the master
if (!SBServerDirectConnect(server))
SBGetServerRulesFromMaster(&connection->autoMatchList, SBServerGetPublicInetAddress(server), SBServerGetPublicQueryPortNBO(server));
else // send normal update
{
SBBool usequerychallenge = SBFalse;
if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE)
usequerychallenge = SBTrue;
SBQueryEngineUpdateServer(&connection->autoMatchEngine, server, 0, QTYPE_FULL, usequerychallenge);
}
break;
case slc_serverupdated:
// If we don't have the full keys, request them
if(!SBServerHasFullKeys(server) && SBServerDirectConnect(server) && !(server->state & STATE_PENDINGFULLQUERY))
{
// Send a normal query, if the server is firewalled we wouldn't be here
// assert(SBServerDirectConnect(server))
SBBool usequerychallenge = SBFalse;
if (serverlist->backendgameflags & QR2_USE_QUERY_CHALLENGE)
usequerychallenge = SBTrue;
SBQueryEngineUpdateServer(&connection->autoMatchEngine, server, 0, QTYPE_FULL, usequerychallenge);
}
else if(!SBServerHasFullKeys(server) && !SBServerDirectConnect(server))
{
SBGetServerRulesFromMaster(&connection->autoMatchList, SBServerGetPublicInetAddress(server), SBServerGetPublicQueryPortNBO(server));
}
else
piSBAutoMatchCheckPushedServer(peer, server);
break;
case slc_serverdeleted:
// make sure it's not in the update queue
if ((server->state & (STATE_PENDINGBASICQUERY|STATE_PENDINGFULLQUERY)) != 0)
SBQueryEngineRemoveServerFromFIFOs(&connection->autoMatchEngine, server);
break;
case slc_initiallistcomplete:
// if no servers were found, start Waiting
// or if servers were found but all were behind a firewall, start Waiting
if(!SBServerListCount(&connection->autoMatchList) ||
(0==connection->autoMatchEngine.querylist.count))
{
piSetAutoMatchStatus(peer, PEERWaiting);
}
break;
case slc_queryerror:
// browsing failed
connection->autoMatchSBFailed = PEERTrue;
if(connection->autoMatchStatus == PEERSearching)
piSetAutoMatchStatus(peer, connection->autoMatchQRFailed?PEERFailed:PEERWaiting);
break;
case slc_publicipdetermined:
// let the engine know the IP
connection->publicIP = serverlist->mypublicip;
SBQueryEngineSetPublicIP(&connection->gameEngine, serverlist->mypublicip);
break;
default:
break;
}
}
static void piSBAutoMatchEngineCallback
(
SBQueryEnginePtr engine,
SBQueryEngineCallbackReason reason,
SBServer server,
void * instance
)
{
PEER peer = (PEER)instance;
int i;
int count;
int rating;
SortInfo info;
PEER_CONNECTION;
#if 0
{
static const char reasonStrings[][32] =
{
"updatesuccess",
"updatefailed",
"engineidle"
};
char buffer[256];
sprintf(buffer, "AUTOMATCH | ENGINE | %s", reasonStrings[reason]);
if(server)
sprintf(buffer + strlen(buffer), " | %s:%d", SBServerGetPublicAddress(server), SBServerGetPublicQueryPort(server));
strcat(buffer, "\n");
OutputDebugString(buffer);
}
#endif
// handle based on the callback reason
switch(reason)
{
case qe_updatesuccess:
// check the server
piSBAutoMatchCheckUpdatedServer(peer, server);
break;
case qe_updatefailed:
if(!SBServerListCount(&connection->autoMatchList))
piSetAutoMatchStatus(peer, PEERWaiting);
break;
// check if the querying is complete.
case qe_engineidle:
// make sure we're searching
if(connection->autoMatchStatus != PEERSearching)
return;
// if we're already in or joining a staging room, ignore this
if(connection->inRoom[StagingRoom] || connection->enteringRoom[StagingRoom])
return;
// loop through all the servers.
count = SBServerListCount(&connection->autoMatchList);
for(i = (count - 1) ; i >= 0 ; i--)
{
// get the server.
server = SBServerListNth(&connection->autoMatchList, i);
// get the rating for this server
rating = piSBAutoMatchGetServerRating(peer, server);
if(rating <= 0)
{
SBServerListRemoveAt(&connection->autoMatchList, i);
continue;
}
// store this server's rating
SBServerAddIntKeyValue(server, PI_AUTOMATCH_RATING_KEY, rating);
}
// recount
count = SBServerListCount(&connection->autoMatchList);
// no matches?
if(!count)
{
piSetAutoMatchStatus(peer, PEERWaiting);
return;
}
// sort by rating
#ifdef GSI_UNICODE
_tcscpy(info.sortkey, (const unsigned short *)PI_AUTOMATCH_RATING_KEY);
#else
_tcscpy(info.sortkey, PI_AUTOMATCH_RATING_KEY);
#endif
info.comparemode = sbcm_int;
SBServerListSort(&connection->autoMatchList, SBTrue, info);
// join the top rated match
if(!piJoinAutoMatchRoom(peer, SBServerListNth(&connection->autoMatchList, 0)))
{
// it's bad news if it failed to start the op
piSetAutoMatchStatus(peer, PEERFailed);
}
break;
default:
break;
}
GSI_UNUSED(engine);
}
PEERBool piSBStartListingAutoMatches
(
PEER peer
)
{
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
{
connection->autoMatchSBFailed = PEERTrue;
return PEERFalse;
}
// stop it if it's going.
piSBStopListingAutoMatches(peer);
// clear the list.
SBServerListClear(&connection->autoMatchList);
// start updating the list.
if(SBServerListConnectAndQuery(&connection->autoMatchList, NULL, connection->autoMatchFilter, PUSH_UPDATES, 0) != sbe_noerror)
{
piSBStopListingAutoMatches(peer);
connection->autoMatchSBFailed = PEERTrue;
return PEERFalse;
}
// clear the error flag
connection->autoMatchSBFailed = PEERFalse;
// we're browsing
connection->autoMatchBrowsing = PEERTrue;
return PEERTrue;
}
void piSBStopListingAutoMatches
(
PEER peer
)
{
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return;
// we're done browsing
connection->autoMatchBrowsing = PEERFalse;
// stop the listing.
SBServerListDisconnect(&connection->autoMatchList);
// stop the engine.
SBEngineHaltUpdates(&connection->autoMatchEngine);
}
/**************
** FUNCTIONS **
**************/
PEERBool piSBInit
(
PEER peer
)
{
char autoMatchTitle[PI_TITLE_MAX_LEN];
PEER_CONNECTION;
// init the game list and engine
memset(&connection->gameList, 0, sizeof(connection->gameList));
SBServerListInit(&connection->gameList, connection->title, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBGamesListCallback, peer);
SBQueryEngineInit(&connection->gameEngine, connection->sbMaxUpdates, piSBQueryVersion, SBFalse, piSBGamesEngineCallback, peer);
// init the group list
memset(&connection->groupList, 0, sizeof(connection->groupList));
SBServerListInit(&connection->groupList, connection->title, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBGroupsListCallback, peer);
// init the AutoMatch list and engine
strzcpy(autoMatchTitle, connection->title, sizeof(autoMatchTitle));
strzcat(autoMatchTitle, "am", sizeof(autoMatchTitle));
memset(&connection->autoMatchList, 0, sizeof(connection->autoMatchList));
SBServerListInit(&connection->autoMatchList, autoMatchTitle, connection->sbName, connection->sbSecretKey, connection->sbGameVersion, SBFalse, piSBAutoMatchListCallback, peer);
SBQueryEngineInit(&connection->autoMatchEngine, connection->sbMaxUpdates, piSBQueryVersion, SBFalse, piSBAutoMatchEngineCallback, peer);
// no host server yet
connection->hostServer = NULL;
// initialized
connection->sbInitialized = PEERTrue;
return PEERTrue;
}
void piSBCleanup
(
PEER peer
)
{
PEER_CONNECTION;
// stop listing
piSBStopListingGames(peer);
piSBStopListingGroups(peer);
// cleanup the SB
if(connection->sbInitialized)
{
SBServerListCleanup(&connection->gameList);
SBEngineCleanup(&connection->gameEngine);
SBServerListCleanup(&connection->groupList);
SBServerListCleanup(&connection->autoMatchList);
SBEngineCleanup(&connection->autoMatchEngine);
}
// AutoMatch cleanup
connection->autoMatchBrowsing = PEERFalse;
}
void piSBUpdateGame
(
PEER peer,
SBServer server,
PEERBool fullUpdate,
PEERBool forceUpdateByMaster,
PEERBool icmpEcho
)
{
PEER_CONNECTION;
// check that we're initialized.
assert(connection->sbInitialized);
if(!connection->sbInitialized)
return;
// Changed 08-26-2004
// Saad Nader
// Added force update by master server parameter
// for internal update function
/////////////////////
if (forceUpdateByMaster)
{
// remove from the existing update lists if present
if(server->flags & UNSOLICITED_UDP_FLAG)
SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server);
// Obtain the information via the master server
SBGetServerRulesFromMaster(&connection->gameList, server->publicip, server->publicport);
return;
}
if (icmpEcho && (server->flags & ICMP_IP_FLAG))
{
SBBool usequerychallenge = SBFalse;
if (connection->gameList.backendgameflags & QR2_USE_QUERY_CHALLENGE)
usequerychallenge = SBTrue;
if (server->flags & UNSOLICITED_UDP_FLAG)
SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server);
SBQueryEngineUpdateServer(&connection->gameEngine, server, 1, QTYPE_ICMP, usequerychallenge);
return;
}
// if the server supports unsolicited UDP, query it directly
if(server->flags & UNSOLICITED_UDP_FLAG)
{
SBBool usequerychallenge = SBFalse;
if (connection->gameList.backendgameflags & QR2_USE_QUERY_CHALLENGE)
usequerychallenge = SBTrue;
// remove from the existing update lists if present
SBQueryEngineRemoveServerFromFIFOs(&connection->gameEngine, server);
// query the server
SBQueryEngineUpdateServer(&connection->gameEngine, server, 1, fullUpdate?QTYPE_FULL:QTYPE_BASIC, usequerychallenge);
}
else
{
// get the values from the master server
SBGetServerRulesFromMaster(&connection->gameList, server->publicip, server->publicport);
}
}
void piSBThink
(
PEER peer
)
{
PEER_CONNECTION;
// check that we're initialized.
if(!connection->sbInitialized)
return;
SBListThink(&connection->gameList);
SBListThink(&connection->groupList);
SBQueryEngineThink(&connection->gameEngine);
SBListThink(&connection->autoMatchList);
SBQueryEngineThink(&connection->autoMatchEngine);
}
void piSendNatNegotiateCookie
(
PEER peer,
unsigned int ip,
unsigned short port,
int cookie
)
{
PEER_CONNECTION;
// check that we're initialized.
if(!connection->sbInitialized)
return;
// send the cookie
if (peerIsAutoMatching(peer))
{
SBSendNatNegotiateCookieToServer(&connection->autoMatchList, ip, htons(port), cookie);
}
else
SBSendNatNegotiateCookieToServer(&connection->gameList, ip, htons(port), cookie);
}
void piSendMessageToServer
(
PEER peer,
unsigned int ip,
unsigned short port,
const char * data,
int len
)
{
PEER_CONNECTION;
// check that we're initialized.
if(!connection->sbInitialized)
return;
// send the message
if(peerIsAutoMatching(peer))
{
SBSendMessageToServer(&connection->autoMatchList, ip, port, data, len);
}
else
{
SBSendMessageToServer(&connection->gameList, ip, port, data, len);
}
}
static void piSBCloneServerTableMap(void * elem, void * clientData)
{
SBKeyValuePair * kvPair = (SBKeyValuePair *)elem;
SBServer clone = (SBServer)clientData;
SBServerAddKeyValue(clone, kvPair->key, kvPair->value);
}
SBServer piSBCloneServer(SBServer server)
{
SBServer clone;
HashTable table;
// allocate the clone
clone = SBAllocServer(NULL, server->publicip, server->publicport);
// save off the table
table = clone->keyvals;
// copy the source server
memcpy(clone, server, sizeof(struct _SBServer));
clone->keyvals = table;
clone->next = NULL;
// copy all the values from the original table
TableMap(server->keyvals, piSBCloneServerTableMap, clone);
return clone;
}
void piSBFreeHostServer(PEER peer)
{
PEER_CONNECTION;
if(!connection->hostServer)
return;
SBServerFree(&connection->hostServer);
connection->hostServer = NULL;
}