mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-15 15:41:24 +01:00
Add and handle disconnect message so a device can reuse its socket for
a new game.
This commit is contained in:
parent
709108f8c3
commit
d9826ae275
8 changed files with 169 additions and 76 deletions
103
relay/cref.cpp
103
relay/cref.cpp
|
@ -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 {
|
||||
|
||||
|
|
22
relay/cref.h
22
relay/cref.h
|
@ -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;
|
||||
|
|
|
@ -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 ) ) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue