major mod to deal with devices that fail to receive ACK and then

reconnect.  I was putting both (i.e. the same device twice) in the
same game.  Now I detect this based on the seed being duplicated and
treat the device as having failed to ACK then proceed with the CONNECT
as if it were new.  Tested pretty heavily but only with two-device
games.
This commit is contained in:
Eric House 2011-06-20 18:13:15 -07:00
parent 44af266db6
commit 85d484a881
9 changed files with 333 additions and 134 deletions

View file

@ -86,14 +86,13 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
m_cookie = cookie==NULL?"":cookie; m_cookie = cookie==NULL?"":cookie;
m_connName = connName==NULL?"":connName; m_connName = connName==NULL?"":connName;
m_cookieID = id; m_cookieID = id;
m_curState = XWS_INITED; m_curState = XWS_EMPTY;
m_nPlayersSought = nPlayers; m_nPlayersSought = nPlayers;
m_nPlayersHere = nAlreadyHere; m_nPlayersHere = nAlreadyHere;
m_locking_thread = 0; m_locking_thread = 0;
m_starttime = uptime(); m_starttime = uptime();
m_in_handleEvents = false; m_in_handleEvents = false;
m_langCode = langCode; m_langCode = langCode;
m_nPendingAcks = 0;
if ( RelayConfigs::GetConfigs()->GetValueFor( "SEND_DELAY_MILLIS", if ( RelayConfigs::GetConfigs()->GetValueFor( "SEND_DELAY_MILLIS",
&m_delayMicros ) ) { &m_delayMicros ) ) {
@ -104,8 +103,13 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
RelayConfigs::GetConfigs()->GetValueFor( "HEARTBEAT", &m_heatbeat ); RelayConfigs::GetConfigs()->GetValueFor( "HEARTBEAT", &m_heatbeat );
logf( XW_LOGINFO, "initing cref for cookie %s, connName %s", logf( XW_LOGINFO, "initing cref for cookie %s, connName %s",
m_cookie.c_str(), m_connName.c_str() ); m_cookie.c_str(), m_connName.c_str() );
}
unsigned int ii;
for ( ii = 0; ii < sizeof(m_timers)/sizeof(m_timers[0]); ++ii ) {
m_timers[ii].m_this = NULL;
m_timers[ii].m_hid = ii + 1;
}
}
CookieRef::CookieRef( const char* cookie, const char* connName, CookieID id, CookieRef::CookieRef( const char* cookie, const char* connName, CookieID id,
int langCode, int nPlayersT, int nAlreadyHere ) int langCode, int nPlayersT, int nAlreadyHere )
@ -176,19 +180,31 @@ CookieRef::Unlock() {
} }
bool bool
CookieRef::_Connect( int socket, int nPlayersH, int nPlayersS, int seed ) CookieRef::_Connect( int socket, int nPlayersH, int nPlayersS, int seed,
bool seenSeed )
{ {
bool connected = false; bool connected = false;
if ( AlreadyHere( seed, socket ) ) { HostID prevHostID = HOST_ID_NONE;
connected = true; /* but drop the packet */ bool alreadyHere = AlreadyHere( seed, socket, &prevHostID );
/* } else if ( AlreadyHere( seed, -1 ) ) { */
/* dupe packet on different socket; need host record */ if ( alreadyHere ) {
} else if ( CRefMgr::Get()->Associate( socket, this ) ) { if ( seenSeed ) { /* we need to get rid of the current entry, then
pushConnectEvent( socket, nPlayersH, nPlayersS, seed ); proceed as if this were a new connection */
handleEvents(); assert( HOST_ID_NONE != prevHostID );
connected = HasSocket_locked( socket ); postDropDevice( prevHostID );
} else { } else {
logf( XW_LOGINFO, "dropping connect event; already connected" ); connected = true; /* but drop the packet */
}
}
if ( !connected ) {
if ( CRefMgr::Get()->Associate( socket, this ) ) {
pushConnectEvent( socket, nPlayersH, nPlayersS, seed );
handleEvents();
connected = HasSocket_locked( socket );
} else {
logf( XW_LOGINFO, "dropping connect event; already connected" );
}
} }
return connected; return connected;
} }
@ -212,7 +228,6 @@ CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersS,
void void
CookieRef::_HandleAck( HostID hostID ) CookieRef::_HandleAck( HostID hostID )
{ {
assert( m_nPendingAcks > 0 && m_nPendingAcks <= 4 );
CRefEvent evt( XWE_GOTONEACK ); CRefEvent evt( XWE_GOTONEACK );
evt.u.ack.srcID = hostID; evt.u.ack.srcID = hostID;
m_eventQueue.push_back( evt ); m_eventQueue.push_back( evt );
@ -288,22 +303,19 @@ CookieRef::SocketForHost( HostID dest )
} }
bool bool
CookieRef::AlreadyHere( unsigned short seed, int socket ) CookieRef::AlreadyHere( unsigned short seed, int socket, HostID* prevHostID )
{ {
logf( XW_LOGINFO, "%s(seed=%x,socket=%d)", __func__, seed, socket ); logf( XW_LOGINFO, "%s(seed=%x,socket=%d)", __func__, seed, socket );
bool here = false; bool here = false;
vector<HostRec>::iterator iter; vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_seed == seed ) { /* client already registered */ here = iter->m_seed == seed; /* client already registered */
if ( iter->m_socket == socket ) { if ( here ) {
/* dup packet */ if ( iter->m_socket != socket ) { /* not just a dupe packet */
here = true; logf( XW_LOGINFO, "%s: seeds match; socket %d assumed closed",
} else { __func__, iter->m_socket );
logf( XW_LOGINFO, "%s: seeds match; nuking existing record" *prevHostID = iter->m_hostID;
" for socket %d b/c assumed closed", __func__,
iter->m_socket );
m_sockets.erase( iter );
} }
break; break;
} }
@ -370,11 +382,10 @@ CookieRef::removeSocket( int socket )
if ( iter->m_socket == socket ) { if ( iter->m_socket == socket ) {
if ( iter->m_ackPending ) { if ( iter->m_ackPending ) {
logf( XW_LOGINFO, logf( XW_LOGINFO,
"Never got ack; removing %d players from DB", "Never got ack; removing hid %d from DB",
iter->m_nPlayersH ); iter->m_hostID );
DBMgr::Get()->RmDevice( ConnName(), iter->m_hostID ); DBMgr::Get()->RmDeviceByHid( ConnName(), iter->m_hostID );
m_nPlayersHere -= iter->m_nPlayersH; m_nPlayersHere -= iter->m_nPlayersH;
--m_nPendingAcks;
} }
m_sockets.erase(iter); m_sockets.erase(iter);
--count; --count;
@ -577,22 +588,24 @@ CookieRef::handleEvents()
switch( takeAction ) { switch( takeAction ) {
case XWA_SEND_CONNRSP: case XWA_SEND_CONNRSP:
if ( increasePlayerCounts( &evt, false ) ) { {
setAllConnectedTimer(); HostID hid;
sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP ); if ( increasePlayerCounts( &evt, false, &hid ) ) {
setAckTimer(); setAllConnectedTimer();
sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP );
setAckTimer( hid );
}
} }
break; break;
case XWA_NOTEACKCHECK:
case XWA_NOTEACK: case XWA_NOTEACK:
modPending( &evt, true ); updateAck( evt.u.ack.srcID, true );
postCheckAllHere(); postCheckAllHere();
break; break;
case XWA_DROPDEVICE: case XWA_DROPDEVICE:
modPending( &evt, false ); updateAck( evt.u.ack.srcID, false );
break; break;
/* case XWA_SEND_1ST_RERSP: */ /* case XWA_SEND_1ST_RERSP: */
@ -603,7 +616,7 @@ CookieRef::handleEvents()
/* break; */ /* break; */
case XWA_SEND_RERSP: case XWA_SEND_RERSP:
increasePlayerCounts( &evt, true ); increasePlayerCounts( &evt, true, NULL );
sendResponse( &evt, false ); sendResponse( &evt, false );
sendAnyStored( &evt ); sendAnyStored( &evt );
postCheckAllHere(); postCheckAllHere();
@ -708,6 +721,16 @@ CookieRef::handleEvents()
} }
m_curState = nextState; m_curState = nextState;
#ifdef DEBUG
if ( XWS_EMPTY == m_curState ) {
assert( 0 == m_sockets.size() );
int nTotal, nHere;
GetPlayerCounts( ConnName(), &nTotal, &nHere );
assert( 0 == nHere );
}
#endif
} else { } else {
logf( XW_LOGERROR, "Killing cref b/c unable to find transition " logf( XW_LOGERROR, "Killing cref b/c unable to find transition "
"from %s on event %s", stateString(m_curState), "from %s on event %s", stateString(m_curState),
@ -779,7 +802,7 @@ CookieRef::send_stored_messages( HostID dest, int socket )
} /* send_stored_messages */ } /* send_stored_messages */
bool bool
CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn ) CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp )
{ {
int nPlayersH = evt->u.con.nPlayersH; int nPlayersH = evt->u.con.nPlayersH;
int socket = evt->u.con.socket; int socket = evt->u.con.socket;
@ -808,9 +831,12 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn )
} }
evt->u.con.srcID = DBMgr::Get()->AddDevice( ConnName(), evt->u.con.srcID, evt->u.con.srcID = DBMgr::Get()->AddDevice( ConnName(), evt->u.con.srcID,
nPlayersH, seed ); nPlayersH, seed, reconn );
HostID hostid = evt->u.con.srcID; HostID hostid = evt->u.con.srcID;
if ( NULL != hidp ) {
*hidp = hostid;
}
/* first add the rec here, whether it'll get ack'd or not */ /* first add the rec here, whether it'll get ack'd or not */
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, " logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, "
@ -831,36 +857,53 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn )
} /* increasePlayerCounts */ } /* increasePlayerCounts */
void void
CookieRef::modPending( const CRefEvent* evt, bool keep ) CookieRef::updateAck( HostID hostID, bool keep )
{ {
HostID hostID = evt->u.ack.srcID; assert( hostID >= HOST_ID_SERVER );
assert( hostID <= 4 );
int socket = 0;
cancelAckTimer( hostID );
vector<HostRec>::iterator iter; vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_ackPending && iter->m_hostID == hostID ) { if ( iter->m_ackPending && iter->m_hostID == hostID ) {
--m_nPendingAcks;
if ( keep ) { if ( keep ) {
iter->m_ackPending = false; iter->m_ackPending = false;
DBMgr::Get()->NoteAckd( ConnName(), hostID );
} else { } else {
DBMgr::Get()->RmDevice( ConnName(), iter->m_hostID ); socket = iter->m_socket;
m_sockets.erase( iter );
} }
break; break;
} }
} }
if ( 0 != socket ) {
removeSocket( socket );
}
printSeeds(__func__); printSeeds(__func__);
} }
void void
CookieRef::postCheckAllHere() CookieRef::postCheckAllHere()
{ {
if ( m_nPendingAcks == 0 && DBMgr::Get()->GameFull( ConnName() ) ) { if ( DBMgr::Get()->AllDevsAckd( ConnName() ) ) {
/* && m_nPlayersHere == m_nPlayersSought ) { /\* complete! *\/ */
CRefEvent evt( XWE_ALLHERE ); CRefEvent evt( XWE_ALLHERE );
m_eventQueue.push_back( evt ); m_eventQueue.push_back( evt );
} }
} }
void
CookieRef::postDropDevice( HostID hostID )
{
CRefEvent evt( XWE_ACKTIMEOUT );
evt.u.ack.srcID = hostID;
m_eventQueue.push_back( evt );
handleEvents();
}
void void
CookieRef::setAllConnectedTimer() CookieRef::setAllConnectedTimer()
{ {
@ -872,23 +915,39 @@ CookieRef::setAllConnectedTimer()
} }
void void
CookieRef::setAckTimer( void ) CookieRef::setAckTimer( HostID hid )
{ {
logf( XW_LOGINFO, "%s()", __func__ ); ASSERT_LOCKED();
logf( XW_LOGINFO, "%s(%d)", __func__, hid );
assert( hid >= HOST_ID_SERVER );
assert( hid <= 4 );
--hid;
assert( NULL == m_timers[hid].m_this );
m_timers[hid].m_this = this;
time_t inHowLong; time_t inHowLong;
if ( RelayConfigs::GetConfigs()->GetValueFor( "DEVACK", &inHowLong ) ) { if ( RelayConfigs::GetConfigs()->GetValueFor( "DEVACK", &inHowLong ) ) {
TimerMgr::GetTimerMgr()->SetTimer( inHowLong, TimerMgr::GetTimerMgr()->SetTimer( inHowLong,
s_checkAck, this, 0 ); s_checkAck, &m_timers[hid], 0 );
++m_nPendingAcks;
} else { } else {
logf( XW_LOGINFO, "not setting timer" ); logf( XW_LOGINFO, "not setting timer" );
} }
} }
void void
CookieRef::cancelAckTimer( void ) CookieRef::cancelAckTimer( HostID hid )
{ {
TimerMgr::GetTimerMgr()->ClearTimer( s_checkAck, this ); ASSERT_LOCKED();
logf( XW_LOGINFO, "%s(%d)", __func__, hid );
assert( hid >= HOST_ID_SERVER );
assert( hid <= 4 );
--hid;
m_timers[hid].m_this = NULL;
// TimerMgr::GetTimerMgr()->ClearTimer( s_checkAck, this );
} }
void void
@ -1231,9 +1290,13 @@ CookieRef::s_checkAllConnected( void* closure )
/* static */ void /* static */ void
CookieRef::s_checkAck( void* closure ) CookieRef::s_checkAck( void* closure )
{ {
CookieRef* self = (CookieRef*)closure; AckTimer* at = (AckTimer*)closure;
SafeCref scr(self); CookieRef* self = at->m_this;
scr.CheckNotAcked(); if ( NULL != self ) {
at->m_this = NULL;
SafeCref scr(self);
scr.CheckNotAcked( at->m_hid );
}
} }
void void
@ -1247,14 +1310,13 @@ CookieRef::_CheckAllConnected()
} }
void void
CookieRef::_CheckNotAcked() CookieRef::_CheckNotAcked( HostID hid )
{ {
logf( XW_LOGINFO, "%s", __func__ ); logf( XW_LOGINFO, "%s(hid=%d)", __func__, hid );
if ( m_nPendingAcks > 0 ) { CRefEvent newEvt( XWE_ACKTIMEOUT );
CRefEvent newEvt( XWE_ACKTIMEOUT ); newEvt.u.ack.srcID = hid;
m_eventQueue.push_back( newEvt ); m_eventQueue.push_back( newEvt );
handleEvents(); handleEvents();
}
} }
void void
@ -1264,10 +1326,11 @@ CookieRef::printSeeds( const char* caller )
char buf[64] = {0}; char buf[64] = {0};
vector<HostRec>::iterator iter; vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
len += snprintf( &buf[len], sizeof(buf)-len, "%.4x/%d ", len += snprintf( &buf[len], sizeof(buf)-len, "%.4x/%d/%c ",
iter->m_seed, iter->m_socket ); iter->m_seed, iter->m_socket,
iter->m_ackPending?'a':'A' );
} }
logf( XW_LOGINFO, "seeds/sockets after %s(): %s", caller, buf ); logf( XW_LOGINFO, "seeds/sockets/ack'd after %s(): %s", caller, buf );
} }
void void

