Make it possible for multiple games to connect using the same room

name.  All new connections are stored together, and after each
connection an attempt is made to build one complete game with a host
and however many guests.  All remaining devices are moved into a new
pending record in the same state, and the completed game is treated as
always.  Seems to work, though nearly 20% of linux instances are
failing to connect the relay run from the new test script samename.sh.
Need to figure out why.

Also added logging of seed and connname to comms.c since games
launched together can no longer be certain to connect on the relay.
This allows the test script to identify joined games from their logs
and detect success or failure.

This checkin changes the relay protocol, so relay and clients will
both need to be upgraded.
This commit is contained in:
ehouse 2009-11-02 01:01:47 +00:00
parent 11b586cd4b
commit 3bdfda6548
8 changed files with 334 additions and 65 deletions

View file

@ -820,6 +820,7 @@ getChannelSeed( CommsCtxt* comms )
{
while ( comms->channelSeed == 0 ) {
comms->channelSeed = XP_RANDOM();
XP_LOGF( "%s: channelSeed: %.4X", __func__, comms->channelSeed );
}
return comms->channelSeed;
}
@ -1082,6 +1083,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
XWHostID destID, srcID;
CookieID cookieID;
XP_U8 relayErr;
XP_U16 nHere, nSought;
/* nothing for us to do here if not using relay */
XWRELAY_Cmd cmd = stream_getU8( stream );
@ -1092,8 +1094,10 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
case XWRELAY_RECONNECT_RESP:
set_relay_state( comms, COMMS_RELAYSTATE_CONNECTED );
comms->r.heartbeat = stream_getU16( stream );
comms->r.cookieID = stream_getU16( stream );
XP_LOGF( "set cookieID = %d", comms->r.cookieID );
nHere = (XP_U16)stream_getU8( stream );
nSought = (XP_U16)stream_getU8( stream );
/* This may belong as an alert to user so knows has connected. */
XP_LOGF( "%s: have %d of %d players", __func__, nHere, nSought );
setHeartbeatTimer( comms );
break;
@ -1103,6 +1107,8 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|| comms->r.myHostID == srcID );
comms->r.myHostID = srcID;
XP_LOGF( "set hostid: %x", comms->r.myHostID );
comms->r.cookieID = stream_getU16( stream );
XP_LOGF( "set cookieID = %d", comms->r.cookieID );
#ifdef DEBUG
{
@ -1111,6 +1117,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
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,

View file

@ -265,14 +265,7 @@ CookieRef::GameOpen( const char* cookie, int nPlayersH, bool isNew,
/* do nothing; reject */
logf( XW_LOGINFO, "reject: bad state %s", stateString(m_curState) );
} else {
if ( m_nPlayersSought == 0 ) {
accept = true;
} else if ( nPlayersH + m_nPlayersHere <= m_nPlayersSought ) {
accept = true;
} else {
logf( XW_LOGINFO, "reject: m_nPlayersSought=%d, m_nPlayersHere=%d",
m_nPlayersSought, m_nPlayersHere );
}
accept = true;
}
/* Error to connect if cookie doesn't match. */
@ -570,7 +563,11 @@ CookieRef::handleEvents()
cancelAllConnectedTimer();
assignHostIds();
assignConnName();
sendAllHere( );
sendAllHere();
break;
case XWA_POSTCLONE:
moveSockets();
break;
case XWA_REJECT:
@ -579,7 +576,6 @@ CookieRef::handleEvents()
/* nothing to do for these */
break;
default:
assert(0);
break;
@ -615,31 +611,230 @@ putNetShort( unsigned char** bufpp, unsigned short s )
*bufpp += sizeof(s);
}
/* static bool */
/* hostRecComp( const HostRec& aa, const HostRec& bb ) */
/* { */
/* /\* first order, hosts go before guests; second order, by m_nPlayersHere *\/ */
/* /\* if ( aa.m_nPlayersS *\/ */
/* return aa.m_nPlayersH < bb.m_nPlayersH; */
/* } */
static void
print_sockets( const char* caller, vector<HostRec>& sockets )
{
logf( XW_LOGINFO, " %s from %s", __func__, caller );
vector<HostRec>::iterator iter;
for ( iter = sockets.begin(); iter != sockets.end(); ++iter ) {
logf( XW_LOGINFO, "isHost: %d; nPlayersH: %d; seed=%.4X; socket: %d",
iter->m_nPlayersS > 0, iter->m_nPlayersH, iter->m_seed,
iter->m_socket );
}
} /* print_sockets */
#define MAX_PER_SIZE 16 /* need to enforce this when connections arrive */
bool
CookieRef::tryMakeGame( vector<HostRec>& remaining )
{
assert( remaining.size() == 0 );
int nHosts = 0;
int nGuests;
bool complete = false;
unsigned int nRecords = m_sockets.size();
int ii;
/* m_sockets is sorted with hosts first, guests after, and within each in
descending order by number of players provided. Start by finding where
the host/guest break is. */
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_nPlayersS == 0 ) {
break;
}
++nHosts;
}
logf( XW_LOGINFO, "%s: there are %d hosts", __func__, nHosts );
nGuests = m_sockets.size() - nHosts;
int inUse[nGuests];
int nUsed;
/* Now for each host, try to give him a set of guests. Assumption:
there's no way we can find more than one complete game here since we
try after every host addition. The algorithm, which assumes guests are
sorted from most-players-provided down, is to try the largest numbers
first, skipping each that won't fit. If we fail, we try again starting
from the next host.
*/
int hostIndex;
for ( hostIndex = 0; hostIndex < nHosts; ++hostIndex ) {
unsigned int firstGuest;
for ( firstGuest = nHosts; firstGuest < nRecords; ++firstGuest ) {
int sought = m_sockets[hostIndex].m_nPlayersS - m_sockets[hostIndex].m_nPlayersH;
nUsed = 0;
for ( ii = (int)firstGuest; ii < (int)nRecords; ++ii ) {
int one = m_sockets[ii].m_nPlayersH;
if ( one <= sought ) { /* not too big? */
sought -= one;
inUse[nUsed++] = ii;
if ( sought == 0 ) {
complete = true;
goto loop_end;
}
}
}
}
}
loop_end:
/* If we have a full compliment of devices now, remove all the others into
remaining */
if ( complete ) {
int nRemaining = nRecords-nUsed-1; /* -1 for host */
int lastUsed = nUsed-1;
/* guest[s] first */
for ( ii = nRecords - 1; ii >= nHosts; --ii ) {
if ( ii == inUse[lastUsed] ) {
--lastUsed;
} else {
assert( nRemaining > 0 );
HostRec hr = m_sockets[ii];
m_nPlayersHere -= hr.m_nPlayersH;
assert( hr.m_nPlayersS == 0 );
remaining.insert( remaining.begin(), hr ); /* insert at start */
--nRemaining;
m_sockets.erase( m_sockets.begin() + ii );
}
}
/* now remove the host we chose */
for ( ii = nHosts - 1; ii >= 0; --ii ) {
if ( ii != hostIndex ) {
assert( nRemaining > 0 );
HostRec hr = m_sockets[ii];
m_nPlayersHere -= hr.m_nPlayersH;
m_nPlayersSought -= hr.m_nPlayersS;
remaining.insert( remaining.begin(), hr ); /* insert at start */
--nRemaining;
m_sockets.erase( m_sockets.begin() + ii );
}
}
assert( 0 == nRemaining );
}
print_sockets( __func__, m_sockets );
print_sockets( __func__, remaining );
assert( remaining.size() + m_sockets.size() == nRecords );
logf( XW_LOGINFO, "%s => %d", __func__, complete );
return complete;
} /* tryMakeGame */
/* Maintain order first by whether is host or not, and then by number of
players provided */
void
CookieRef::insertSorted( HostRec hr )
{
bool newIsHost = hr.m_nPlayersS > 0;
int newPlayersH = hr.m_nPlayersH;
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
bool curIsHost = iter->m_nPlayersS > 0;
bool belongsBySort = newPlayersH <= iter->m_nPlayersH;
/* We're done when we're inserting a host and have found a guest; or
when we're in the right region (host or guest) and the secondary
sort says do-it.*/
if ( newIsHost && !curIsHost ) {
break;
} else if ( (newIsHost == curIsHost) && belongsBySort ) {
break;
}
}
m_sockets.insert( iter, hr );
logf( XW_LOGINFO, "m_sockets.size() now %d", m_sockets.size() );
print_sockets( __func__, m_sockets );
m_nPlayersHere += hr.m_nPlayersH;
m_nPlayersSought += hr.m_nPlayersS;
} /* insertSorted */
void
CookieRef::populate( vector<HostRec> hosts )
{
/* copy enough state that it can live on own */
m_sockets = hosts;
m_curState = XWS_CLONED;
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
m_nPlayersSought += iter->m_nPlayersS;
m_nPlayersHere += iter->m_nPlayersH;
}
print_sockets( __func__, m_sockets );
}
void
CookieRef::increasePlayerCounts( const CRefEvent* evt )
{
int nPlayersH = evt->u.con.nPlayersH;
int nPlayersS = evt->u.con.nPlayersS;
int socket = evt->u.con.socket;
HostID hid = evt->u.con.srcID;
int seed = evt->u.con.seed;
assert( hid <= 4 );
logf( XW_LOGINFO, "%s: hid=%d, nPlayersH=%d, ", __func__,
"nPlayersS=%d", hid, nPlayersH, nPlayersS );
logf( XW_LOGINFO, "%s: hid=%d, nPlayersH=%d, "
"nPlayersS=%d", __func__, hid, nPlayersH, nPlayersS );
if ( hid == HOST_ID_SERVER ) {
assert( m_nPlayersSought == 0 );
m_nPlayersSought = nPlayersS;
} else {
assert( nPlayersS == 0 ); /* should catch this earlier!!! */
assert( m_nPlayersSought == 0 || m_nPlayersHere <= m_nPlayersSought );
/* Up to this point we should just be adding host records to this cref.
Maybe even including multiple hosts. Now we go through what we have
and try to build a game. sendResponse() is where new hostrecs are
actually added. That seems broken! */
ASSERT_LOCKED();
/* 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());
HostRec hr( hid, socket, nPlayersH, nPlayersS, seed );
insertSorted( hr );
vector<HostRec> remaining;
bool gameComplete = tryMakeGame( remaining );
/* If we built a game but had leftover HostRecs, they're now in remaining.
Build a new cref for them, and process its first event now. It'll then
be ready to receive new messages, e.g. new connections. */
if ( remaining.size() > 0 ) {
CookieRef* clone = CRefMgr::Get()->Clone( this );
assert( !!clone );
clone->Lock();
clone->populate( remaining );
assert( clone->m_eventQueue.size() == 0 );
CRefEvent evt;
evt.type = XWE_CLONECHKMSG;
clone->m_eventQueue.push_back( evt );
clone->handleEvents();
clone->Unlock();
}
m_nPlayersHere += nPlayersH;
logf( XW_LOGVERBOSE1, "%s: here=%d; total=%d", __func__,
m_nPlayersHere, m_nPlayersSought );
CRefEvent newevt;
if ( m_nPlayersHere == m_nPlayersSought ) {
if ( gameComplete ) {
newevt.type = XWE_ALLHERE;
m_gameFull = true;
} else {
@ -657,7 +852,7 @@ CookieRef::reducePlayerCounts( int socket )
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
if ( iter->m_socket == socket ) {
if ( iter->m_hostID == HOST_ID_SERVER ) {
m_nPlayersSought = 0;
m_nPlayersSought -= iter->m_nPlayersS;
} else {
assert( iter->m_nPlayersS == 0 );
}
@ -677,12 +872,16 @@ void
CookieRef::checkCounts( const CRefEvent* evt )
{
int nPlayersH = evt->u.con.nPlayersH;
int nPlayersS = evt->u.con.nPlayersS;
HostID hid = evt->u.con.srcID;
bool success;
logf( XW_LOGVERBOSE1, "checkCounts: hid=%d, nPlayers=%d, m_nPlayersSought = %d, "
"m_nPlayersHere = %d",
hid, nPlayersH, m_nPlayersSought, m_nPlayersHere );
logf( XW_LOGVERBOSE1, "%s: hid:%d; nPlayersS:%d; nPlayersH:%d; "
"m_nPlayersSought:%d; m_nPlayersHere:%d", __func__,
hid, nPlayersS, nPlayersH, m_nPlayersSought, m_nPlayersHere );
/* increasePlayerCounts() is where we actually increase the numbers. Is
that right? */
if ( hid == HOST_ID_SERVER ) {
success = m_nPlayersSought == 0;
@ -694,7 +893,7 @@ CookieRef::checkCounts( const CRefEvent* evt )
CRefEvent newevt;
if ( success ) {
newevt = *evt;
newevt = *evt; /* this is a gross hack!!! */
newevt.type = XWE_OKTOSEND;
} else {
newevt.type = XWE_COUNTSBAD;
@ -721,30 +920,20 @@ void
CookieRef::sendResponse( const CRefEvent* evt, bool initial )
{
int socket = evt->u.con.socket;
HostID hid = evt->u.con.srcID;
int nPlayersH = evt->u.con.nPlayersH;
int nPlayersS = evt->u.con.nPlayersS;
int seed = evt->u.con.seed;
ASSERT_LOCKED();
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, socket=%d (size=%d)",
__func__, hid, socket, m_sockets.size());
HostRec hr(hid, socket, nPlayersH, nPlayersS, seed );
m_sockets.push_back( hr );
logf( XW_LOGINFO, "m_sockets.size() now %d", m_sockets.size() );
/* Now send the response */
unsigned char buf[1 + /* cmd */
sizeof(short) + /* heartbeat */
sizeof(CookieID)
unsigned char buf[1 /* cmd */
+ sizeof(short) /* heartbeat */
+ sizeof(short) /* total here */
+ sizeof(short) /* total expected */
];
unsigned char* bufp = buf;
*bufp++ = initial ? XWRELAY_CONNECT_RESP : XWRELAY_RECONNECT_RESP;
putNetShort( &bufp, GetHeartbeat() );
putNetShort( &bufp, GetCookieID() );
*bufp++ = GetPlayersHere();
*bufp++ = GetPlayersSought();
send_with_length( socket, buf, bufp - buf, true );
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
@ -814,16 +1003,35 @@ CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
}
} /* notifyOthers */
void
CookieRef::moveSockets( void )
{
ASSERT_LOCKED();
vector<int> sockets;
vector<HostRec>::iterator iter;
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
sockets.push_back( iter->m_socket );
}
CRefMgr::Get()->MoveSockets( sockets, this );
}
void
CookieRef::sendAllHere( void )
{
unsigned char buf[1 + 1 + 1 + MAX_CONNNAME_LEN];
unsigned char buf[1 + 1 /* hostID */
+ sizeof(CookieID)
+ 1 + MAX_CONNNAME_LEN];
unsigned char* bufp = buf;
unsigned char* idLoc;
*bufp++ = XWRELAY_ALLHERE;
idLoc = bufp++; /* space for hostId, remembering address */
putNetShort( &bufp, GetCookieID() );
const char* connName = ConnName();
assert( !!connName && connName[0] );
int len = strlen( connName );

View file

@ -82,7 +82,7 @@ class CookieRef {
int CountSockets() { return m_sockets.size(); }
bool HasSocket( int socket );
bool HasSocket_locked( int socket );
const char* Cookie() { return m_cookie.c_str(); }
const char* Cookie() const { return m_cookie.c_str(); }
const char* ConnName() { return m_connName.c_str(); }
int GetHeartbeat() { return m_heatbeat; }
@ -185,6 +185,7 @@ class CookieRef {
void handleEvents();
void sendResponse( const CRefEvent* evt, bool initial );
void populate( vector<HostRec> hosts );
void increasePlayerCounts( const CRefEvent* evt );
void reducePlayerCounts( int socket );
void checkCounts( const CRefEvent* evt );
@ -201,6 +202,7 @@ class CookieRef {
void notifyDisconn(const CRefEvent* evt);
void removeSocket( int socket );
void sendAllHere( void );
void moveSockets( void );
bool SeedBelongs( int gameSeed );
bool SeedsBelong( const char* connName );
void assignConnName( void );
@ -212,6 +214,9 @@ class CookieRef {
bool notInUse(void) { return m_cookieID == 0; }
bool tryMakeGame( vector<HostRec>& remaining );
void insertSorted( HostRec hr );
/* timer callback */
static void s_checkAllConnected( void* closure );

View file

@ -130,8 +130,9 @@ CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
HostID hid, int socket, int nPlayersH, int nPlayersT,
int gameSeed, bool* alreadyHere )
{
logf( XW_LOGINFO, "%s(cookie=%s,connName=%s,hid=%d,seed=%x,socket=%d)", __func__,
cookie, connName, hid, gameSeed, socket );
logf( XW_LOGINFO, "%s(cookie=%s,connName=%s,hid=%d,seed=%x,socket=%d,"
"here=%d,total=%d)", __func__, cookie, connName, hid, gameSeed,
socket, nPlayersH, nPlayersT );
CookieRef* found = NULL;
if ( !!cookie || !!connName ) { /* drop if both are null */
@ -149,7 +150,8 @@ CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
if ( cref->Lock() ) {
assert( !cookie || 0 == strcmp( cookie, cref->Cookie() ) );
if ( cref->SeedBelongs( gameSeed ) ) {
logf( XW_LOGINFO, "%s: SeedBelongs: dup packet?", __func__ );
logf( XW_LOGINFO, "%s: SeedBelongs: dup packet?",
__func__ );
*alreadyHere = true;
found = cref;
} else if ( cref->GameOpen( cookie, nPlayersH,
@ -312,7 +314,7 @@ CRefMgr::getMakeCookieRef_locked( const char* cookie, const char* connName,
cref = FindOpenGameFor( cookie, connName, hid, socket, nPlayersH, nPlayersT,
gameSeed, &alreadyHere );
if ( cref == NULL && !alreadyHere ) {
cref = AddNew( cookie, connName, gameSeed, nextCID( NULL ) );
cref = AddNew( cookie, connName, nextCID( NULL ) );
}
return cref;
@ -321,8 +323,14 @@ CRefMgr::getMakeCookieRef_locked( const char* cookie, const char* connName,
bool
CRefMgr::Associate( int socket, CookieRef* cref )
{
bool isNew = false;
MutexLock ml( &m_SocketStuffMutex );
return Associate_locked( socket, cref );
}
bool
CRefMgr::Associate_locked( int socket, CookieRef* cref )
{
bool isNew = false;
SocketMap::iterator iter = m_SocketStuff.find( socket );
/* This isn't enough. Must provide a way to reuse sockets should a
genuinely different connection appear. Now maybe we already remove
@ -341,9 +349,8 @@ CRefMgr::Associate( int socket, CookieRef* cref )
}
void
CRefMgr::Disassociate( int socket, CookieRef* cref )
CRefMgr::Disassociate_locked( int socket, CookieRef* cref )
{
MutexLock ml( &m_SocketStuffMutex );
SocketMap::iterator iter = m_SocketStuff.find( socket );
if ( iter == m_SocketStuff.end() ) {
logf( XW_LOGERROR, "can't find SocketStuff for socket %d", socket );
@ -355,6 +362,32 @@ CRefMgr::Disassociate( int socket, CookieRef* cref )
}
}
void
CRefMgr::Disassociate( int socket, CookieRef* cref )
{
MutexLock ml( &m_SocketStuffMutex );
Disassociate_locked( socket, cref );
}
void
CRefMgr::MoveSockets( vector<int> sockets, CookieRef* cref )
{
MutexLock ml( &m_SocketStuffMutex );
vector<int>::iterator iter;
for ( iter = sockets.begin(); iter != sockets.end(); ++iter ) {
Disassociate_locked( *iter, NULL );
Associate_locked( *iter, cref );
}
}
CookieRef*
CRefMgr::Clone( const CookieRef* parent )
{
const char* cookie = parent->Cookie();
CookieRef* cref = AddNew( cookie, NULL, nextCID( NULL ) );
return cref;
}
#if 0
pthread_mutex_t*
CRefMgr::GetWriteMutexForSocket( int socket )
@ -441,11 +474,11 @@ CRefMgr::heartbeatProc( void* closure )
#endif
CookieRef*
CRefMgr::AddNew( const char* cookie, const char* connName, int seed,
CookieID id )
CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id )
{
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, seed=%.4X, cid=%d)", __func__,
cookie, connName, seed, id );
/* PENDING: should this return a locked cref? */
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, cid=%d)", __func__,
cookie, connName, id );
CookieRef* ref = getFromFreeList();

View file

@ -97,7 +97,11 @@ class CRefMgr {
/* Track sockets independent of cookie refs */
bool Associate( int socket, CookieRef* cref );
bool Associate_locked( int socket, CookieRef* cref );
void Disassociate( int socket, CookieRef* cref );
void Disassociate_locked( int socket, CookieRef* cref );
void MoveSockets( vector<int> sockets, CookieRef* cref );
CookieRef* Clone( const CookieRef* parent );
pthread_mutex_t* GetWriteMutexForSocket( int socket );
void RemoveSocketRefs( int socket );
void PrintSocketInfo( int socket, string& out );
@ -133,8 +137,7 @@ class CRefMgr {
CookieRef* getCookieRef( int socket );
bool checkCookieRef_locked( CookieRef* cref );
CookieRef* getCookieRef_impl( CookieID cookieID );
CookieRef* AddNew( const char* cookie, const char* connName, int seed,
CookieID id );
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id );
CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
HostID hid, int socket, int nPlayersH,
int nPlayersS, int gameSeed,

View file

@ -83,6 +83,9 @@ StateTable g_stateTable[] = {
{ XWS_CONNECTING, XWE_DISCONNMSG, XWA_DISCONNECT, XWS_CONNECTING },
{ XWS_MISSING, XWE_DISCONNMSG, XWA_DISCONNECT, XWS_MISSING },
/* Cloned state is added via code, not via table actions; new initial state */
{ XWS_CLONED, XWE_CLONECHKMSG, XWA_POSTCLONE, XWS_CONNECTING },
/* I'm seeing this but not sure how to handle. Might disconnect be
needed now */
{ XWS_MISSING, XWE_FORWARDMSG, XWA_DISCONNECT, XWS_MISSING },
@ -178,6 +181,7 @@ stateString( XW_RELAY_STATE state )
CASESTR(XWS_CHKCOUNTS_INIT);
CASESTR(XWS_CHKCOUNTS_MISS);
CASESTR(XWS_CHKCOUNTS);
CASESTR(XWS_CLONED);
default:
assert(0);
}
@ -212,6 +216,7 @@ eventString( XW_RELAY_EVENT evt )
CASESTR(XWE_OKTOSEND);
CASESTR(XWE_COUNTSBAD);
CASESTR(XWE_SHUTDOWN);
CASESTR(XWE_CLONECHKMSG);
default:
assert(0);
}
@ -240,6 +245,7 @@ actString( XW_RELAY_ACTION act )
CASESTR(XWA_REMOVESOCKET);
CASESTR(XWA_HEARTDISCONN);
CASESTR(XWA_SHUTDOWN);
CASESTR(XWA_POSTCLONE);
default:
assert(0);
}

View file

@ -35,6 +35,8 @@ enum {
,XWS_CHKCOUNTS_MISS /* from the missing state */
,XWS_CHKCOUNTS /* check from any other state */
,XWS_CLONED /* just got duplicated */
,XWS_CHK_ALLHERE /* Need to see if all expected devices/players
are on board. */
@ -93,6 +95,8 @@ typedef enum {
,XWE_RECONNECTMSG /* A device is re-connecting using the
connID for this object */
,XWE_CLONECHKMSG /* We've cloned; now clean up */
,XWE_DISCONNMSG /* disconnect socket from this game/cref */
,XWE_FORWARDMSG /* A message needs forwarding */
@ -132,6 +136,8 @@ typedef enum {
,XWA_SENDALLHERE /* Let all devices know we're in business */
,XWA_SNDALLHERE_2 /* Ditto, but for a reconnect */
,XWA_POSTCLONE
,XWA_FWD /* Forward a message */
,XWA_NOTEHEART /* Record heartbeat received */

View file

@ -51,19 +51,19 @@ enum { XWRELAY_NONE /* 0 is an illegal value */
, XWRELAY_CONNECT_RESP
/* Sent from relay to device in response to XWRELAY_CONNECT. Format:
heartbeat_seconds: 2; connectionID: 2; connNameLen: 1;
connName<connNameLen>*/
heartbeat_seconds: 2; players_here: 1; players_sought: 1; */
, XWRELAY_RECONNECT_RESP
/* Sent from relay to device in response to XWRELAY_RECONNECT. Format:
heartbeat_seconds: 2; */
same as for XWRELAY_CONNECT_RESP */
, XWRELAY_ALLHERE
/* Sent from relay when it enters the state where all expected devices
are here (at start of new game or after having been gone for a
while). Devices should not attempt to forward messages before this
message is received or after XWRELAY_DISCONNECT_OTHER is received.
Format: hostID: 1; */
Format: hostID: 1; connectionID: 2; connNameLen: 1;
connName<connNameLen>; */
, XWRELAY_DISCONNECT_YOU
/* Sent from relay when existing connection is terminated.
@ -103,9 +103,10 @@ typedef unsigned char XWRELAY_Cmd;
#define MAX_MSG_LEN 256 /* 100 is more like it */
#define MAX_CONNNAME_LEN 48 /* host ID, boot time, and seeds as hex? */
#define XWRELAY_PROTO_VERSION_ORIG 0x01
#define XWRELAY_PROTO_VERSION_LATE_NAME 0x02
#define XWRELAY_PROTO_VERSION XWRELAY_PROTO_VERSION_LATE_NAME
#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
/* Errors passed with denied */
#ifndef CANT_DO_TYPEDEF