Add and handle disconnect message so a device can reuse its socket for

a new game.
This commit is contained in:
ehouse 2005-09-05 15:50:49 +00:00
parent 709108f8c3
commit d9826ae275
8 changed files with 169 additions and 76 deletions

View file

@ -71,7 +71,7 @@ SocketsIterator::Next()
* CookieRef class
*****************************************************************************/
CookieRef::CookieRef( string s, CookieID id )
CookieRef::CookieRef( const char* s, CookieID id )
: m_heatbeat(RelayConfigs::GetConfigs()->GetHeartbeatInterval())
, m_name(s)
, m_totalSent(0)
@ -97,15 +97,15 @@ CookieRef::~CookieRef()
for ( ; ; ) {
RWWriteLock rwl( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
map<HostID,HostRec>::iterator iter = m_sockets.begin();
if ( iter == m_hostSockets.end() ) {
if ( iter == m_sockets.end() ) {
break;
}
int socket = iter->second.m_socket;
tPool->CloseSocket( socket );
m_hostSockets.erase( iter );
m_sockets.erase( iter );
}
pthread_rwlock_destroy( &m_sockets_rwlock );
@ -133,12 +133,28 @@ CookieRef::_Reconnect( int socket, HostID srcID )
handleEvents();
}
void
CookieRef::_Disconnect( int socket, HostID hostID )
{
CRefMgr::Get()->Disassociate( socket, this );
MutexLock ml( &m_EventsMutex );
CRefEvent evt;
evt.type = XW_EVENT_DISCONNECTMSG;
evt.u.discon.socket = socket;
evt.u.discon.srcID = hostID;
m_eventQueue.push_back( evt );
handleEvents();
}
int
CookieRef::SocketForHost( HostID dest )
{
int socket;
map<HostID,HostRec>::iterator iter = m_hostSockets.find( dest );
if ( iter == m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.find( dest );
if ( iter == m_sockets.end() ) {
socket = -1;
} else {
socket = iter->second.m_socket;
@ -148,6 +164,18 @@ CookieRef::SocketForHost( HostID dest )
return socket;
}
/* The idea here is: have we never seen the XW_ST_ALLCONNECTED state. This
needs to include any states reachable from XW_ST_ALLCONNECTED from which
recovery back to XW_ST_ALLCONNECTED is possible. This is used to decide
whether to admit a connection based on its cookie -- whether that cookie
should join an existing cref or get a new one? */
int
CookieRef::NeverFullyConnected()
{
return m_curState != XW_ST_ALLCONNECTED
&& m_curState != XW_ST_MISSING;
}
void
CookieRef::notifyDisconn( const CRefEvent* evt )
{
@ -161,19 +189,18 @@ CookieRef::notifyDisconn( const CRefEvent* evt )
} /* notifyDisconn */
void
CookieRef::removeSocket( const CRefEvent* evt )
CookieRef::removeSocket( int socket )
{
int socket = evt->u.rmsock.socket;
int count;
{
RWWriteLock rwl( &m_sockets_rwlock );
count = CountSockets();
count = m_sockets.size();
assert( count > 0 );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.begin();
while ( iter != m_sockets.end() ) {
if ( iter->second.m_socket == socket ) {
m_hostSockets.erase(iter);
m_sockets.erase(iter);
--count;
break;
}
@ -181,9 +208,6 @@ CookieRef::removeSocket( const CRefEvent* evt )
}
}
/* Does this belong here or at a higher level? */
XWThreadPool::GetTPool()->CloseSocket( socket );
if ( count == 0 ) {
pushLastSocketGoneEvent();
}
@ -196,8 +220,8 @@ CookieRef::HasSocket( int socket )
logf( "CookieRef::HasSocket" );
RWReadLock rwl( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.begin();
while ( iter != m_sockets.end() ) {
if ( iter->second.m_socket == socket ) {
found = 1;
break;
@ -222,8 +246,8 @@ CookieRef::_CheckHeartbeats( time_t now )
MutexLock ml( &m_EventsMutex );
{
RWReadLock rwl( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.begin();
while ( iter != m_sockets.end() ) {
time_t last = iter->second.m_lastHeartbeat;
if ( (now - last) > GetHeartbeat() ) {
pushHeartFailedEvent( iter->second.m_socket );
@ -375,9 +399,9 @@ CookieRef::handleEvents()
XW_RELAY_ACTION takeAction;
if ( getFromTable( m_curState, evt.type, &takeAction, &m_nextState ) ) {
logf( "moving from state %s to state %s for event %s",
stateString(m_curState), stateString(m_nextState),
eventString(evt.type) );
logf( "cid %d: moving from state %s to state %s for event %s",
m_connectionID, stateString(m_curState),
stateString(m_nextState), eventString(evt.type) );
switch( takeAction ) {
case XW_ACTION_SEND_1ST_RSP:
@ -413,6 +437,11 @@ CookieRef::handleEvents()
XWRELAY_ERROR_HEART_YOU );
break;
case XW_ACTION_DISCONNECT:
removeSocket( evt.u.discon.socket );
/* Don't notify. This is a normal part of a game ending. */
break;
case XW_ACTION_NOTEHEART:
noteHeartbeat( &evt );
break;
@ -424,7 +453,7 @@ CookieRef::handleEvents()
case XW_ACTION_REMOVESOCKET:
notifyOthers( evt.u.rmsock.socket, XWRELAY_DISCONNECT_OTHER,
XWRELAY_ERROR_LOST_OTHER );
removeSocket( &evt );
removeSocket( evt.u.rmsock.socket );
break;
case XW_ACTION_NONE:
@ -437,8 +466,6 @@ CookieRef::handleEvents()
}
m_curState = m_nextState;
} else {
assert(0);
}
}
} /* handleEvents */
@ -447,12 +474,14 @@ void
CookieRef::send_with_length( int socket, unsigned char* buf, int bufLen )
{
SocketWriteLock slock( socket );
if ( slock.socketFound() ) {
if ( send_with_length_unsafe( socket, buf, bufLen ) ) {
RecordSent( bufLen, socket );
} else {
/* ok that the slock above is still in scope */
killSocket( socket, "couldn't send" );
if ( send_with_length_unsafe( socket, buf, bufLen ) ) {
RecordSent( bufLen, socket );
} else {
/* ok that the slock above is still in scope */
killSocket( socket, "couldn't send" );
}
}
}
@ -498,7 +527,7 @@ CookieRef::sendResponse( const CRefEvent* evt )
logf( "remembering pair: hostid=%x, socket=%d", id, socket );
RWWriteLock ml( &m_sockets_rwlock );
HostRec hr(socket);
m_hostSockets.insert( pair<HostID,HostRec>(id,hr) );
m_sockets.insert( pair<HostID,HostRec>(id,hr) );
/* Now send the response */
unsigned char buf[7];
@ -589,8 +618,8 @@ CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
RWReadLock ml( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.begin();
while ( iter != m_sockets.end() ) {
int other = iter->second.m_socket;
if ( other != socket ) {
send_msg( other, iter->first, msg, why );
@ -604,8 +633,8 @@ CookieRef::disconnectSockets( int socket, XWREASON why )
{
if ( socket == 0 ) {
RWReadLock ml( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.begin();
while ( iter != m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.begin();
while ( iter != m_sockets.end() ) {
assert( iter->second.m_socket != 0 );
disconnectSockets( iter->second.m_socket, why );
++iter;
@ -624,8 +653,8 @@ CookieRef::noteHeartbeat( const CRefEvent* evt )
RWWriteLock rwl( &m_sockets_rwlock );
map<HostID,HostRec>::iterator iter = m_hostSockets.find(id);
if ( iter == m_hostSockets.end() ) {
map<HostID,HostRec>::iterator iter = m_sockets.find(id);
if ( iter == m_sockets.end() ) {
logf( "no socket for HostID %d", id );
} else {

View file

@ -52,34 +52,35 @@ class CookieRef {
friend class SafeCref;
friend class CookieMapIterator;
CookieRef( string s, CookieID id );
CookieRef( const char* s, CookieID id );
~CookieRef();
/* Within this cookie, remember that this hostID and socket go together.
If the hostID is HOST_ID_SERVER, it's the server. */
CookieID GetCookieID() { return m_connectionID; }
int HostKnown( HostID host ) { return -1 != SocketForHost( host ); }
int CountSockets() { return m_hostSockets.size(); }
int CountSockets() { return m_sockets.size(); }
int HasSocket( int socket );
string Name() { return m_name; }
short GetHeartbeat() { return m_heatbeat; }
int SocketForHost( HostID dest );
int NotFullyConnected() { return m_curState != XW_ST_ALLCONNECTED; }
int NeverFullyConnected();
/* for console */
void _PrintCookieInfo( string& out );
void PrintSocketInfo( string& out, int socket );
static CookieMapIterator GetCookieIterator();
static CookieRef* AddNew( string s, CookieID id );
/* Nuke an existing */
static void Delete( CookieID id );
static void Delete( const char* name );
void _Connect( int socket, HostID srcID );
void _Reconnect( int socket, HostID srcID );
void _Disconnect(int socket, HostID hostID );
void _HandleHeartbeat( HostID id, int socket );
void _CheckHeartbeats( time_t now );
void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen );
@ -101,6 +102,10 @@ class CookieRef {
int socket;
HostID srcID;
} con;
struct {
int socket;
HostID srcID;
} discon;
struct {
HostID id;
int socket;
@ -109,10 +114,6 @@ class CookieRef {
time_t now;
vector<int>* victims;
} htime;
struct {
HostID hostID;
int reason;
} discon;
struct {
int socket;
} rmsock;
@ -160,14 +161,15 @@ class CookieRef {
void disconnectSockets( int socket, XWREASON why );
void noteHeartbeat(const CRefEvent* evt);
void notifyDisconn(const CRefEvent* evt);
void removeSocket(const CRefEvent* evt);
void removeSocket( int socket );
/* timer callback */
static void s_checkAllConnected( void* closure );
map<HostID,HostRec> m_hostSockets;
map<HostID,HostRec> m_sockets;
pthread_rwlock_t m_sockets_rwlock;
CookieID m_connectionID;
short m_heatbeat; /* might change per carrier or something. */
string m_name;

View file

@ -70,7 +70,7 @@ CRefMgr::getMakeCookieRef_locked( const char* cookie, CookieID connID )
CookieID newId = CookieIdForName( cookie );
if ( newId == 0 ) { /* not in the system */
cref = AddNew( string(cookie), connID );
cref = AddNew( cookie, connID );
} else {
cref = getCookieRef_impl( newId );
}
@ -94,7 +94,7 @@ CRefMgr::CookieIdForName( const char* name )
CookieMap::iterator iter = m_cookieMap.begin();
while ( iter != m_cookieMap.end() ) {
cref = iter->second;
if ( cref->Name() == s && cref->NotFullyConnected() ) {
if ( cref->Name() == s && cref->NeverFullyConnected() ) {
return cref->GetCookieID();
}
++iter;
@ -115,6 +115,21 @@ CRefMgr::Associate( int socket, CookieRef* cref )
m_SocketStuff.insert( pair< int, SocketStuff* >( socket, stuff ) );
}
void
CRefMgr::Disassociate( int socket, CookieRef* cref )
{
MutexLock ml( &m_SocketStuffMutex );
SocketMap::iterator iter = m_SocketStuff.find( socket );
if ( iter == m_SocketStuff.end() ) {
logf( "can't find cref/threadID pair for socket %d", socket );
} else {
SocketStuff* stuff = iter->second;
assert( stuff->m_cref == cref );
delete stuff;
m_SocketStuff.erase( iter );
}
}
pthread_mutex_t*
CRefMgr::GetWriteMutexForSocket( int socket )
{
@ -124,7 +139,8 @@ CRefMgr::GetWriteMutexForSocket( int socket )
SocketStuff* stuff = iter->second;
return &stuff->m_writeMutex;
}
assert( 0 );
logf( "GetWriteMutexForSocket: not found" );
return NULL;
} /* GetWriteMutexForSocket */
void
@ -240,13 +256,13 @@ CRefMgr::UnlockCref( CookieRef* cref )
}
CookieRef*
CRefMgr::AddNew( string s, CookieID id )
CRefMgr::AddNew( const char* s, CookieID id )
{
RWWriteLock rwl( &m_cookieMapRWLock );
logf( "making new cref" );
CookieRef* ref = new CookieRef( s, id );
m_cookieMap.insert( pair<CookieID, CookieRef*>(ref->GetCookieID(), ref ) );
logf( "paired cookie %s with id %d", s.c_str(), ref->GetCookieID() );
logf( "paired cookie %s with id %d", s, ref->GetCookieID() );
return ref;
} /* AddNew */
@ -366,7 +382,6 @@ CookieMapIterator::Next()
SafeCref::SafeCref( const char* cookie, CookieID connID )
: m_cref( NULL )
, m_connID(0)
, m_mgr( CRefMgr::Get() )
{
CookieRef* cref = m_mgr->getMakeCookieRef_locked( cookie, connID );
@ -379,7 +394,6 @@ SafeCref::SafeCref( const char* cookie, CookieID connID )
SafeCref::SafeCref( CookieID connID )
: m_cref( NULL )
, m_connID(0)
, m_mgr( CRefMgr::Get() )
{
CookieRef* cref = m_mgr->getCookieRef_locked( connID );
@ -392,7 +406,6 @@ SafeCref::SafeCref( CookieID connID )
SafeCref::SafeCref( int socket )
: m_cref( NULL )
, m_connID(0)
, m_mgr( CRefMgr::Get() )
{
CookieRef* cref = m_mgr->getCookieRef_locked( socket );
@ -405,7 +418,6 @@ SafeCref::SafeCref( int socket )
SafeCref::SafeCref( CookieRef* cref )
: m_cref( NULL )
, m_connID(0)
, m_mgr( CRefMgr::Get() )
{
if ( m_mgr->checkCookieRef_locked( cref ) ) {

View file

@ -69,6 +69,7 @@ class CRefMgr {
/* Track sockets independent of cookie refs */
void Associate( int socket, CookieRef* cref );
void Disassociate( int socket, CookieRef* cref );
pthread_mutex_t* GetWriteMutexForSocket( int socket );
void RemoveSocketRefs( int socket );
void PrintSocketInfo( int socket, string& out );
@ -76,12 +77,12 @@ class CRefMgr {
private:
friend class SafeCref;
CookieRef* getMakeCookieRef_locked( const char* cookie, CookieID connID );
CookieRef* getMakeCookieRef_locked( const char* cookie, CookieID cid );
CookieRef* getCookieRef_locked( CookieID cookieID );
CookieRef* getCookieRef_locked( int socket );
int checkCookieRef_locked( CookieRef* cref );
CookieRef* getCookieRef_impl( CookieID cookieID );
CookieRef* AddNew( string s, CookieID id );
CookieRef* AddNew( const char* s, CookieID id );
int LockCref( CookieRef* cref );
void UnlockCref( CookieRef* cref );
@ -105,8 +106,8 @@ class SafeCref {
CookieRef instance at a time. */
public:
SafeCref( const char* cookie, CookieID connID );
SafeCref( CookieID connID );
SafeCref( const char* cookie, CookieID cid );
SafeCref( CookieID cid );
SafeCref( int socket );
SafeCref( CookieRef* cref );
~SafeCref();
@ -122,6 +123,9 @@ class SafeCref {
void Reconnect( int socket, HostID srcID ) {
m_cref->_Reconnect( socket, srcID );
}
void Disconnect(int socket, HostID hostID ) {
m_cref->_Disconnect( socket, hostID );
}
void Remove( int socket ) {
m_cref->_Remove( socket );
}
@ -142,7 +146,6 @@ class SafeCref {
private:
CookieRef* m_cref;
CookieID m_connID;
CRefMgr* m_mgr;
};

View file

@ -66,6 +66,12 @@ StateTable g_stateTable[] = {
{ XW_ST_CONNECTING, XW_EVENT_CONNECTMSG, XW_ACTION_SENDRSP, XW_ST_CONNECTING },
{ XW_ST_CONNECTING, XW_EVENT_RECONNECTMSG, XW_ACTION_SENDRSP, XW_ST_CONNECTING },
/* Disconnect. */
{ XW_ST_ALLCONNECTED, XW_EVENT_DISCONNECTMSG, XW_ACTION_DISCONNECT, XW_ST_MISSING },
{ XW_ST_CONNECTING, XW_EVENT_DISCONNECTMSG, XW_ACTION_DISCONNECT, XW_ST_CONNECTING },
{ XW_ST_MISSING, XW_EVENT_DISCONNECTMSG, XW_ACTION_DISCONNECT, XW_ST_MISSING },
{ XW_ST_MISSING, XW_EVENT_NOMORESOCKETS, XW_ACTION_NONE, XW_ST_DEAD },
/* Forward requests while not locked are ok -- but we must check that the
target is actually present. If no socket available must drop the message */
{ XW_ST_CONNECTING, XW_EVENT_FORWARDMSG, XW_ACTION_CHECKDEST, XW_ST_CHECKINGDEST },
@ -79,27 +85,31 @@ StateTable g_stateTable[] = {
/* Timeout before all connected */
{ XW_ST_CONNECTING, XW_EVENT_CONNTIMER, XW_ACTION_TIMERDISCONNECT,XW_ST_DEAD },
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTFAILED, XW_ACTION_HEARTDISCONNECT, XW_ST_MISSING },
{ XW_ST_CONNECTING, XW_EVENT_HEARTFAILED, XW_ACTION_HEARTDISCONNECT, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTFAILED, XW_ACTION_HEARTDISCONNECT, XW_ST_ALLCONNECTED },
{ XW_ST_MISSING, XW_EVENT_HEARTFAILED, XW_ACTION_HEARTDISCONNECT, XW_ST_MISSING },
{ XW_ST_CONNECTING, XW_EVENT_REMOVESOCKET, XW_ACTION_REMOVESOCKET, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_REMOVESOCKET, XW_ACTION_REMOVESOCKET, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_REMOVESOCKET, XW_ACTION_REMOVESOCKET, XW_ST_MISSING },
{ XW_ST_MISSING, XW_EVENT_REMOVESOCKET, XW_ACTION_REMOVESOCKET, XW_ST_MISSING },
{ XW_ST_CONNECTING, XW_EVENT_NOMORESOCKETS, XW_ACTION_NONE, XW_ST_DEAD },
{ XW_ST_DEAD, XW_EVENT_NOMORESOCKETS, XW_ACTION_NONE, XW_ST_DEAD },
{ XW_ST_CONNECTING, XW_EVENT_NOMORESOCKETS, XW_ACTION_NONE, XW_ST_DEAD },
{ XW_ST_DEAD, XW_EVENT_NOMORESOCKETS, XW_ACTION_NONE, XW_ST_DEAD },
/* This is the entry we'll use most of the time */
{ XW_ST_ALLCONNECTED, XW_EVENT_FORWARDMSG, XW_ACTION_FWD, XW_ST_ALLCONNECTED },
{ XW_ST_ALLCONNECTED, XW_EVENT_CONNTIMER, XW_ACTION_NONE, XW_ST_ALLCONNECTED },
/* Heartbeat arrived */
{ XW_ST_CONNECTING, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_ALLCONNECTED },
{ XW_ST_CONNECTING, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_ALLCONNECTED },
{ XW_ST_MISSING, XW_EVENT_HEARTMSG, XW_ACTION_NOTEHEART, XW_ST_MISSING },
/* I think we need a state XW_ST_SOMEMISSING. The game can't be played,
but we're open to XWRELAY_RECONNECT (but not to XWRELAY_CONNECT) */
{ XW_ST_CONNECTING, XW_EVENT_NOTIFYDISCON, XW_ACTION_NOTIFYDISCON, XW_ST_CONNECTING },
{ XW_ST_ALLCONNECTED, XW_EVENT_NOTIFYDISCON, XW_ACTION_NOTIFYDISCON, XW_ST_ALLCONNECTED },
{ XW_ST_ALLCONNECTED, XW_EVENT_NOTIFYDISCON, XW_ACTION_NOTIFYDISCON, XW_ST_MISSING },
{ XW_ST_MISSING, XW_EVENT_NOTIFYDISCON, XW_ACTION_NOTIFYDISCON, XW_ST_DEAD },
{ XW_ST_DEAD, XW_EVENT_NOTIFYDISCON, XW_ACTION_NOTIFYDISCON, XW_ST_DEAD },
{ XW_ST_DEAD, XW_EVENT_REMOVESOCKET, XW_ACTION_REMOVESOCKET, XW_ST_DEAD },
@ -150,6 +160,7 @@ stateString( XW_RELAY_STATE state )
CASESTR(XW_ST_CHECKING_CONN);
CASESTR(XW_ST_CHECKINGDEST);
CASESTR(XW_ST_CHECKING_CAN_LOCK);
CASESTR(XW_ST_MISSING);
}
assert(0);
return "";
@ -162,6 +173,7 @@ eventString( XW_RELAY_EVENT evt )
CASESTR(XW_EVENT_NONE);
CASESTR(XW_EVENT_CONNECTMSG);
CASESTR(XW_EVENT_RECONNECTMSG);
CASESTR(XW_EVENT_DISCONNECTMSG);
CASESTR(XW_EVENT_FORWARDMSG);
CASESTR(XW_EVENT_HEARTMSG);
CASESTR(XW_EVENT_CONNTIMER);

View file

@ -22,7 +22,8 @@
/* states */
typedef enum {
typedef
enum {
XW_ST_NONE
,XW_ST_INITED /* Relay's running and the object's been
@ -42,6 +43,10 @@ typedef enum {
relay to do its work. This is the state
we're in most of the time. */
,XW_ST_MISSING /* We've been fully connected before but lost
somebody. Once [s]he's back we can be
fully connected again. */
,XW_ST_WAITING_RECON /* At least one device has been timed out or
sent a disconnect message. We can't flow
messages in this state, and will be killing
@ -67,6 +72,8 @@ typedef enum {
,XW_EVENT_RECONNECTMSG /* A device is re-connecting using the
connID for this object */
,XW_EVENT_DISCONNECTMSG /* disconnect socket from this game/cref */
,XW_EVENT_FORWARDMSG /* A message needs forwarding */
,XW_EVENT_HEARTMSG /* A heartbeat message arrived */
@ -110,6 +117,8 @@ typedef enum {
,XW_ACTION_CHECKDEST /* check that a given hostID has a socket */
,XW_ACTION_DISCONNECT
,XW_ACTION_NOTIFYDISCON
,XW_ACTION_REMOVESOCKET

View file

@ -215,6 +215,22 @@ processConnect( unsigned char* bufp, int bufLen, int socket, int recon )
}
} /* processConnect */
static void
processDisconnect( unsigned char* bufp, int bufLen, int socket )
{
if ( bufLen == 6 ) {
CookieID cookieID = getNetLong( &bufp );
HostID hostID = getNetShort( &bufp );
SafeCref scr( cookieID );
if ( scr.IsValid() ) {
scr.Disconnect( socket, hostID );
}
} else {
logf( "dropping XWRELAY_GAME_DISCONNECT; wrong length" );
}
}
void
killSocket( int socket, char* why )
{
@ -223,6 +239,7 @@ killSocket( int socket, char* why )
/* Might want to kill the thread it belongs to if we're not in it,
e.g. when unable to write to another socket. */
logf( "killSocket done" );
XWThreadPool::GetTPool()->CloseSocket( socket );
}
time_t
@ -258,14 +275,17 @@ processMessage( unsigned char* buf, int bufLen, int socket )
{
XWRELAY_Cmd cmd = *buf;
switch( cmd ) {
case XWRELAY_CONNECT:
case XWRELAY_GAME_CONNECT:
logf( "processMessage got XWRELAY_CONNECT" );
processConnect( buf+1, bufLen-1, socket, 0 );
break;
case XWRELAY_RECONNECT:
case XWRELAY_GAME_RECONNECT:
logf( "processMessage got XWRELAY_RECONNECT" );
processConnect( buf+1, bufLen-1, socket, 1 );
break;
case XWRELAY_GAME_DISCONNECT:
processDisconnect( buf+1, bufLen-1, socket );
break;
case XWRELAY_CONNECTRESP:
logf( "bad: processMessage got XWRELAY_CONNECTRESP" );
break;

View file

@ -26,18 +26,24 @@
/* Set if device is acting a server; cleared if as client */
#define FLAGS_SERVER_BIT 0x01
typedef enum { XWRELAY_NONE /* 0 is an illegal value */
typedef
enum { XWRELAY_NONE /* 0 is an illegal value */
, XWRELAY_CONNECT
, XWRELAY_GAME_CONNECT
/* Sent from device to relay to establish connection to relay. Format:
flags: 1; cookieLen: 1; cookie: <cookieLen>; hostID:
2. connectionID: 2. */
, XWRELAY_RECONNECT
, XWRELAY_GAME_RECONNECT
/* Connect using ID rather than cookie. Used by a device that's lost
its connection to a game in progress. Once a game is locked this is
the only way a host can get (back) in. */
, XWRELAY_GAME_DISCONNECT
/* Tell the relay that we're gone for this game. After this message is
sent, the host can reconnect on the same socket for a new game.
Format: cookieID: 4; srcID: 2 */
, XWRELAY_CONNECTRESP
/* Sent from relay to device in response to XWRELAY_CONNECT or
XWRELAY_RECONNECT. Format: heartbeat_seconds: 2; connectionID:
@ -58,10 +64,10 @@ typedef enum { XWRELAY_NONE /* 0 is an illegal value */
/* The relay says go away. Format: reason code: 1 */
, XWRELAY_HEARTBEAT
/* Sent in either direction. Format: cookieID: 2; srcID: 2 */
/* Sent in either direction. Format: cookieID: 4; srcID: 2 */
, XWRELAY_MSG_FROMRELAY
/* Sent from relay to device. Format: cookieID: 2; src_hostID: 2;
/* Sent from relay to device. Format: cookieID: 4; src_hostID: 2;
dest_hostID: 2; data <len-headerLen> */
, XWRELAY_MSG_TORELAY