View file

@ -58,6 +58,12 @@ HostRec(HostID hostID, int socket, int nPlayersH, int seed, bool ackPending )
bool m_ackPending; bool m_ackPending;
}; };
struct AckTimer {
public:
HostID m_hid;
class CookieRef* m_this;
};
class CookieRef { class CookieRef {
private: private:
@ -95,7 +101,7 @@ class CookieRef {
HostID HostForSocket( int sock ); HostID HostForSocket( int sock );
/* connect case */ /* connect case */
bool AlreadyHere( unsigned short seed, int socket ); bool AlreadyHere( unsigned short seed, int socket, HostID* prevHostID );
/* reconnect case */ /* reconnect case */
bool AlreadyHere( HostID hid, unsigned short seed, int socket ); bool AlreadyHere( HostID hid, unsigned short seed, int socket );
@ -110,7 +116,8 @@ class CookieRef {
static void Delete( CookieID id ); static void Delete( CookieID id );
static void Delete( const char* name ); static void Delete( const char* name );
bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed ); bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed,
bool seenSeed );
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS, void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed, bool gameDead ); int seed, bool gameDead );
void _HandleAck( HostID hostID ); void _HandleAck( HostID hostID );
@ -122,9 +129,9 @@ class CookieRef {
void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen ); void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen );
void _Remove( int socket ); void _Remove( int socket );
void _CheckAllConnected(); void _CheckAllConnected();
void _CheckNotAcked(); void _CheckNotAcked( HostID hid );
bool ShouldDie() { return m_curState == XWS_DEAD; } bool ShouldDie() { return m_curState == XWS_EMPTY; }
XW_RELAY_STATE CurState() { return m_curState; } XW_RELAY_STATE CurState() { return m_curState; }
void logf( XW_LogLevel level, const char* format, ... ); void logf( XW_LogLevel level, const char* format, ... );
@ -202,18 +209,21 @@ class CookieRef {
void sendResponse( const CRefEvent* evt, bool initial ); void sendResponse( const CRefEvent* evt, bool initial );
void sendAnyStored( const CRefEvent* evt ); void sendAnyStored( const CRefEvent* evt );
void initPlayerCounts( const CRefEvent* evt ); void initPlayerCounts( const CRefEvent* evt );
bool increasePlayerCounts( CRefEvent* evt, bool reconn ); bool increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp );
void modPending( const CRefEvent* evt, bool keep ); void updateAck( HostID hostID, bool keep );
void dropPending( int seed );
void postCheckAllHere(); void postCheckAllHere();
void postDropDevice( HostID hostID );
bool hostAlreadyHere( int seed, int socket ); bool hostAlreadyHere( int seed, int socket );
void reducePlayerCounts( int socket ); void reducePlayerCounts( int socket );
void setAllConnectedTimer(); void setAllConnectedTimer();
void cancelAllConnectedTimer(); void cancelAllConnectedTimer();
void setAckTimer(); void setAckTimer( HostID hid );
void cancelAckTimer(); void cancelAckTimer( HostID hid );
void forward_or_store( const CRefEvent* evt ); void forward_or_store( const CRefEvent* evt );
void send_denied( const CRefEvent* evt, XWREASON why ); void send_denied( const CRefEvent* evt, XWREASON why );
@ -271,7 +281,8 @@ class CookieRef {
int m_langCode; int m_langCode;
time_t m_starttime; time_t m_starttime;
int m_nPendingAcks;
AckTimer m_timers[4];
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;

View file

@ -180,7 +180,8 @@ CRefMgr::GetStats( CrefMgrInfo& mgrInfo )
info.m_langCode = cref->GetLangCode(); info.m_langCode = cref->GetLangCode();
SafeCref sc(cref); SafeCref sc(cref);
sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostSeeds, &info.m_hostIps ); sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostSeeds,
&info.m_hostIps );
mgrInfo.m_crefInfo.push_back( info ); mgrInfo.m_crefInfo.push_back( info );
} }
@ -231,25 +232,31 @@ CRefMgr::getFromFreeList( void )
CookieRef* CookieRef*
CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket, CRefMgr::getMakeCookieRef( const char* cookie, HostID hid, int socket,
int nPlayersH, int nPlayersT, int langCode, int nPlayersH, int nPlayersT, int langCode,
int gameSeed, bool wantsPublic, int seed, bool wantsPublic,
bool makePublic ) bool makePublic, bool* seenSeed )
{ {
CookieRef* cref; CookieRef* cref;
CookieID cid;
char connNameBuf[MAX_CONNNAME_LEN+1] = {0};
int alreadyHere = 0;
/* We have a cookie from a new connection or from a reconnect. This may /* We have a cookie from a new connection or from a reconnect. This may
be the first time it's been seen, or there may be a game currently in be the first time it's been seen, or there may be a game currently in
the XW_ST_CONNECTING state, or it may be a dupe of a connect packet. the XW_ST_CONNECTING state, or it may be a dupe of a connect packet on
If there's a game, cool. Otherwise add a new one. Pass the connName the same or a different socket. If there's a game, cool. Otherwise add
which will be used if set, but if not set we'll be generating another a new one. Pass the connName which will be used if set, but if not set
later when the game is complete. we'll be generating another later when the game is complete.
*/ */
char connNameBuf[MAX_CONNNAME_LEN+1] = {0}; *seenSeed = m_db->SeenSeed( cookie, seed, langCode, nPlayersT,
int alreadyHere = 0; wantsPublic, connNameBuf,
CookieID cid = m_db->FindOpen( cookie, langCode, nPlayersT, nPlayersH, sizeof(connNameBuf), &alreadyHere, &cid );
wantsPublic, if ( !*seenSeed ) {
connNameBuf, sizeof(connNameBuf), cid = m_db->FindOpen( cookie, langCode, nPlayersT, nPlayersH,
&alreadyHere ); wantsPublic, connNameBuf, sizeof(connNameBuf),
&alreadyHere );
}
if ( cid > 0 ) { if ( cid > 0 ) {
cref = getCookieRef_impl( cid ); cref = getCookieRef_impl( cid );
} else { } else {
@ -657,12 +664,14 @@ SafeCref::SafeCref( const char* cookie, int socket, int nPlayersH, int nPlayersS
: m_cref( NULL ) : m_cref( NULL )
, m_mgr( CRefMgr::Get() ) , m_mgr( CRefMgr::Get() )
, m_isValid( false ) , m_isValid( false )
, m_seenSeed( false )
{ {
CookieRef* cref; CookieRef* cref;
cref = m_mgr->getMakeCookieRef( cookie, 0, socket, cref = m_mgr->getMakeCookieRef( cookie, 0, socket,
nPlayersH, nPlayersS, langCode, nPlayersH, nPlayersS, langCode,
gameSeed, wantsPublic, makePublic ); gameSeed, wantsPublic, makePublic,
&m_seenSeed );
if ( cref != NULL ) { if ( cref != NULL ) {
m_locked = cref->Lock(); m_locked = cref->Lock();
m_cref = cref; m_cref = cref;

View file

@ -138,7 +138,8 @@ class CRefMgr {
CookieRef* getMakeCookieRef( const char* cookie, CookieRef* getMakeCookieRef( const char* cookie,
HostID hid, int socket, int nPlayersH, HostID hid, int socket, int nPlayersH,
int nPlayersS, int langCode, int seed, int nPlayersS, int langCode, int seed,
bool wantsPublic, bool makePublic ); bool wantsPublic, bool makePublic,
bool* seenSeed );
/* reconnect case; just the stuff we don't have in db */ /* reconnect case; just the stuff we don't have in db */
CookieRef* getMakeCookieRef( const char* connName, const char* cookie, CookieRef* getMakeCookieRef( const char* connName, const char* cookie,
@ -219,7 +220,8 @@ class SafeCref {
bool Connect( int socket, int nPlayersH, int nPlayersS, int seed ) { bool Connect( int socket, int nPlayersH, int nPlayersS, int seed ) {
if ( IsValid() ) { if ( IsValid() ) {
assert( 0 != m_cref->GetCookieID() ); assert( 0 != m_cref->GetCookieID() );
return m_cref->_Connect( socket, nPlayersH, nPlayersS, seed ); return m_cref->_Connect( socket, nPlayersH, nPlayersS, seed,
m_seenSeed );
} else { } else {
return false; return false;
} }
@ -300,9 +302,9 @@ class SafeCref {
m_cref->_CheckAllConnected(); m_cref->_CheckAllConnected();
} }
} }
void CheckNotAcked() { void CheckNotAcked( HostID hid ) {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_CheckNotAcked(); m_cref->_CheckNotAcked( hid );
} }
} }
const char* Cookie() { const char* Cookie() {
@ -366,6 +368,7 @@ class SafeCref {
} }
bool IsValid() { return m_isValid; } bool IsValid() { return m_isValid; }
bool SeenSeed() { return m_seenSeed; }
private: private:
CookieRef* m_cref; CookieRef* m_cref;
@ -373,6 +376,7 @@ class SafeCref {
bool m_isValid; bool m_isValid;
bool m_locked; bool m_locked;
bool m_dead; bool m_dead;
bool m_seenSeed;
}; /* SafeCref class */ }; /* SafeCref class */

View file

@ -39,6 +39,8 @@ static DBMgr* s_instance = NULL;
static void formatParams( char* paramValues[], int nParams, const char* fmt, static void formatParams( char* paramValues[], int nParams, const char* fmt,
char* buf, int bufLen, ... ); char* buf, int bufLen, ... );
static int here_less_seed( const char* seeds, int perDeviceSum,
unsigned short seed );
/* static */ DBMgr* /* static */ DBMgr*
DBMgr::Get() DBMgr::Get()
@ -130,6 +132,48 @@ DBMgr::FindGame( const char* connName, char* cookieBuf, int bufLen,
logf( XW_LOGINFO, "%s(%s)=>%d", __func__, connName, cid ); logf( XW_LOGINFO, "%s(%s)=>%d", __func__, connName, cid );
return cid; return cid;
} /* FindGame */
bool
DBMgr::SeenSeed( const char* cookie, unsigned short seed,
int langCode, int nPlayersT, bool wantsPublic,
char* connNameBuf, int bufLen, int* nPlayersHP,
CookieID* cid )
{
int nParams = 5;
char* paramValues[nParams];
char buf[512];
formatParams( paramValues, nParams,
"%s"DELIM"%d"DELIM"%d"DELIM"%d"DELIM"%s", buf, sizeof(buf),
cookie, langCode, nPlayersT, seed,
wantsPublic?"TRUE":"FALSE" );
const char* cmd = "SELECT cid, connName, seeds, sum_array(nPerDevice) FROM "
GAMES_TABLE
" WHERE NOT dead"
" AND room ILIKE $1"
" AND lang = $2"
" AND nTotal = $3"
" AND $4 = ANY(seeds)"
" AND $5 = pub"
" ORDER BY ctime DESC"
" LIMIT 1";
PGresult* result = PQexecParams( getThreadConn(), cmd,
nParams, NULL,
paramValues,
NULL, NULL, 0 );
bool found = 1 == PQntuples( result );
if ( found ) {
*cid = atoi( PQgetvalue( result, 0, 0 ) );
*nPlayersHP = here_less_seed( PQgetvalue( result, 0, 2 ),
atoi( PQgetvalue( result, 0, 3 ) ),
seed );
snprintf( connNameBuf, bufLen, "%s", PQgetvalue( result, 0, 1 ) );
}
PQclear( result );
logf( XW_LOGINFO, "%s(%4X)=>%s", __func__, seed, found?"true":"false" );
return found;
} }
CookieID CookieID
@ -174,9 +218,9 @@ DBMgr::FindOpen( const char* cookie, int lang, int nPlayersT, int nPlayersH,
} /* FindOpen */ } /* FindOpen */
bool bool
DBMgr::GameFull( const char* const connName ) DBMgr::AllDevsAckd( const char* const connName )
{ {
const char* cmd = "SELECT ntotal=sum_array(nperdevice) from " GAMES_TABLE const char* cmd = "SELECT ntotal=sum_array(nperdevice) AND 'A'=ALL(ack) from " GAMES_TABLE
" WHERE connName='%s'"; " WHERE connName='%s'";
char query[256]; char query[256];
snprintf( query, sizeof(query), cmd, connName ); snprintf( query, sizeof(query), cmd, connName );
@ -187,12 +231,13 @@ DBMgr::GameFull( const char* const connName )
assert( nTuples <= 1 ); assert( nTuples <= 1 );
bool full = 't' == PQgetvalue( result, 0, 0 )[0]; bool full = 't' == PQgetvalue( result, 0, 0 )[0];
PQclear( result ); PQclear( result );
logf( XW_LOGINFO, "%s=>%d", __func__, full );
return full; return full;
} }
HostID HostID
DBMgr::AddDevice( const char* connName, HostID curID, int nToAdd, DBMgr::AddDevice( const char* connName, HostID curID, int nToAdd,
unsigned short seed ) unsigned short seed, bool ackd )
{ {
HostID newID = curID; HostID newID = curID;
@ -208,29 +253,79 @@ DBMgr::AddDevice( const char* connName, HostID curID, int nToAdd,
assert( newID <= 4 ); assert( newID <= 4 );
const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d," const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d,"
" seeds[%d] = %d, mtimes[%d]='now'" " seeds[%d] = %d, mtimes[%d]='now', ack[%d]=\'%c\'"
" WHERE connName = '%s'"; " WHERE connName = '%s'";
char query[256]; char query[256];
snprintf( query, sizeof(query), fmt, newID, nToAdd, newID, seed, newID, connName ); snprintf( query, sizeof(query), fmt, newID, nToAdd, newID, seed, newID,
newID, ackd?'A':'a', connName );
logf( XW_LOGINFO, "%s: query: %s", __func__, query ); logf( XW_LOGINFO, "%s: query: %s", __func__, query );
execSql( query ); execSql( query );
return newID; return newID;
} /* AddDevice */
void
DBMgr::NoteAckd( const char* const connName, HostID id )
{
char query[256];
const char* fmt = "UPDATE " GAMES_TABLE " SET ack[%d]='A'"
" WHERE connName = '%s'";
snprintf( query, sizeof(query), fmt, id, connName );
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
execSql( query );
} }
bool bool
DBMgr::RmDevice( const char* connName, HostID hid ) DBMgr::RmDeviceByHid( const char* connName, HostID hid )
{ {
const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = 0, " const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = 0, "
"seeds[%d] = 0, mtimes[%d]='now' WHERE connName = '%s'"; "seeds[%d] = 0, ack[%d]='-', mtimes[%d]='now' WHERE connName = '%s'";
char query[256]; char query[256];
snprintf( query, sizeof(query), fmt, hid, hid, hid, connName ); snprintf( query, sizeof(query), fmt, hid, hid, hid, hid, connName );
logf( XW_LOGINFO, "%s: query: %s", __func__, query ); logf( XW_LOGINFO, "%s: query: %s", __func__, query );
return execSql( query ); return execSql( query );
} }
void
DBMgr::RmDeviceBySeed( const char* const connName, unsigned short seed )
{
char seeds[128] = {0};
const char* fmt = "SELECT seeds FROM " GAMES_TABLE
" WHERE connName = '%s'"
" AND %d = ANY(seeds)";
char query[256];
snprintf( query, sizeof(query), fmt, connName, seed );
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
PGresult* result = PQexec( getThreadConn(), query );
if ( 1 == PQntuples( result ) ) {
snprintf( seeds, sizeof(seeds), "%s", PQgetvalue( result, 0, 0 ) );
}
PQclear( result );
if ( 0 != seeds[0] ) {
char *saveptr = NULL;
int ii;
char* str;
for ( str = seeds, ii = 0; ; str = NULL, ++ii ) {
char* tok = strtok_r( str, "{},", &saveptr );
if ( NULL == tok ) {
break;
} else {
int asint = atoi( tok );
if ( asint == seed ) {
RmDeviceByHid( connName, ii + 1 );
break;
}
}
}
} else {
assert(0); /* but don't ship with this!!!! */
}
} /* RmDeviceSeed */
bool bool
DBMgr::HaveDevice( const char* connName, HostID hid, int seed ) DBMgr::HaveDevice( const char* connName, HostID hid, int seed )
{ {
@ -537,7 +632,15 @@ formatParams( char* paramValues[], int nParams, const char* fmt, char* buf,
} }
} }
va_end(ap); va_end(ap);
} }
static int
here_less_seed( const char* seeds, int sumPerDevice, unsigned short seed )
{
logf( XW_LOGINFO, "%s: find %x in \"%s\", sub from \"%d\"", __func__,
seed, seeds, sumPerDevice );
return sumPerDevice - 1; /* FIXME */
}
static void static void
destr_function( void* conn ) destr_function( void* conn )

View file

@ -43,14 +43,22 @@ class DBMgr {
CookieID FindGame( const char* connName, char* cookieBuf, int bufLen, CookieID FindGame( const char* connName, char* cookieBuf, int bufLen,
int* langP, int* nPlayersTP, int* nPlayersHP, int* langP, int* nPlayersTP, int* nPlayersHP,
bool* isDead ); bool* isDead );
bool SeenSeed( const char* cookie, unsigned short seed,
int langCode, int nPlayersT, bool wantsPublic,
char* connNameBuf, int bufLen, int* nPlayersHP,
CookieID* cid );
CookieID FindOpen( const char* cookie, int lang, int nPlayersT, CookieID FindOpen( const char* cookie, int lang, int nPlayersT,
int nPlayersH, bool wantsPublic, int nPlayersH, bool wantsPublic,
char* connNameBuf, int bufLen, int* nPlayersHP ); char* connNameBuf, int bufLen, int* nPlayersHP );
bool GameFull( const char* const connName ); bool AllDevsAckd( const char* const connName );
HostID AddDevice( const char* const connName, HostID curID, HostID AddDevice( const char* const connName, HostID curID,
int nToAdd, unsigned short seed ); int nToAdd, unsigned short seed, bool unAckd );
bool RmDevice( const char* const connName, HostID id ); void NoteAckd( const char* const connName, HostID id );
bool RmDeviceByHid( const char* const connName, HostID id );
void RmDeviceBySeed( const char* const connName, unsigned short seed );
bool HaveDevice( const char* const connName, HostID id, int seed ); bool HaveDevice( const char* const connName, HostID id, int seed );
void AddCID( const char* const connName, CookieID cid ); void AddCID( const char* const connName, CookieID cid );
void ClearCID( const char* connName ); void ClearCID( const char* connName );

View file

@ -61,7 +61,7 @@ typedef struct StateTable {
*/ */
static StateTable g_stateTable[] = { static StateTable g_stateTable[] = {
{ XWS_INITED, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITMORE }, { XWS_EMPTY, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITMORE },
{ XWS_WAITMORE, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITMORE }, { XWS_WAITMORE, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITMORE },
{ XWS_WAITMORE, XWE_GOTONEACK, XWA_NOTEACK, XWS_WAITMORE }, { XWS_WAITMORE, XWE_GOTONEACK, XWA_NOTEACK, XWS_WAITMORE },
{ XWS_WAITMORE, XWE_ACKTIMEOUT, XWA_DROPDEVICE, XWS_WAITMORE }, { XWS_WAITMORE, XWE_ACKTIMEOUT, XWA_DROPDEVICE, XWS_WAITMORE },
@ -73,6 +73,7 @@ static StateTable g_stateTable[] = {
{ XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND }, { XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_ALLHERE, XWA_NONE, XWS_ALLCONND }, { XWS_ALLCONND, XWE_ALLHERE, XWA_NONE, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_ALLCONND }, { XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_ALLCONND },
{ XWS_ALLCONND, XWE_GOTONEACK, XWA_NONE, XWS_ALLCONND },
/* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */ /* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */
/* { XWS_WAITMORE, XWE_CHECKFULL, XWA_, XWS_WAITMORE }, */ /* { XWS_WAITMORE, XWE_CHECKFULL, XWA_, XWS_WAITMORE }, */
@ -107,12 +108,14 @@ static StateTable g_stateTable[] = {
/* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */ /* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */
/* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */ /* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */
{ XWS_ANY, XWE_NOMORESOCKETS, XWA_NONE, XWS_DEAD }, { XWS_ANY, XWE_NOMORESOCKETS, XWA_NONE, XWS_EMPTY },
{ XWS_ANY, XWE_SHUTDOWN, XWA_SHUTDOWN, XWS_DEAD }, { XWS_ANY, XWE_SHUTDOWN, XWA_SHUTDOWN, XWS_EMPTY },
/* drop timeout (unless we're in XWS_WAITMORE; see above) */
{ XWS_ANY, XWE_ACKTIMEOUT, XWA_NONE, XWS_SAME },
/* This doesn't make sense. Can't go straight to ALLCOND if don't have all /* This doesn't make sense. Can't go straight to ALLCOND if don't have all
players/devices. */ players/devices. */
{ XWS_INITED, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE }, { XWS_EMPTY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
{ XWS_MSGONLY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE }, { XWS_MSGONLY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
/* { XWS_MISSING, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 }, */ /* { XWS_MISSING, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 }, */
@ -134,7 +137,7 @@ static StateTable g_stateTable[] = {
{ XWS_MISSING, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_MISSING }, { XWS_MISSING, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_MISSING },
#endif #endif
{ XWS_INITED, XWE_DEVGONE, XWA_RMDEV, XWS_DEAD }, { XWS_EMPTY, XWE_DEVGONE, XWA_RMDEV, XWS_EMPTY },
{ XWS_WAITMORE, XWE_DEVGONE, XWA_RMDEV, XWS_WAITMORE }, { XWS_WAITMORE, XWE_DEVGONE, XWA_RMDEV, XWS_WAITMORE },
/* This should be impossible unless device allows deleting an open/connected /* This should be impossible unless device allows deleting an open/connected
game */ game */
@ -143,20 +146,20 @@ static StateTable g_stateTable[] = {
{ XWS_ALLCONND, XWE_GAMEDEAD, XWA_TELLGAMEDEAD, XWS_ALLCONND }, { XWS_ALLCONND, XWE_GAMEDEAD, XWA_TELLGAMEDEAD, XWS_ALLCONND },
/* Connect timer */ /* Connect timer */
{ XWS_WAITMORE, XWE_CONNTIMER, XWA_TIMERDISCONN, XWS_DEAD }, { XWS_WAITMORE, XWE_CONNTIMER, XWA_TIMERDISCONN, XWS_EMPTY },
/* { XWS_MISSING, XWE_CONNTIMER, XWA_NONE, XWS_MISSING }, */ /* { XWS_MISSING, XWE_CONNTIMER, XWA_NONE, XWS_MISSING }, */
{ XWS_ALLCONND, XWE_CONNTIMER, XWA_NONE, XWS_ALLCONND }, { XWS_ALLCONND, XWE_CONNTIMER, XWA_NONE, XWS_ALLCONND },
{ XWS_WAITMORE, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_WAITMORE }, { XWS_WAITMORE, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_WAITMORE },
/* { XWS_ALLCONND, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */ /* { XWS_ALLCONND, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */
/* { XWS_MISSING, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */ /* { XWS_MISSING, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING }, */
{ XWS_DEAD, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_DEAD }, { XWS_EMPTY, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_EMPTY },
/* This is our bread-n-butter */ /* This is our bread-n-butter */
{ XWS_ALLCONND, XWE_FORWARDMSG, XWA_FWD, XWS_ALLCONND }, { XWS_ALLCONND, XWE_FORWARDMSG, XWA_FWD, XWS_ALLCONND },
/* { XWS_MISSING, XWE_FORWARDMSG, XWA_FWD, XWS_MISSING }, */ /* { XWS_MISSING, XWE_FORWARDMSG, XWA_FWD, XWS_MISSING }, */
{ XWS_DEAD, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_DEAD } { XWS_EMPTY, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_EMPTY }
}; };
@ -172,7 +175,8 @@ getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,
if ( stp->stateStart == curState || stp->stateStart == XWS_ANY ) { if ( stp->stateStart == curState || stp->stateStart == XWS_ANY ) {
if ( stp->stateEvent == curEvent || stp->stateEvent == XWE_ANY ) { if ( stp->stateEvent == curEvent || stp->stateEvent == XWE_ANY ) {
*takeAction = stp->stateAction; *takeAction = stp->stateAction;
*nextState = stp->stateEnd; *nextState =
stp->stateEnd == XWS_SAME? curState : stp->stateEnd;
found = true; found = true;
break; break;
} }
@ -192,11 +196,10 @@ stateString( XW_RELAY_STATE state )
switch( state ) { switch( state ) {
CASESTR(XWS_NONE); CASESTR(XWS_NONE);
CASESTR(XWS_ANY); CASESTR(XWS_ANY);
CASESTR(XWS_INITED); CASESTR(XWS_EMPTY);
CASESTR(XWS_WAITMORE); CASESTR(XWS_WAITMORE);
CASESTR(XWS_WAITING_ACKS); CASESTR(XWS_WAITING_ACKS);
CASESTR(XWS_ALLCONND); CASESTR(XWS_ALLCONND);
CASESTR(XWS_DEAD);
/* CASESTR(XWS_MISSING); */ /* CASESTR(XWS_MISSING); */
CASESTR(XWS_MSGONLY); CASESTR(XWS_MSGONLY);
/* CASESTR(XWS_CHK_ALLHERE); */ /* CASESTR(XWS_CHK_ALLHERE); */
@ -264,7 +267,6 @@ actString( XW_RELAY_ACTION act )
CASESTR(XWA_SEND_INITRSP); CASESTR(XWA_SEND_INITRSP);
CASESTR(XWA_SEND_CONNRSP); CASESTR(XWA_SEND_CONNRSP);
CASESTR(XWA_NOTEACK); CASESTR(XWA_NOTEACK);
CASESTR(XWA_NOTEACKCHECK);
/* CASESTR(XWA_ADDDEVICE); */ /* CASESTR(XWA_ADDDEVICE); */
CASESTR(XWA_DROPDEVICE); CASESTR(XWA_DROPDEVICE);
CASESTR(XWA_SNDALLHERE_2); CASESTR(XWA_SNDALLHERE_2);

View file

@ -27,6 +27,7 @@ typedef
enum { enum {
XWS_NONE XWS_NONE
,XWS_ANY /* wildcard */ ,XWS_ANY /* wildcard */
,XWS_SAME /* wildcard: means use same state as current */
/* ,XWS_CHKCOUNTS_INIT */ /* from initial state, check if all players /* ,XWS_CHKCOUNTS_INIT */ /* from initial state, check if all players
are here. Success should be an error, are here. Success should be an error,
@ -40,11 +41,13 @@ enum {
/* ,XWS_CHK_ALLHERE_2 */ /* same as above, but triggered by a reconnect /* ,XWS_CHK_ALLHERE_2 */ /* same as above, but triggered by a reconnect
rather than a connect request */ rather than a connect request */
,XWS_INITED /* Relay's running and the object's been ,XWS_EMPTY /* Relay's running and the object's been
created, but nobody's signed up yet. This created, and nobody's signed up yet. The
is a very short-lived state since an object should never be in this state except
incoming connection is why the object was immediately after created, just before
created. */ deleted, or transitionally, as after a
device is removed prior to replacing its
record with another. */
,XWS_WAITMORE /* At least one device has connected, but no ,XWS_WAITMORE /* At least one device has connected, but no
packets have yet arrived to be packets have yet arrived to be
@ -63,8 +66,6 @@ enum {
/* ,XWS_ROOMCHK */ /* do we have room for as many players as are /* ,XWS_ROOMCHK */ /* do we have room for as many players as are
being provided */ being provided */
,XWS_DEAD /* About to kill the object */
} XW_RELAY_STATE; } XW_RELAY_STATE;
@ -129,7 +130,6 @@ typedef enum {
// ,XWA_ADDDEVICE /* got ack, so device is in for sure */ // ,XWA_ADDDEVICE /* got ack, so device is in for sure */
,XWA_NOTEACK ,XWA_NOTEACK
,XWA_NOTEACKCHECK
,XWA_DROPDEVICE /* no ack; remove all traces of device */ ,XWA_DROPDEVICE /* no ack; remove all traces of device */
,XWA_SEND_INITRSP /* response to first to connect */ ,XWA_SEND_INITRSP /* response to first to connect */

View file

@ -314,8 +314,6 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
unsigned char* end = bufp + bufLen; unsigned char* end = bufp + bufLen;
bool success = false; bool success = false;
logf( XW_LOGINFO, "%s()", __func__ );
cookie[0] = '\0'; cookie[0] = '\0';
unsigned char flags = *bufp++; unsigned char flags = *bufp++;
@ -324,7 +322,7 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
/* HostID srcID; */ /* HostID srcID; */
unsigned char nPlayersH; unsigned char nPlayersH;
unsigned char nPlayersT; unsigned char nPlayersT;
unsigned short gameSeed; unsigned short seed;
unsigned char langCode; unsigned char langCode;
unsigned char makePublic, wantsPublic; unsigned char makePublic, wantsPublic;
if ( readStr( &bufp, end, cookie, sizeof(cookie) ) if ( readStr( &bufp, end, cookie, sizeof(cookie) )
@ -333,10 +331,11 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
/* && getNetByte( &bufp, end, &srcID ) */ /* && getNetByte( &bufp, end, &srcID ) */
&& getNetByte( &bufp, end, &nPlayersH ) && getNetByte( &bufp, end, &nPlayersH )
&& getNetByte( &bufp, end, &nPlayersT ) && getNetByte( &bufp, end, &nPlayersT )
&& getNetShort( &bufp, end, &gameSeed ) && getNetShort( &bufp, end, &seed )
&& getNetByte( &bufp, end, &langCode ) ) { && getNetByte( &bufp, end, &langCode ) ) {
logf( XW_LOGINFO, "%s(): langCode=%d; nPlayersT=%d; wantsPublic=%d", __func__, logf( XW_LOGINFO, "%s(): langCode=%d; nPlayersT=%d; "
langCode, nPlayersT, wantsPublic ); "wantsPublic=%d; seed=%.4X",
__func__, langCode, nPlayersT, wantsPublic, seed );
/* Make sure second thread can't create new cref for same cookie /* Make sure second thread can't create new cref for same cookie
this one just handled.*/ this one just handled.*/
@ -344,10 +343,10 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
MutexLock ml( &s_newCookieLock ); MutexLock ml( &s_newCookieLock );
SafeCref scr( cookie, socket, nPlayersH, nPlayersT, SafeCref scr( cookie, socket, nPlayersH, nPlayersT,
gameSeed, langCode, wantsPublic, makePublic ); seed, langCode, wantsPublic, makePublic );
/* nPlayersT etc could be slots in SafeCref to avoid passing /* nPlayersT etc could be slots in SafeCref to avoid passing
here */ here */
success = scr.Connect( socket, nPlayersH, nPlayersT, gameSeed ); success = scr.Connect( socket, nPlayersH, nPlayersT, seed );
} else { } else {
err = XWRELAY_ERROR_BADPROTO; err = XWRELAY_ERROR_BADPROTO;
} }
@ -442,7 +441,7 @@ processDisconnect( unsigned char* bufp, int bufLen, int socket )
static void static void
killSocket( int socket ) killSocket( int socket )
{ {
logf( XW_LOGINFO, "killSocket(%d)", socket ); logf( XW_LOGINFO, "%s(%d)", __func__, socket );
CRefMgr::Get()->RemoveSocketRefs( socket ); CRefMgr::Get()->RemoveSocketRefs( socket );
} }