tons of changes, still rough, snapshoted here: a gtk device vs device

game works to completion with both signing up as guests (no -s) with
one local and one remote player (identical commandlines.)  Not yet
tested: if any signs up as a host, reconnecting rather than
connecting, etc.  This is just a snapshot.
This commit is contained in:
Andy2 2010-09-10 01:30:40 -07:00
parent 34a94f23a0
commit 20312144dd
15 changed files with 500 additions and 288 deletions

View file

@ -784,7 +784,7 @@ board_commitTurn( BoardCtxt* board )
/* Hide the tray so no peeking. Leave it hidden even if user
cancels as otherwise another player could get around
passwords and peek at tiles. */
if ( gi_countLocalHumans( board->gi ) > 1 ) {
if ( gi_countLocalPlayers( board->gi, XP_TRUE ) > 1 ) {
result = board_hideTray( board );
}
@ -3310,7 +3310,7 @@ boardTurnChanged( void* p_board )
nextPlayer = chooseBestSelPlayer( board );
if ( nextPlayer >= 0 ) {
XP_U16 nHumans = gi_countLocalHumans( board->gi );
XP_U16 nHumans = gi_countLocalPlayers( board->gi, XP_TRUE );
selectPlayerImpl( board, nextPlayer, nHumans <= 1, XP_TRUE );
}

View file

@ -298,14 +298,17 @@ comms_resetSame( CommsCtxt* comms )
comms->r.nPlayersHere, comms->r.nPlayersTotal );
}
void
comms_reset( CommsCtxt* comms, XP_Bool isServer,
XP_U16 XP_UNUSED_RELAY(nPlayersHere),
XP_U16 XP_UNUSED_RELAY(nPlayersTotal) )
static void
reset_internal( CommsCtxt* comms, XP_Bool isServer,
XP_U16 XP_UNUSED_RELAY(nPlayersHere),
XP_U16 XP_UNUSED_RELAY(nPlayersTotal),
XP_Bool XP_UNUSED_RELAY(resetRelay) )
{
LOG_FUNC();
#ifdef XWFEATURE_RELAY
relayDisconnect( comms );
if ( resetRelay ) {
relayDisconnect( comms );
}
#endif
cleanupInternal( comms );
@ -318,11 +321,21 @@ comms_reset( CommsCtxt* comms, XP_Bool isServer,
comms->connID = CONN_ID_NONE;
#ifdef XWFEATURE_RELAY
init_relay( comms, nPlayersHere, nPlayersTotal );
if ( resetRelay ) {
init_relay( comms, nPlayersHere, nPlayersTotal );
}
#endif
LOG_RETURN_VOID();
} /* comms_reset */
void
comms_reset( CommsCtxt* comms, XP_Bool isServer,
XP_U16 nPlayersHere,
XP_U16 nPlayersTotal )
{
reset_internal( comms, isServer, nPlayersHere, nPlayersTotal, XP_TRUE );
}
#ifdef XWFEATURE_RELAY
static XP_Bool
@ -884,6 +897,7 @@ XP_S16
comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
{
XP_PlayerAddr channelNo = stream_getAddress( stream );
XP_LOGF( "%s: channelNo=%x", __func__, channelNo );
AddressRecord* rec = getRecordFor( comms, NULL, channelNo, XP_FALSE );
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
MsgQueueElem* elem;
@ -1119,13 +1133,38 @@ got_connect_cmd( CommsCtxt* comms, XWStreamCtxt* stream,
XP_Bool reconnected )
{
XP_U16 nHere, nSought;
XP_Bool isServer;
set_relay_state( comms, reconnected ? COMMS_RELAYSTATE_RECONNECTED
: COMMS_RELAYSTATE_CONNECTED );
comms->r.myHostID = stream_getU8( stream );
isServer = HOST_ID_SERVER == comms->r.myHostID;
if ( isServer != comms->isServer ) {
comms->isServer = isServer;
util_setIsServer( comms->util, comms->isServer );
reset_internal( comms, isServer, comms->r.nPlayersHere,
comms->r.nPlayersTotal, XP_FALSE );
}
comms->r.heartbeat = stream_getU16( stream );
nSought = (XP_U16)stream_getU8( stream );
nHere = (XP_U16)stream_getU8( stream );
#ifdef DEBUG
{
XP_UCHAR connName[MAX_CONNNAME_LEN+1];
stringFromStreamHere( stream, connName, sizeof(connName) );
XP_ASSERT( comms->r.connName[0] == '\0'
|| 0 == XP_STRCMP( comms->r.connName, connName ) );
XP_MEMCPY( comms->r.connName, connName, sizeof(comms->r.connName) );
XP_LOGF( "%s: connName: \"%s\"", __func__, connName );
}
#else
stringFromStreamHere( stream, comms->r.connName,
sizeof(comms->r.connName) );
#endif
if ( ! reconnected ) {
/* This may belong as an alert to user so knows has connected. */
(*comms->procs.rconnd)( comms->procs.closure, XP_FALSE, nSought - nHere );
@ -1310,6 +1349,7 @@ preProcess( CommsCtxt* comms, XWStreamCtxt* stream,
default:
break;
}
LOG_RETURNF( "%d", consumed );
return consumed;
} /* preProcess */
@ -1419,6 +1459,7 @@ validateInitialMessage( CommsCtxt* comms,
if ( addRec ) {
if ( comms->isServer ) {
XP_LOGF( "%s: looking at channelNo: %x", __func__, *channelNo );
XP_ASSERT( (*channelNo && CHANNEL_MASK) == 0 );
*channelNo |= ++comms->nextChannelNo;
XP_ASSERT( comms->nextChannelNo <= CHANNEL_MASK );
@ -1432,6 +1473,7 @@ validateInitialMessage( CommsCtxt* comms,
}
#endif
} else {
XP_LOGF( "%s: looking at channelNo: %x", __func__, *channelNo );
rec = getRecordFor( comms, addr, *channelNo, XP_TRUE );
if ( !!rec ) {
/* reject: we've already seen init message on channel */
@ -1543,7 +1585,7 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
/* Call after we've had a chance to create rec for addr */
noteHBReceived( comms/* , addr */ );
LOG_RETURNF( "%d", (XP_U16)messageValid );
LOG_RETURNF( "%s", messageValid?"valid":"invalid" );
return messageValid;
} /* comms_checkIncomingStream */
@ -1860,6 +1902,23 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
}
break;
case XWRELAY_GAME_CONNECT:
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
stringToStream( tmpStream, addr.u.ip_relay.invite );
stream_putU8( tmpStream, addr.u.ip_relay.seeksPublicRoom );
stream_putU8( tmpStream, addr.u.ip_relay.advertiseRoom );
/* XP_ASSERT( cmd == XWRELAY_GAME_RECONNECT */
/* || comms->r.myHostID == HOST_ID_NONE */
/* || comms->r.myHostID == HOST_ID_SERVER ); */
XP_LOGF( "%s: writing nPlayersHere: %d; nPlayersTotal: %d",
__func__, comms->r.nPlayersHere,
comms->r.nPlayersTotal );
stream_putU8( tmpStream, comms->r.nPlayersHere );
stream_putU8( tmpStream, comms->r.nPlayersTotal );
stream_putU16( tmpStream, getChannelSeed(comms) );
stringToStream( tmpStream, comms->r.connName );
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
break;
case XWRELAY_GAME_RECONNECT:
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
stringToStream( tmpStream, addr.u.ip_relay.invite );
@ -1869,15 +1928,15 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
XP_ASSERT( cmd == XWRELAY_GAME_RECONNECT
|| comms->r.myHostID == HOST_ID_NONE
|| comms->r.myHostID == HOST_ID_SERVER );
XP_LOGF( "%s: writing nPlayersHere: %d; nPlayersTotal: %d",
__func__, comms->r.nPlayersHere,
comms->r.nPlayersTotal );
stream_putU8( tmpStream, comms->r.nPlayersHere );
stream_putU8( tmpStream, comms->r.nPlayersTotal );
stream_putU16( tmpStream, getChannelSeed(comms) );
if ( XWRELAY_GAME_RECONNECT == cmd ) {
stringToStream( tmpStream, comms->r.connName );
} else {
const CurGameInfo* gameInfo = comms->util->gameInfo;
stream_putU8( tmpStream, gameInfo->dictLang );
}
const CurGameInfo* gameInfo = comms->util->gameInfo;
stream_putU8( tmpStream, gameInfo->dictLang );
stringToStream( tmpStream, comms->r.connName );
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
break;

View file

@ -50,7 +50,7 @@ checkServerRole( CurGameInfo* gi, XP_U16* nPlayersHere, XP_U16* nPlayersTotal )
if ( !!gi ) {
XP_U16 ii, remoteCount = 0;
if ( SERVER_ISSERVER == gi->serverRole ) {
if ( SERVER_STANDALONE != gi->serverRole ) {
for ( ii = 0; ii < gi->nPlayers; ++ii ) {
if ( !gi->players[ii].isLocal ) {
++remoteCount;
@ -65,11 +65,7 @@ checkServerRole( CurGameInfo* gi, XP_U16* nPlayersHere, XP_U16* nPlayersTotal )
}
*nPlayersHere = gi->nPlayers - remoteCount;
if ( SERVER_ISCLIENT == gi->serverRole ) {
*nPlayersTotal = 0;
} else {
*nPlayersTotal = gi->nPlayers;
}
*nPlayersTotal = gi->nPlayers;
}
} /* checkServerRole */
@ -388,19 +384,23 @@ gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGI )
} /* gi_copy */
XP_U16
gi_countLocalHumans( const CurGameInfo* gi )
gi_countLocalPlayers( const CurGameInfo* gi, XP_Bool humanOnly )
{
XP_U16 count = 0;
XP_U16 nPlayers = gi->nPlayers;
const LocalPlayer* lp = gi->players;
while ( nPlayers-- ) {
if ( lp->isLocal && !lp->isRobot ) {
++count;
if ( lp->isLocal ) {
if ( humanOnly && lp->isRobot ) {
// skip
} else {
++count;
}
}
++lp;
}
return count;
} /* gi_countLocalHumans */
} /* gi_countLocalPlayers */
void
gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )

View file

@ -110,7 +110,7 @@ void gi_disposePlayerInfo( MPFORMAL CurGameInfo* gi );
void gi_writeToStream( XWStreamCtxt* stream, const CurGameInfo* gi );
void gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi );
void gi_copy( MPFORMAL CurGameInfo* destGI, const CurGameInfo* srcGi );
XP_U16 gi_countLocalHumans( const CurGameInfo* gi );
XP_U16 gi_countLocalPlayers( const CurGameInfo* gi, XP_Bool humanOnly );
XP_Bool player_hasPasswd( LocalPlayer* player );
XP_Bool player_passwordMatches( LocalPlayer* player, XP_U8* buf, XP_U16 len );

View file

@ -197,6 +197,25 @@ logNewState( XW_State old, XW_State newst )
/*****************************************************************************
*
****************************************************************************/
#ifndef XWFEATURE_STANDALONE_ONLY
static void
syncPlayers( ServerCtxt* server )
{
XP_U16 ii;
CurGameInfo* gi = server->vol.gi;
LocalPlayer* lp = gi->players;
ServerPlayer* player = server->players;
for ( ii = 0; ii < gi->nPlayers; ++ii, ++lp, ++player ) {
if ( !lp->isLocal/* && !lp->name */ ) {
++server->nv.pendingRegistrations;
}
player->deviceIndex = lp->isLocal? SERVER_DEVICE : UNKNOWN_DEVICE;
}
}
#else
# define syncPlayers( server )
#endif
static void
initServer( ServerCtxt* server )
{
@ -211,20 +230,7 @@ initServer( ServerCtxt* server )
SETSTATE( server, XWSTATE_BEGIN );
}
#ifndef XWFEATURE_STANDALONE_ONLY
{
XP_U16 ii;
CurGameInfo* gi = server->vol.gi;
LocalPlayer* lp = gi->players;
ServerPlayer* player = server->players;
for ( ii = 0; ii < gi->nPlayers; ++ii, ++lp, ++player ) {
if ( !lp->isLocal/* && !lp->name */ ) {
++server->nv.pendingRegistrations;
}
player->deviceIndex = lp->isLocal? SERVER_DEVICE : UNKNOWN_DEVICE;
}
}
#endif
syncPlayers( server );
server->nv.nDevices = 1; /* local device (0) is always there */
} /* initServer */
@ -467,11 +473,12 @@ server_countTilesInPool( ServerCtxt* server )
void
server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
{
LOG_FUNC();
CurGameInfo* gi = server->vol.gi;
XP_U16 nPlayers;
LocalPlayer* lp;
#ifdef DEBUG
XP_U16 i = 0;
XP_U16 ii = 0;
#endif
XP_ASSERT( gi->serverRole == SERVER_ISCLIENT );
@ -483,13 +490,17 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
nPlayers = gi->nPlayers;
XP_ASSERT( nPlayers > 0 );
stream_putBits( stream, NPLAYERS_NBITS, nPlayers );
stream_putBits( stream, NPLAYERS_NBITS,
gi_countLocalPlayers( gi, XP_FALSE) );
for ( lp = gi->players; nPlayers-- > 0; ++lp ) {
XP_UCHAR* name;
XP_U8 len;
XP_ASSERT( i++ < MAX_NUM_PLAYERS );
XP_ASSERT( ii++ < MAX_NUM_PLAYERS );
if ( !lp->isLocal ) {
continue;
}
stream_putBits( stream, 1, lp->isRobot ); /* better not to send this */
@ -1030,11 +1041,11 @@ sortTilesIf( ServerCtxt* server, XP_S16 turn )
}
}
#ifndef XWFEATURE_STANDALONE_ONLY
/* Called in response to message from server listing all the names of
* players in the game (in server-assigned order) and their initial
* tray contents.
*/
#ifndef XWFEATURE_STANDALONE_ONLY
static XP_Bool
client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream )
{
@ -1131,6 +1142,8 @@ client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream )
sortTilesIf( server, i );
}
syncPlayers( server );
SETSTATE( server, XWSTATE_INTURN );
/* Give board a chance to redraw self with the full compliment of known

View file

@ -160,6 +160,7 @@ typedef struct UtilVtable {
#ifndef XWFEATURE_STANDALONE_ONLY
void (*m_util_addrChange)( XW_UtilCtxt* uc, const CommsAddrRec* oldAddr,
const CommsAddrRec* newAddr );
void (*m_util_setIsServer)(XW_UtilCtxt* uc, XP_Bool isServer );
#endif
#ifdef XWFEATURE_SEARCHLIMIT
@ -255,6 +256,8 @@ struct XW_UtilCtxt {
#ifndef XWFEATURE_STANDALONE_ONLY
# define util_addrChange( uc, addro, addrn ) \
(uc)->vtable->m_util_addrChange((uc), (addro), (addrn))
# define util_setIsServer( uc, is ) \
(uc)->vtable->m_util_setIsServer((uc), (is))
# else
# define util_addrChange( uc, addro, addrn )
#endif

View file

@ -639,6 +639,16 @@ linux_util_addrChange( XW_UtilCtxt* uc,
#endif
}
}
static void
linux_util_setIsServer( XW_UtilCtxt* uc, XP_Bool isServer )
{
XP_LOGF( "%s(%d)", __func__, isServer );
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
DeviceRole newRole = isServer? SERVER_ISSERVER : SERVER_ISCLIENT;
cGlobals->params->serverRole = newRole;
cGlobals->params->gi.serverRole = newRole;
}
#endif
static unsigned int
@ -1045,12 +1055,17 @@ main( int argc, char** argv )
mainParams.needsNewGame = XP_TRUE;
}
if ( !isServer ) {
if ( mainParams.info.serverInfo.nRemotePlayers > 0 ) {
mainParams.needsNewGame = XP_TRUE;
}
if ( 0 < mainParams.info.serverInfo.nRemotePlayers
&& SERVER_STANDALONE == mainParams.gi.serverRole ) {
mainParams.needsNewGame = XP_TRUE;
}
/* if ( !isServer ) { */
/* if ( mainParams.info.serverInfo.nRemotePlayers > 0 ) { */
/* mainParams.needsNewGame = XP_TRUE; */
/* } */
/* } */
if ( 0 ) {
#ifdef XWFEATURE_RELAY
} else if ( conType == COMMS_CONN_RELAY ) {
@ -1118,6 +1133,7 @@ main( int argc, char** argv )
#ifndef XWFEATURE_STANDALONE_ONLY
mainParams.util->vtable->m_util_addrChange = linux_util_addrChange;
mainParams.util->vtable->m_util_setIsServer = linux_util_setIsServer;
#endif
srandom( seed ); /* init linux random number generator */

View file

@ -184,19 +184,15 @@ CookieRef::Unlock() {
}
bool
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersS,
int seed )
CookieRef::_Connect( int socket, int nPlayersH, int nPlayersS, int seed )
{
bool connected = false;
if ( hostAlreadyHere( seed, socket ) ) {
if ( AlreadyHere( seed, socket ) ) {
connected = true; /* but drop the packet */
/* } else if ( AlreadyHere( seed, -1 ) ) { */
/* dupe packet on different socket; need host record */
} else if ( CRefMgr::Get()->Associate( socket, this ) ) {
if ( hid == HOST_ID_NONE ) {
logf( XW_LOGINFO, "%s: Waiting to assign host id", __func__ );
} else {
logf( XW_LOGINFO, "NOT assigned host id; why?" );
}
pushConnectEvent( socket, hid, nPlayersH, nPlayersS, seed );
pushConnectEvent( socket, nPlayersH, nPlayersS, seed );
handleEvents();
connected = HasSocket_locked( socket );
} else {
@ -209,7 +205,7 @@ void
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersS,
int seed )
{
if ( !hostAlreadyHere( seed, socket ) ) {
if ( !AlreadyHere( seed, socket ) ) {
(void)CRefMgr::Get()->Associate( socket, this );
pushReconnectEvent( socket, hid, nPlayersH, nPlayersS, seed );
handleEvents();
@ -270,19 +266,16 @@ CookieRef::NeverFullyConnected()
}
bool
CookieRef::GameOpen( const char* cookie, bool isNew,
bool* alreadyHere )
CookieRef::GameOpen( const char* cookie )
{
bool accept = false;
*alreadyHere = false;
/* First, do we have room. Second, are we missing this guy? */
if ( isNew && m_gameFull ) {
if ( m_gameFull ) {
/* do nothing; reject */
logf( XW_LOGINFO, "reject: game for %s is full", cookie );
} else if ( m_curState != XWS_INITED
&& m_curState != XWS_WAITGUESTS
&& m_curState != XWS_MISSING ) {
&& m_curState != XWS_WAITMORE ) {
/* do nothing; reject */
logf( XW_LOGINFO, "reject: bad state %s", stateString(m_curState) );
} else {
@ -299,6 +292,31 @@ CookieRef::GameOpen( const char* cookie, bool isNew,
return accept;
} /* GameOpen */
bool
CookieRef::AlreadyHere( unsigned short seed, int socket )
{
bool here = false;
vector<unsigned short>::iterator iter;
for ( iter = m_seeds.begin(); !here && iter != m_seeds.end(); ++iter ) {
here = *iter == seed;
}
if ( !here && socket != -1 ) {
vector<HostRec>::const_iterator iter;
for ( iter = m_sockets.begin(); !here && iter != m_sockets.end();
++iter ) {
if ( iter->m_socket == socket ) {
/* NFW should the socket be here but seed not match */
assert( seed != iter->m_seed );
here = true;
}
}
}
logf( XW_LOGINFO, "%s=>%d", __func__, here );
return here;
}
void
CookieRef::notifyDisconn( const CRefEvent* evt )
{
@ -365,6 +383,7 @@ CookieRef::HasSocket_locked( int socket )
}
}
logf( XW_LOGINFO, "%s=>%d", __func__, found );
return found;
} /* HasSocket_locked */
@ -407,14 +426,13 @@ CookieRef::_Remove( int socket )
} /* Forward */
void
CookieRef::pushConnectEvent( int socket, HostID srcID,
int nPlayersH, int nPlayersS,
CookieRef::pushConnectEvent( int socket, int nPlayersH, int nPlayersS,
int seed )
{
CRefEvent evt;
evt.type = nPlayersS == 0? XWE_GUESTCONNECT : XWE_HOSTCONNECT;
evt.type = XWE_DEVCONNECT;
evt.u.con.socket = socket;
evt.u.con.srcID = srcID;
evt.u.con.srcID = nextHostID();
evt.u.con.nPlayersH = nPlayersH;
evt.u.con.nPlayersS = nPlayersS;
evt.u.con.seed = seed;
@ -532,20 +550,29 @@ CookieRef::handleEvents()
checkHaveRoom( &evt );
break;
case XWA_SEND_HOST_RSP:
case XWA_SEND_GUEST_RSP:
case XWA_SEND_1ST_RERSP:
case XWA_SEND_INITRSP:
setAllConnectedTimer();
sendResponse( &evt, true );
break;
case XWA_SEND_CONNRSP:
if ( increasePlayerCounts( &evt, false ) ) {
setAllConnectedTimer();
sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP );
postCheckAllHere();
}
break;
/* case XWA_SEND_1ST_RERSP: */
/* if ( increasePlayerCounts( &evt, false ) ) { */
/* setAllConnectedTimer(); */
/* sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP ); */
/* } */
/* break; */
case XWA_SEND_RERSP:
if ( increasePlayerCounts( &evt, true ) ) {
sendResponse( &evt, false );
sendAnyStored( &evt );
}
sendResponse( &evt, false );
sendAnyStored( &evt );
// postCheckAllHere();
break;
case XWA_SEND_NO_ROOM:
@ -576,14 +603,14 @@ CookieRef::handleEvents()
notifyOthers( evt.u.heart.socket, XWRELAY_DISCONNECT_OTHER,
XWRELAY_ERROR_HEART_OTHER );
setAllConnectedTimer();
reducePlayerCounts( evt.u.discon.socket );
// reducePlayerCounts( evt.u.discon.socket );
disconnectSockets( evt.u.heart.socket,
XWRELAY_ERROR_HEART_YOU );
break;
case XWA_DISCONNECT:
setAllConnectedTimer();
reducePlayerCounts( evt.u.discon.socket );
// reducePlayerCounts( evt.u.discon.socket );
notifyOthers( evt.u.discon.socket, XWRELAY_DISCONNECT_OTHER,
XWRELAY_ERROR_OTHER_DISCON );
removeSocket( evt.u.discon.socket );
@ -602,7 +629,7 @@ CookieRef::handleEvents()
setAllConnectedTimer();
/* fallthru */
case XWA_REMOVESOCK_1:
reducePlayerCounts( evt.u.rmsock.socket );
// reducePlayerCounts( evt.u.rmsock.socket );
if ( XWA_REMOVESOCK_2 == takeAction ) {
notifyOthers( evt.u.rmsock.socket, XWRELAY_DISCONNECT_OTHER,
XWRELAY_ERROR_LOST_OTHER );
@ -613,9 +640,8 @@ CookieRef::handleEvents()
case XWA_SENDALLHERE:
CRefMgr::Get()->IncrementFullCount();
cancelAllConnectedTimer();
assignHostIds();
assignConnName();
sendAllHere( true );
checkSomeMissing();
break;
case XWA_SNDALLHERE_2:
@ -623,13 +649,21 @@ CookieRef::handleEvents()
break;
case XWA_NOTE_EMPTY:
cancelAllConnectedTimer();
//cancelAllConnectedTimer();
if ( 0 == count_msgs_stored() ) {
CRefEvent evt( XWE_NOMOREMSGS );
m_eventQueue.push_back( evt );
}
break;
case XWA_INITGAME: {
initPlayerCounts( &evt );
CRefEvent initedevt( XWE_INITTEDGAME );
initedevt.u.con = evt.u.con;
m_eventQueue.push_back( initedevt );
}
break;
case XWA_NONE:
/* nothing to do for these */
break;
@ -641,12 +675,12 @@ CookieRef::handleEvents()
m_curState = nextState;
} else {
CRefEvent shutevt( XWE_SHUTDOWN );
m_eventQueue.push_back( shutevt );
logf( XW_LOGERROR, "Killing cref b/c unable to find transition "
"from %s on event %s", stateString(m_curState),
eventString(evt.type) );
assert(0);
CRefEvent shutevt( XWE_SHUTDOWN );
m_eventQueue.push_back( shutevt );
}
}
m_in_handleEvents = false;
@ -722,21 +756,37 @@ CookieRef::send_stored_messages( HostID dest, int socket )
}
} /* send_stored_messages */
void
CookieRef::initPlayerCounts( const CRefEvent* evt )
{
assert( evt->type == XWE_DEVCONNECT );
assert( m_nPlayersSought == 0 && m_nPlayersHere == 0 );
m_nPlayersSought = evt->u.con.nPlayersS;
m_nPlayersHere = evt->u.con.nPlayersH;
HostRec hr( evt->u.con.srcID, evt->u.con.socket, evt->u.con.nPlayersH,
evt->u.con.nPlayersS, evt->u.con.seed );
m_sockets.push_back( hr );
assert( !AlreadyHere( evt->u.con.seed, -1 ) );
m_seeds.push_back( evt->u.con.seed );
}
bool
CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
{
int nPlayersH = evt->u.con.nPlayersH;
int nPlayersS = evt->u.con.nPlayersS;
assert( nPlayersS > 0 ); /* catch earlier; assert here */
int socket = evt->u.con.socket;
HostID hid = evt->u.con.srcID;
int seed = evt->u.con.seed;
bool addHost = false;
XW_RELAY_EVENT newEvt = XWE_NONE;
/* XW_RELAY_EVENT newEvt = XWE_NONE; */
assert( hid <= 4 );
assert( m_nPlayersSought > 0 );
logf( XW_LOGINFO, "%s: hid=%d, nPlayersH=%d, "
"nPlayersS=%d", __func__, hid, nPlayersH, nPlayersS );
logf( XW_LOGINFO, "%s: nPlayersH=%d, "
"nPlayersS=%d", __func__, nPlayersH, nPlayersS );
ASSERT_LOCKED();
@ -768,77 +818,100 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
}
m_nPlayersHere += nPlayersH;
if ( m_nPlayersHere == m_nPlayersSought ) {
newEvt = XWE_ALLHERE;
} else {
newEvt = XWE_SOMEMISSING;
}
/* if ( m_nPlayersHere == m_nPlayersSought ) { */
/* newEvt = XWE_ALLHERE; */
/* } else { */
/* newEvt = XWE_SOMEMISSING; */
/* } */
addHost = true;
} else if ( nPlayersS > 0 ) { /* a host; init values */
if ( m_nPlayersSought != 0 || m_nPlayersHere != 0 ) {
logf( XW_LOGERROR, "cref in bad state: m_nPlayersSought: %d; "
"m_nPlayersHere: %d", m_nPlayersSought, m_nPlayersHere );
goto drop;
}
m_nPlayersHere = nPlayersH;
m_nPlayersSought = nPlayersS;
} else { /* a host; init values */
assert( m_nPlayersSought == nPlayersS );
m_nPlayersHere += nPlayersH;
assert( m_nPlayersHere <= m_nPlayersSought );
addHost = true;
} else { /* a guest */
assert( reconn || m_nPlayersSought != 0 ); /* host better be here */
if ( m_nPlayersSought < m_nPlayersHere + nPlayersH ) { /* too many;
reject */
newEvt = XWE_TOO_MANY;
} else {
m_nPlayersHere += nPlayersH;
if ( m_nPlayersHere == m_nPlayersSought ) { /* complete! */
newEvt = XWE_ALLHERE;
m_gameFull = true;
} else {
newEvt = XWE_SOMEMISSING;
}
addHost = true;
}
/* if ( m_nPlayersHere == m_nPlayersSought ) { /\* complete! *\/ */
/* newEvt = XWE_ALLHERE; */
/* } else { */
/* newEvt = XWE_SOMEMISSING; */
/* } */
/* } else { /\* a guest *\/ */
/* assert( reconn || m_nPlayersSought != 0 ); /\* host better be here *\/ */
/* if ( m_nPlayersSought < m_nPlayersHere + nPlayersH ) { /\* too many; */
/* reject *\/ */
/* newEvt = XWE_TOO_MANY; */
/* } else { */
/* m_nPlayersHere += nPlayersH; */
/* if ( m_nPlayersHere == m_nPlayersSought ) { /\* complete! *\/ */
/* newEvt = XWE_ALLHERE; */
/* m_gameFull = true; */
/* } else { */
/* newEvt = XWE_SOMEMISSING; */
/* } */
/* addHost = true; */
/* } */
}
if ( newEvt != XWE_NONE ) {
CRefEvent evt( newEvt );
m_eventQueue.push_back( evt );
} else {
logf( XW_LOGERROR, "%s: not pushing an event", __func__ );
}
/* if ( newEvt != XWE_NONE ) { */
/* CRefEvent evt( newEvt ); */
/* m_eventQueue.push_back( evt ); */
/* } else { */
/* logf( XW_LOGERROR, "%s: not pushing an event", __func__ ); */
/* } */
if ( addHost ) {
HostID hostid = evt->u.con.srcID;
/* first add the rec here, whether it'll stay for not */
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, "
"socket=%d (size=%d)",
__func__, hid, socket, m_sockets.size());
__func__, hostid, socket, m_sockets.size());
HostRec hr( hid, socket, nPlayersH, nPlayersS, seed );
HostRec hr( hostid, socket, nPlayersH, nPlayersS, seed );
m_sockets.push_back( hr );
assert( !AlreadyHere( evt->u.con.seed, -1 ) );
m_seeds.push_back( evt->u.con.seed );
logf( XW_LOGVERBOSE1, "%s: here=%d; total=%d", __func__,
m_nPlayersHere, m_nPlayersSought );
} else {
assert( 0 );
}
drop:
return addHost;
} /* increasePlayerCounts */
bool
CookieRef::hostAlreadyHere( int seed, int socket )
void
CookieRef::postCheckAllHere()
{
ASSERT_LOCKED();
bool found = false;
vector<HostRec>::const_iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_seed == seed && iter->m_socket == socket ) {
found = true;
break;
}
XW_RELAY_EVENT newEvt;
if ( m_nPlayersHere == m_nPlayersSought ) { /* complete! */
m_gameFull = true;
newEvt = XWE_ALLHERE;
} else {
newEvt = XWE_SOMEMISSING;
}
return found;
CRefEvent evt( newEvt );
m_eventQueue.push_back( evt );
}
/* bool */
/* CookieRef::socketAlreadyHere( int socket ) */
/* { */
/* ASSERT_LOCKED(); */
/* bool found = false; */
/* vector<HostRec>::const_iterator iter; */
/* for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { */
/* if ( iter->m_seed == seed && iter->m_socket == socket ) { */
/* found = true; */
/* break; */
/* } */
/* } */
/* return found; */
/* } */
void
CookieRef::reducePlayerCounts( int socket )
{
@ -847,11 +920,6 @@ CookieRef::reducePlayerCounts( int socket )
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_socket == socket ) {
if ( iter->m_hostID == HOST_ID_SERVER ) {
m_nPlayersSought -= iter->m_nPlayersS;
} else {
assert( iter->m_nPlayersS == 0 );
}
m_nPlayersHere -= iter->m_nPlayersH;
logf( XW_LOGVERBOSE1,
@ -886,18 +954,29 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial )
/* Now send the response */
unsigned char buf[1 /* cmd */
+ sizeof(unsigned char) /* hostID */
+ sizeof(short) /* heartbeat */
+ sizeof(short) /* total here */
+ sizeof(short) /* total expected */
+ sizeof(unsigned char) /* total here */
+ sizeof(unsigned char) /* total expected */
+ 1 + MAX_CONNNAME_LEN
];
unsigned char* bufp = buf;
*bufp++ = initial ? XWRELAY_CONNECT_RESP : XWRELAY_RECONNECT_RESP;
*bufp++ = evt->u.con.srcID;
putNetShort( &bufp, GetHeartbeat() );
*bufp++ = GetPlayersSought();
*bufp++ = GetPlayersHere();
const char* connName = ConnName();
assert( !!connName && connName[0] );
int len = strlen( connName );
assert( len < MAX_CONNNAME_LEN );
*bufp++ = (char)len;
memcpy( bufp, connName, len );
bufp += len;
send_with_length( socket, buf, bufp - buf, true );
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
} /* sendResponse */
@ -1034,29 +1113,29 @@ CookieRef::sendAllHere( bool initial )
} /* sendAllHere */
void
CookieRef::assignHostIds( void )
CookieRef::checkSomeMissing( void )
{
ASSERT_LOCKED();
HostID nextId = HOST_ID_SERVER;
unsigned int bits = 0;
logf( XW_LOGINFO, "%s", __func__ );
int count = 0;
int nPlayersS;
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_hostID != HOST_ID_NONE ) {
bits |= 1 << iter->m_hostID;
count += iter->m_nPlayersH;
if ( iter != m_sockets.begin() ) {
assert( iter->m_nPlayersS == nPlayersS );
} else {
nPlayersS = iter->m_nPlayersS;
}
}
assert( (bits & (1 << HOST_ID_SERVER)) != 0 );
logf( XW_LOGINFO, "%s; count=%d; nPlayersS=%d", __func__,
count, nPlayersS );
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_hostID == HOST_ID_NONE ) {
while ( ((1 << nextId) & bits) != 0 ) {
++nextId;
}
iter->m_hostID = nextId++; /* ++: don't reuse */
}
assert( count <= nPlayersS );
if ( count < nPlayersS ) {
CRefEvent evt( XWE_SOMEMISSING );
m_eventQueue.push_back( evt );
}
}
@ -1111,14 +1190,14 @@ CookieRef::assignConnName( void )
{
if ( '\0' == ConnName()[0] ) {
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
char buf[5];
snprintf( buf, sizeof(buf), "%.4X", iter->m_seed );
m_connName += buf;
}
/* vector<HostRec>::iterator iter; */
/* for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) { */
/* char buf[5]; */
/* snprintf( buf, sizeof(buf), "%.4X", iter->m_seed ); */
/* m_connName += buf; */
/* } */
m_connName += CONNNAME_DELIM + PermID::GetNextUniqueID();
m_connName += /*CONNNAME_DELIM + */PermID::GetNextUniqueID();
logf( XW_LOGINFO, "%s: assigning name: %s", __func__, ConnName() );
} else {

View file

@ -41,14 +41,16 @@ class CookieMapIterator; /* forward */
struct HostRec {
public:
HostRec(HostID hostID, int socket, int nPlayersH, int nPlayersS,
int seed )
int seed )
: m_hostID(hostID)
, m_socket(socket)
, m_nPlayersH(nPlayersH)
, m_nPlayersS(nPlayersS)
, m_seed(seed)
, m_lastHeartbeat(uptime())
{}
{
::logf( XW_LOGINFO, "created HostRec with id %d", m_hostID);
}
HostID m_hostID;
int m_socket;
int m_nPlayersH;
@ -92,7 +94,8 @@ class CookieRef {
int SocketForHost( HostID dest );
bool NeverFullyConnected();
bool GameOpen( const char* cookie, bool isNew, bool* alreadyHere );
bool AlreadyHere( unsigned short seed, int socket );
bool GameOpen( const char* cookie );
/* for console */
void _PrintCookieInfo( string& out );
@ -105,8 +108,7 @@ class CookieRef {
static void Delete( CookieID id );
static void Delete( const char* name );
bool _Connect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed );
bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed );
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed );
void _Disconnect(int socket, HostID hostID );
@ -171,8 +173,7 @@ class CookieRef {
m_totalSent += nBytes;
}
void pushConnectEvent( int socket, HostID srcID,
int nPlayersH, int nPlayersS,
void pushConnectEvent( int socket, int nPlayersH, int nPlayersS,
int seed );
void pushReconnectEvent( int socket, HostID srcID,
int nPlayersH, int nPlayersS,
@ -192,7 +193,9 @@ class CookieRef {
void sendResponse( const CRefEvent* evt, bool initial );
void sendAnyStored( const CRefEvent* evt );
void initPlayerCounts( const CRefEvent* evt );
bool increasePlayerCounts( const CRefEvent* evt, bool reconn );
void postCheckAllHere();
bool hostAlreadyHere( int seed, int socket );
void reducePlayerCounts( int socket );
@ -211,13 +214,15 @@ class CookieRef {
void notifyDisconn(const CRefEvent* evt);
void removeSocket( int socket );
void sendAllHere( bool initial );
void checkSomeMissing( void );
void moveSockets( void );
bool SeedBelongs( int gameSeed );
bool SeedsBelong( const char* connName );
void assignConnName( void );
void assignHostIds( void );
HostID nextHostID() { return ++m_nextHostID; }
HostID nextHostID() { return m_nextHostID++; }
time_t GetStarttime( void ) { return m_starttime; }
@ -263,6 +268,7 @@ class CookieRef {
bool m_in_handleEvents; /* for debugging only */
int m_delayMicros;
vector<unsigned short> m_seeds;
}; /* CookieRef */
#endif

View file

@ -136,67 +136,57 @@ CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
socket, nPlayersH, nPlayersT );
CookieRef* found = NULL;
if ( !!cookie || !!connName ) { /* drop if both are null */
assert( !!cookie || !!connName );
RWReadLock rwl( &m_cookieMapRWLock );
RWReadLock rwl( &m_cookieMapRWLock );
CookieMap::iterator iter;
for ( iter = m_cookieMap.begin();
NULL == found && iter != m_cookieMap.end();
++iter ) {
CookieRef* cref = iter->second;
CookieMap::iterator iter;
for ( iter = m_cookieMap.begin();
NULL == found && iter != m_cookieMap.end();
++iter ) {
CookieRef* cref = iter->second;
if ( !!connName && 0 == strcmp( cref->ConnName(), connName ) ) {
found = cref;
/* if ( cref->Lock() ) { */
/* assert( !cookie || */
/* 0 == strcasecmp( cookie, cref->Cookie() ) ); */
/* if ( cref->SeedBelongs( gameSeed ) ) { */
/* logf( XW_LOGINFO, "%s: SeedBelongs: dup packet?", */
/* __func__ ); */
/* *alreadyHere = true; */
/* found = cref; */
/* } else if ( cref->GameOpen( cookie, false, */
/* alreadyHere ) ) { */
/* found = cref; */
/* } else { */
/* /\* drop if we match on connName and it's not */
/* wanted; must be dup. *\/ */
/* *alreadyHere = true; */
/* } */
/* cref->Unlock(); */
/* } */
}
if ( !!connName ) {
if ( 0 == strcmp( cref->ConnName(), connName ) ) {
if ( cref->Lock() ) {
assert( !cookie ||
0 == strcasecmp( cookie, cref->Cookie() ) );
if ( cref->SeedBelongs( gameSeed ) ) {
logf( XW_LOGINFO, "%s: SeedBelongs: dup packet?",
__func__ );
*alreadyHere = true;
found = cref;
} else if ( cref->GameOpen( cookie, false,
alreadyHere ) ) {
found = cref;
} else {
/* drop if we match on connName and it's not
wanted; must be dup. */
*alreadyHere = true;
}
cref->Unlock();
}
}
}
if ( !found && !!cookie ) {
if ( 0 == strcasecmp( cref->Cookie(), cookie ) ) {
if ( cref->Lock() ) {
if ( cref->ConnName()[0] ) {
/* if has a connName, we can tell if belongs */
if ( cref->SeedBelongs( gameSeed ) ) {
found = cref;
}
} else if ( !!connName ) {
/* Or, if we have a connName and it doesn't,
perhaps we have its name. Does our name
contain its other members? */
if ( cref->SeedsBelong( connName ) ) {
found = cref;
}
} else if ( cref->GameOpen( cookie, true,
alreadyHere ) ) {
found = cref;
} else if ( cref->HasSocket_locked(socket) ) {
logf( XW_LOGINFO, "%s: HasSocket case", __func__);
found = cref;
}
cref->Unlock();
if ( !found && !!cookie ) {
if ( 0 == strcasecmp( cref->Cookie(), cookie ) ) {
if ( cref->Lock() ) {
assert( cref->ConnName()[0] );
if ( cref->AlreadyHere( gameSeed, -1 ) ) {
found = cref;
*alreadyHere = true;
} else if ( cref->GameOpen( cookie ) ) {
found = cref;
} else if ( cref->HasSocket_locked(socket) ) {
assert( 0 ); /* should have dumped the socket */
logf( XW_LOGINFO, "%s: HasSocket case", __func__);
found = cref;
}
cref->Unlock();
}
}
}
}
} /* for */
logf( XW_LOGINFO, "%s=>%p", __func__, found );
return found;
@ -520,6 +510,8 @@ CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id )
ref = new CookieRef( cookie, connName, id );
}
ref->assignConnName();
m_cookieMap.insert( pair<CookieID, CookieRef*>(ref->GetCookieID(), ref ) );
logf( XW_LOGINFO, "%s: paired cookie %s/connName %s with cid %d", __func__,
(cookie?cookie:"NULL"), connName, ref->GetCookieID() );
@ -665,8 +657,28 @@ CookieMapIterator::Next()
// SafeCref
//////////////////////////////////////////////////////////////////////////////
SafeCref::SafeCref( const char* cookie, const char* connName, HostID hid,
int socket, int nPlayersH, int nPlayersT,
/* connect case */
SafeCref::SafeCref( const char* cookie, int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed, int langCode, bool wantsPublic,
bool makePublic )
: m_cref( NULL )
, m_mgr( CRefMgr::Get() )
, m_isValid( false )
{
CookieRef* cref;
cref = m_mgr->getMakeCookieRef_locked( cookie, NULL, 0, socket,
nPlayersH, nPlayersS, gameSeed );
if ( cref != NULL ) {
m_locked = cref->Lock();
m_cref = cref;
m_isValid = true;
}
}
/* REconnect case */
SafeCref::SafeCref( const char* connName, HostID hid,
int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed )
: m_cref( NULL )
, m_mgr( CRefMgr::Get() )
@ -674,8 +686,8 @@ SafeCref::SafeCref( const char* cookie, const char* connName, HostID hid,
{
CookieRef* cref;
cref = m_mgr->getMakeCookieRef_locked( cookie, connName, hid, socket,
nPlayersH, nPlayersT, gameSeed );
cref = m_mgr->getMakeCookieRef_locked( NULL, connName, hid, socket, nPlayersH,
nPlayersS, gameSeed );
if ( cref != NULL ) {
m_locked = cref->Lock();
m_cref = cref;

View file

@ -177,7 +177,12 @@ class SafeCref {
CookieRef instance at a time. */
public:
SafeCref( const char* cookie, const char* connName, HostID hid,
/* for connect */
SafeCref( const char* cookie, int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed, int langCode, bool wantsPublic,
bool makePublic );
/* for reconnect */
SafeCref( const char* connName, HostID hid,
int socket, int nPlayersH, int nPlayersS,
unsigned short gameSeed );
SafeCref( CookieID cid, bool failOk = false );
@ -193,10 +198,9 @@ class SafeCref {
return false;
}
}
bool Connect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed ) {
bool Connect( int socket, int nPlayersH, int nPlayersS, int seed ) {
if ( IsValid() ) {
return m_cref->_Connect( socket, srcID, nPlayersH, nPlayersS, seed );
return m_cref->_Connect( socket, nPlayersH, nPlayersS, seed );
} else {
return false;
}

View file

@ -43,8 +43,7 @@ typedef struct StateTable {
New rules on accepting connections and reconnections:
- Connect and reconnect messages contain nPlayersHere (local) and
nPlayersTotal params.
- Connect messages contain nPlayersHere (local) and nPlayersTotal params.
- On connect action, we either note the total expected, or increase the
total we have. Ditto on reconnect. On disconnect, we take the departing
@ -63,59 +62,70 @@ typedef struct StateTable {
static StateTable g_stateTable[] = {
{ XWS_INITED, XWE_HOSTCONNECT, XWA_SEND_HOST_RSP, XWS_WAITGUESTS },
{ XWS_INITED, XWE_GUESTCONNECT, XWA_SEND_NO_ROOM, XWS_DEAD },
{ XWS_INITED, XWE_DEVCONNECT, XWA_INITGAME, XWS_INITINGGAME },
{ XWS_INITINGGAME, XWE_INITTEDGAME, XWA_SEND_INITRSP, XWS_WAITMORE },
{ XWS_WAITGUESTS, XWE_GUESTCONNECT, XWA_CHECK_HAVE_ROOM,XWS_ROOMCHK },
{ XWS_WAITMORE, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_CHK_ALLHERE },
{ XWS_WAITMORE, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND },
/* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */
/* { XWS_WAITMORE, XWE_CHECKFULL, XWA_, XWS_WAITMORE }, */
/* { XWS_INITED, XWE_DEVCONNECT, XWA_SEND_NO_ROOM, XWS_DEAD }, */
/* { XWS_WAITMORE, XWE_DEVCONNECT, XWA_CHECK_FULL, XWS_FULLCHK }, */
/* { XWS_FULLCHK, XWE_FULLCHK */
/* { XWS_ROOMCHK, XWE_HAVE_ROOM, XWA_SEND_GUEST_RSP, XWS_CHK_ALLHERE }, */
/* { XWS_ROOMCHK, XWE_TOO_MANY, XWA_SEND_TOO_MANY, XWS_WAITGUESTS }, */
{ XWS_ROOMCHK, XWE_HAVE_ROOM, XWA_SEND_GUEST_RSP, XWS_CHK_ALLHERE },
{ XWS_ROOMCHK, XWE_TOO_MANY, XWA_SEND_TOO_MANY, XWS_WAITGUESTS },
{ XWS_CHK_ALLHERE, XWE_ALLHERE, XWA_SENDALLHERE, XWS_ALLCONND },
{ XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITGUESTS },
{ XWS_WAITGUESTS, XWE_HOSTCONNECT, XWA_SEND_DUP_ROOM, XWS_WAITGUESTS },
{ XWS_ALLCONND, XWE_SOMEMISSING, XWA_NONE, XWS_MISSING },
{ XWS_CHK_ALLHERE, XWE_SOMEMISSING, XWA_NONE, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING },
{ XWS_WAITGUESTS, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITGUESTS },
{ XWS_WAITMORE, XWE_DISCONN, XWA_DISCONNECT, XWS_WAITMORE },
{ XWS_MISSING, XWE_DISCONN, XWA_DISCONNECT, XWS_MISSING },
/* EMPTY means have messages to send but no connections. Time out and free
memory after a while. BUT: don't I really want to keep these forever and
free the oldest ones if memory usage realy does become a problem.
There's no problem now! */
{ XWS_MISSING, XWE_NOMORESOCKETS, XWA_NOTE_EMPTY, XWS_MSGONLY },
{ XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD },
{ XWS_WAITMORE, XWE_NOMORESOCKETS, XWA_NONE, XWS_WAITMORE },
{ XWS_MISSING, XWE_NOMORESOCKETS, XWA_NONE, XWS_MISSING },
/* { XWS_MSGONLY, XWE_NOMOREMSGS, XWA_NONE, XWS_DEAD }, */
{ XWS_ANY, XWE_NOMORESOCKETS, XWA_NONE, XWS_DEAD },
{ XWS_ANY, XWE_SHUTDOWN, XWA_SHUTDOWN, XWS_DEAD },
{ XWS_INITED, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 },
{ XWS_MSGONLY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 },
{ XWS_INITED, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND },
/* { XWS_MSGONLY, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 }, */
{ XWS_MISSING, XWE_RECONNECT, XWA_SEND_RERSP, XWS_CHK_ALLHERE_2 },
{ XWS_CHK_ALLHERE_2, XWE_ALLHERE, XWA_SNDALLHERE_2, XWS_ALLCONND },
{ XWS_CHK_ALLHERE_2, XWE_SOMEMISSING, XWA_NONE, XWS_MISSING },
{ XWS_WAITGUESTS, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_WAITGUESTS },
{ XWS_WAITMORE, XWE_REMOVESOCKET, XWA_REMOVESOCK_1, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING },
{ XWS_MISSING, XWE_REMOVESOCKET, XWA_REMOVESOCK_2, XWS_MISSING },
#ifdef RELAY_HEARTBEAT
{ XWS_ALLCONND, XWE_HEARTFAILED, XWA_HEARTDISCONN, XWS_MISSING },
{ XWS_WAITGUESTS, XWE_HEARTFAILED, XWA_HEARTDISCONN, XWS_WAITGUESTS },
{ XWS_WAITMORE, XWE_HEARTFAILED, XWA_HEARTDISCONN, XWS_WAITMORE },
{ XWS_MISSING, XWE_HEARTFAILED, XWA_HEARTDISCONN, XWS_MISSING },
/* Heartbeat arrived */
{ XWS_WAITGUESTS, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_WAITGUESTS },
{ XWS_WAITMORE, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_ALLCONND },
{ XWS_MISSING, XWE_HEARTRCVD, XWA_NOTEHEART, XWS_MISSING },
#endif
/* Connect timer */
{ XWS_WAITGUESTS, XWE_CONNTIMER, XWA_TIMERDISCONN, XWS_DEAD },
{ XWS_WAITMORE, XWE_CONNTIMER, XWA_TIMERDISCONN, XWS_DEAD },
{ XWS_MISSING, XWE_CONNTIMER, XWA_NONE, XWS_MISSING },
{ XWS_ALLCONND, XWE_CONNTIMER, XWA_NONE, XWS_ALLCONND },
{ XWS_WAITGUESTS, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_WAITGUESTS },
{ XWS_WAITMORE, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING },
{ XWS_MISSING, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_MISSING },
{ XWS_DEAD, XWE_NOTIFYDISCON, XWA_NOTIFYDISCON, XWS_DEAD },
@ -161,16 +171,15 @@ stateString( XW_RELAY_STATE state )
CASESTR(XWS_NONE);
CASESTR(XWS_ANY);
CASESTR(XWS_INITED);
CASESTR(XWS_WAITGUESTS);
CASESTR(XWS_WAITMORE);
CASESTR(XWS_ALLCONND);
CASESTR(XWS_DEAD);
CASESTR(XWS_CHECKING_CONN);
CASESTR(XWS_MISSING);
CASESTR(XWS_MSGONLY);
CASESTR(XWS_CHK_ALLHERE);
CASESTR(XWS_CHK_ALLHERE_2);
CASESTR(XWS_CHKCOUNTS_INIT);
CASESTR(XWS_ROOMCHK);
CASESTR(XWS_INITINGGAME);
default:
assert(0);
}
@ -187,8 +196,7 @@ eventString( XW_RELAY_EVENT evt )
const char* str = NULL;
switch( evt ) {
CASESTR(XWE_NONE);
CASESTR(XWE_GUESTCONNECT);
CASESTR(XWE_HOSTCONNECT);
CASESTR(XWE_DEVCONNECT);
CASESTR(XWE_RECONNECT);
CASESTR(XWE_DISCONN);
CASESTR(XWE_FORWARDMSG);
@ -206,6 +214,7 @@ eventString( XW_RELAY_EVENT evt )
CASESTR(XWE_SOMEMISSING);
CASESTR(XWE_TOO_MANY);
CASESTR(XWE_HAVE_ROOM);
CASESTR(XWE_INITTEDGAME);
CASESTR(XWE_SHUTDOWN);
default:
@ -220,14 +229,13 @@ actString( XW_RELAY_ACTION act )
const char* str = NULL;
switch ( act ) {
CASESTR(XWA_NONE);
CASESTR(XWA_SEND_1ST_RERSP);
CASESTR(XWA_SEND_RERSP);
CASESTR(XWA_SENDALLHERE);
CASESTR(XWA_SEND_NO_ROOM);
CASESTR(XWA_SEND_TOO_MANY);
CASESTR(XWA_SEND_DUP_ROOM);
CASESTR(XWA_SEND_HOST_RSP);
CASESTR(XWA_SEND_GUEST_RSP);
CASESTR(XWA_SEND_INITRSP);
CASESTR(XWA_SEND_CONNRSP);
CASESTR(XWA_SNDALLHERE_2);
CASESTR(XWA_FWD);
CASESTR(XWA_NOTEHEART);
@ -240,6 +248,7 @@ actString( XW_RELAY_ACTION act )
CASESTR(XWA_SHUTDOWN);
CASESTR(XWA_CHECK_HAVE_ROOM);
CASESTR(XWA_NOTE_EMPTY);
CASESTR(XWA_INITGAME);
default:
assert(0);
}

View file

@ -46,13 +46,10 @@ enum {
incoming connection is why the object was
created. */
,XWS_WAITGUESTS /* At least one device has connected, but no
,XWS_WAITMORE /* At least one device has connected, but no
packets have yet arrived to be
forwarded. */
,XWS_CHECKING_CONN /* While we're still not fully connected a
message comes in */
,XWS_ALLCONND /* All devices are connected and ready for the
relay to do its work. This is the state
we're in most of the time. */
@ -61,12 +58,11 @@ enum {
somebody. Once [s]he's back we can be
fully connected again. */
,XWS_MSGONLY /* We have no connections but still messages to
send */
,XWS_ROOMCHK /* do we have room for as many players as are
being provided */
,XWS_INITINGGAME
,XWS_DEAD /* About to kill the object */
} XW_RELAY_STATE;
@ -80,9 +76,8 @@ typedef enum {
,XWE_HAVE_ROOM
,XWE_TOO_MANY
,XWE_GUESTCONNECT /* A device is connecting using the cookie for */
,XWE_HOSTCONNECT /* this object, as host or guest */
,XWE_DEVCONNECT /* A device is connecting using the cookie for */
/*,XWE_HOSTCONNECT*/ /* this object, as host or guest */
,XWE_RECONNECT /* A device is re-connecting using the connID for
this object */
@ -107,6 +102,8 @@ typedef enum {
hosts */
,XWE_SHUTDOWN /* shutdown this game */
,XWE_INITTEDGAME
,XWE_ANY /* wildcard; matches all */
} XW_RELAY_EVENT;
@ -120,8 +117,8 @@ typedef enum {
,XWA_SEND_DUP_ROOM /* host comes in while game open */
,XWA_SEND_NO_ROOM /* guest comes in when no game open */
,XWA_SEND_TOO_MANY
,XWA_SEND_GUEST_RSP
,XWA_SEND_HOST_RSP
,XWA_SEND_INITRSP /* response to first to connect */
,XWA_SEND_CONNRSP /* response to rest that connect */
,XWA_SEND_RERSP
@ -149,6 +146,8 @@ typedef enum {
,XWA_SHUTDOWN
,XWA_INITGAME
} XW_RELAY_ACTION;
bool getFromTable( XW_RELAY_STATE curState, XW_RELAY_EVENT curEvent,

View file

@ -305,27 +305,32 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
unsigned char flags = *bufp++;
XWREASON err = flagsOK( flags );
if ( err == XWRELAY_ERROR_NONE ) {
HostID srcID;
/* HostID srcID; */
unsigned char nPlayersH;
unsigned char nPlayersT;
unsigned short gameSeed;
unsigned char langCode;
unsigned char makePublic, wantsPublic;
if ( readStr( &bufp, end, cookie, sizeof(cookie) )
&& getNetByte( &bufp, end, &srcID )
&& getNetByte( &bufp, end, &wantsPublic )
&& getNetByte( &bufp, end, &makePublic )
/* && getNetByte( &bufp, end, &srcID ) */
&& getNetByte( &bufp, end, &nPlayersH )
&& getNetByte( &bufp, end, &nPlayersT )
&& getNetShort( &bufp, end, &gameSeed ) ) {
&& getNetShort( &bufp, end, &gameSeed )
&& getNetByte( &bufp, end, &langCode ) ) {
logf( XW_LOGINFO, "%s(): langCode=%d", __func__, langCode );
/* Make sure second thread can't create new cref for same cookie
this one just handled.*/
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
MutexLock ml( &s_newCookieLock );
SafeCref scr( cookie, NULL, srcID, socket, nPlayersH, nPlayersT,
gameSeed );
SafeCref scr( cookie, socket, nPlayersH, nPlayersT,
gameSeed, langCode, wantsPublic, makePublic );
/* nPlayersT etc could be slots in SafeCref to avoid passing
here */
success = scr.Connect( socket, srcID, nPlayersH, nPlayersT,
gameSeed );
success = scr.Connect( socket, nPlayersH, nPlayersT, gameSeed );
} else {
err = XWRELAY_ERROR_BADPROTO;
}
@ -351,25 +356,28 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
denyConnection( socket, err );
} else {
char cookie[MAX_INVITE_LEN+1];
char connName[MAX_CONNNAME_LEN+1];
char connName[MAX_CONNNAME_LEN+1] = {0};
HostID srcID;
unsigned char nPlayersH;
unsigned char nPlayersT;
unsigned short gameSeed;
unsigned char makePublic, wantsPublic;
unsigned char langCode;
connName[0] = '\0';
if ( readStr( &bufp, end, cookie, sizeof(cookie) )
&& getNetByte( &bufp, end, &wantsPublic )
&& getNetByte( &bufp, end, &makePublic )
&& getNetByte( &bufp, end, &srcID )
&& getNetByte( &bufp, end, &nPlayersH )
&& getNetByte( &bufp, end, &nPlayersT )
&& getNetShort( &bufp, end, &gameSeed )
&& getNetByte( &bufp, end, &langCode )
&& readStr( &bufp, end, connName, sizeof(connName) ) ) {
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
MutexLock ml( &s_newCookieLock );
SafeCref scr( cookie[0]? cookie : NULL,
connName[0]? connName : NULL,
SafeCref scr( connName[0]? connName : NULL,
srcID, socket, nPlayersH,
nPlayersT, gameSeed );
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT,
@ -473,9 +481,11 @@ processMessage( unsigned char* buf, int bufLen, int socket )
case XWRELAY_GAME_DISCONNECT:
success = processDisconnect( buf+1, bufLen-1, socket );
break;
#ifdef RELAY_HEARTBEAT
case XWRELAY_HEARTBEAT:
success = processHeartbeat( buf + 1, bufLen - 1, socket );
break;
#endif
case XWRELAY_MSG_TORELAY:
success = forwardMessage( buf, bufLen, socket );
break;
@ -486,7 +496,7 @@ processMessage( unsigned char* buf, int bufLen, int socket )
}
if ( !success ) {
killSocket( socket, "couldn't forward message" );
killSocket( socket, "failure" );
}
return success; /* caller defines non-0 as failure */
@ -1008,6 +1018,7 @@ main( int argc, char** argv )
}
#ifdef DO_HTTP
if ( FD_ISSET( g_http, &rfds ) ) {
FD_CLR( g_http, &rfds );
run_http_thread( &http_state );
--retval;
}

View file

@ -112,7 +112,8 @@ typedef unsigned char XWRELAY_Cmd;
#define XWRELAY_PROTO_VERSION_ORIG 0x01
#define XWRELAY_PROTO_VERSION_LATE_NAME 0x02
#define XWRELAY_PROTO_VERSION_LATE_COOKIEID 0x03
#define XWRELAY_PROTO_VERSION XWRELAY_PROTO_VERSION_LATE_COOKIEID
#define XWRELAY_PROTO_VERSION_NOCLIENT 0x04
#define XWRELAY_PROTO_VERSION XWRELAY_PROTO_VERSION_NOCLIENT
/* Errors passed with denied */
#ifndef CANT_DO_TYPEDEF