mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-29 08:34:37 +01:00
add ACK to protocol, returned by device after gets connName on initial
connection. Space is held for device on assumption ack will come back, then given up if it fails.
This commit is contained in:
parent
f8c1c016cc
commit
821e4d9c39
9 changed files with 174 additions and 14 deletions
|
@ -1079,6 +1079,12 @@ sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
|
|||
return result;
|
||||
} /* sendMsg */
|
||||
|
||||
static void
|
||||
send_ack( CommsCtxt* comms )
|
||||
{
|
||||
send_via_relay( comms, XWRELAY_ACK, comms->r.myHostID, NULL, 0 );
|
||||
}
|
||||
|
||||
XP_S16
|
||||
comms_resendAll( CommsCtxt* comms )
|
||||
{
|
||||
|
@ -1190,6 +1196,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
|||
|
||||
case XWRELAY_CONNECT_RESP:
|
||||
got_connect_cmd( comms, stream, XP_FALSE );
|
||||
send_ack( comms );
|
||||
break;
|
||||
case XWRELAY_RECONNECT_RESP:
|
||||
got_connect_cmd( comms, stream, XP_TRUE );
|
||||
|
@ -1941,6 +1948,10 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
|||
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||
break;
|
||||
|
||||
case XWRELAY_ACK:
|
||||
stream_putU8( tmpStream, destID );
|
||||
break;
|
||||
|
||||
case XWRELAY_GAME_DISCONNECT:
|
||||
stream_putU16( tmpStream, comms->r.cookieID );
|
||||
stream_putU8( tmpStream, comms->r.myHostID );
|
||||
|
|
|
@ -97,6 +97,7 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
|
|||
m_nHostMsgs = 0;
|
||||
m_in_handleEvents = false;
|
||||
m_langCode = langCode;
|
||||
m_nPendingAcks = 0;
|
||||
|
||||
if ( RelayConfigs::GetConfigs()->GetValueFor( "SEND_DELAY_MILLIS",
|
||||
&m_delayMicros ) ) {
|
||||
|
@ -215,6 +216,17 @@ CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersS,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::_HandleAck( HostID hostID )
|
||||
{
|
||||
assert( m_nPendingAcks > 0 && m_nPendingAcks <= 4 );
|
||||
XW_RELAY_EVENT newEvt = m_nPendingAcks == 1? XWE_GOTLASTACK : XWE_GOTONEACK;
|
||||
CRefEvent evt( newEvt );
|
||||
evt.u.ack.srcID = hostID;
|
||||
m_eventQueue.push_back( evt );
|
||||
handleEvents();
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::_Disconnect( int socket, HostID hostID )
|
||||
{
|
||||
|
@ -557,9 +569,21 @@ CookieRef::handleEvents()
|
|||
if ( increasePlayerCounts( &evt, false ) ) {
|
||||
setAllConnectedTimer();
|
||||
sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP );
|
||||
postCheckAllHere();
|
||||
setAckTimer();
|
||||
}
|
||||
break;
|
||||
|
||||
case XWA_NOTEACKCHECK:
|
||||
postCheckAllHere();
|
||||
/* FALLTHRU */
|
||||
case XWA_NOTEACK:
|
||||
modPending( &evt, true );
|
||||
break;
|
||||
|
||||
case XWA_DROPDEVICE:
|
||||
modPending( &evt, false );
|
||||
break;
|
||||
|
||||
/* case XWA_SEND_1ST_RERSP: */
|
||||
/* if ( increasePlayerCounts( &evt, false ) ) { */
|
||||
/* setAllConnectedTimer(); */
|
||||
|
@ -753,6 +777,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
|
|||
int socket = evt->u.con.socket;
|
||||
int seed = evt->u.con.seed;
|
||||
bool addHost = false;
|
||||
bool addAck = false;
|
||||
/* XW_RELAY_EVENT newEvt = XWE_NONE; */
|
||||
|
||||
assert( m_nPlayersSought > 0 );
|
||||
|
@ -790,8 +815,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
|
|||
} else { /* a host; init values */
|
||||
m_nPlayersHere += nPlayersH;
|
||||
assert( m_nPlayersHere <= m_nPlayersSought );
|
||||
addHost = true;
|
||||
|
||||
addAck = true;
|
||||
DBMgr::Get()->AddPlayers( ConnName(), nPlayersH );
|
||||
|
||||
/* if ( m_nPlayersHere == m_nPlayersSought ) { /\* complete! *\/ */
|
||||
|
@ -824,14 +848,14 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
|
|||
/* logf( XW_LOGERROR, "%s: not pushing an event", __func__ ); */
|
||||
/* } */
|
||||
|
||||
if ( addHost ) {
|
||||
if ( addHost || addAck ) {
|
||||
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__, hostid, socket, m_sockets.size());
|
||||
|
||||
HostRec hr( hostid, socket, nPlayersH, seed );
|
||||
HostRec hr( hostid, socket, nPlayersH, seed, addAck );
|
||||
m_sockets.push_back( hr );
|
||||
|
||||
assert( !AlreadyHere( evt->u.con.seed, -1 ) );
|
||||
|
@ -843,9 +867,28 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
|
|||
assert( 0 );
|
||||
}
|
||||
drop:
|
||||
return addHost;
|
||||
return addHost || addAck;
|
||||
} /* increasePlayerCounts */
|
||||
|
||||
void
|
||||
CookieRef::modPending( const CRefEvent* evt, bool keep )
|
||||
{
|
||||
HostID hostID = evt->u.ack.srcID;
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_ackPending && iter->m_hostID == hostID ) {
|
||||
--m_nPendingAcks;
|
||||
|
||||
if ( keep ) {
|
||||
iter->m_ackPending = false;
|
||||
} else {
|
||||
m_sockets.erase( iter );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::postCheckAllHere()
|
||||
{
|
||||
|
@ -905,6 +948,26 @@ CookieRef::setAllConnectedTimer()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::setAckTimer( void )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s()", __func__ );
|
||||
time_t inHowLong;
|
||||
if ( RelayConfigs::GetConfigs()->GetValueFor( "DEVACK", &inHowLong ) ) {
|
||||
TimerMgr::GetTimerMgr()->SetTimer( inHowLong,
|
||||
s_checkAck, this, 0 );
|
||||
++m_nPendingAcks;
|
||||
} else {
|
||||
logf( XW_LOGINFO, "not setting timer" );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::cancelAckTimer( void )
|
||||
{
|
||||
TimerMgr::GetTimerMgr()->ClearTimer( s_checkAck, this );
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::cancelAllConnectedTimer()
|
||||
{
|
||||
|
@ -1224,6 +1287,14 @@ CookieRef::s_checkAllConnected( void* closure )
|
|||
scr.CheckAllConnected();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
CookieRef::s_checkAck( void* closure )
|
||||
{
|
||||
CookieRef* self = (CookieRef*)closure;
|
||||
SafeCref scr(self);
|
||||
scr.CheckNotAcked();
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::_CheckAllConnected()
|
||||
{
|
||||
|
@ -1234,6 +1305,17 @@ CookieRef::_CheckAllConnected()
|
|||
handleEvents();
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::_CheckNotAcked()
|
||||
{
|
||||
logf( XW_LOGINFO, "%s", __func__ );
|
||||
if ( m_nPendingAcks > 0 ) {
|
||||
assert( m_curState == XWS_WAITING_ACKS );
|
||||
CRefEvent newEvt( XWE_ACKTIMEOUT );
|
||||
m_eventQueue.push_back( newEvt );
|
||||
handleEvents();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::logf( XW_LogLevel level, const char* format, ... )
|
||||
|
|
|
@ -39,13 +39,14 @@ using namespace std;
|
|||
class CookieMapIterator; /* forward */
|
||||
|
||||
struct HostRec {
|
||||
public:
|
||||
HostRec(HostID hostID, int socket, int nPlayersH, int seed )
|
||||
public:
|
||||
HostRec(HostID hostID, int socket, int nPlayersH, int seed, bool ackPending )
|
||||
: m_hostID(hostID)
|
||||
, m_socket(socket)
|
||||
, m_nPlayersH(nPlayersH)
|
||||
, m_seed(seed)
|
||||
, m_lastHeartbeat(uptime())
|
||||
, m_ackPending(ackPending)
|
||||
{
|
||||
::logf( XW_LOGINFO, "created HostRec with id %d", m_hostID);
|
||||
}
|
||||
|
@ -54,6 +55,7 @@ struct HostRec {
|
|||
int m_nPlayersH;
|
||||
int m_seed;
|
||||
time_t m_lastHeartbeat;
|
||||
bool m_ackPending;
|
||||
};
|
||||
|
||||
class CookieRef {
|
||||
|
@ -110,6 +112,7 @@ class CookieRef {
|
|||
bool _Connect( int socket, int nPlayersH, int nPlayersS, int seed );
|
||||
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
|
||||
int seed );
|
||||
void _HandleAck( HostID hostID );
|
||||
void _Disconnect(int socket, HostID hostID );
|
||||
void _Shutdown();
|
||||
void _HandleHeartbeat( HostID id, int socket );
|
||||
|
@ -117,6 +120,7 @@ class CookieRef {
|
|||
void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen );
|
||||
void _Remove( int socket );
|
||||
void _CheckAllConnected();
|
||||
void _CheckNotAcked();
|
||||
|
||||
bool ShouldDie() { return m_curState == XWS_DEAD; }
|
||||
XW_RELAY_STATE CurState() { return m_curState; }
|
||||
|
@ -142,6 +146,9 @@ class CookieRef {
|
|||
int seed;
|
||||
HostID srcID;
|
||||
} con;
|
||||
struct {
|
||||
HostID srcID;
|
||||
} ack;
|
||||
struct {
|
||||
int socket;
|
||||
HostID srcID;
|
||||
|
@ -194,6 +201,8 @@ class CookieRef {
|
|||
void sendAnyStored( const CRefEvent* evt );
|
||||
void initPlayerCounts( const CRefEvent* evt );
|
||||
bool increasePlayerCounts( const CRefEvent* evt, bool reconn );
|
||||
void modPending( const CRefEvent* evt, bool keep );
|
||||
|
||||
void postCheckAllHere();
|
||||
bool hostAlreadyHere( int seed, int socket );
|
||||
|
||||
|
@ -201,6 +210,8 @@ class CookieRef {
|
|||
|
||||
void setAllConnectedTimer();
|
||||
void cancelAllConnectedTimer();
|
||||
void setAckTimer();
|
||||
void cancelAckTimer();
|
||||
|
||||
void forward_or_store( const CRefEvent* evt );
|
||||
void send_denied( const CRefEvent* evt, XWREASON why );
|
||||
|
@ -235,7 +246,8 @@ class CookieRef {
|
|||
|
||||
/* timer callback */
|
||||
static void s_checkAllConnected( void* closure );
|
||||
|
||||
static void s_checkAck( void* closure );
|
||||
|
||||
unsigned int m_nHostMsgs;
|
||||
MsgBufQueue m_hostMsgQueues[4];
|
||||
vector<HostRec> m_sockets;
|
||||
|
@ -262,12 +274,12 @@ class CookieRef {
|
|||
int m_langCode;
|
||||
|
||||
time_t m_starttime;
|
||||
int m_nPendingAcks;
|
||||
|
||||
pthread_mutex_t m_mutex;
|
||||
|
||||
pthread_t m_locking_thread; /* for debugging only */
|
||||
bool m_in_handleEvents; /* for debugging only */
|
||||
|
||||
int m_delayMicros;
|
||||
vector<unsigned short> m_seeds;
|
||||
}; /* CookieRef */
|
||||
|
|
|
@ -225,6 +225,14 @@ class SafeCref {
|
|||
m_cref->_Disconnect( socket, hostID );
|
||||
}
|
||||
}
|
||||
bool HandleAck(HostID hostID ) {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_HandleAck( hostID );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
void Shutdown() {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_Shutdown();
|
||||
|
@ -262,6 +270,11 @@ class SafeCref {
|
|||
m_cref->_CheckAllConnected();
|
||||
}
|
||||
}
|
||||
void CheckNotAcked() {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_CheckNotAcked();
|
||||
}
|
||||
}
|
||||
const char* Cookie() {
|
||||
if ( IsValid() ) {
|
||||
return m_cref->Cookie();
|
||||
|
|
|
@ -62,11 +62,14 @@ typedef struct StateTable {
|
|||
|
||||
static StateTable g_stateTable[] = {
|
||||
|
||||
{ XWS_INITED, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_CHK_ALLHERE },
|
||||
{ XWS_WAITMORE, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_CHK_ALLHERE },
|
||||
{ XWS_INITED, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITING_ACKS },
|
||||
{ XWS_WAITMORE, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITING_ACKS },
|
||||
{ XWS_WAITING_ACKS, XWE_DEVCONNECT, XWA_SEND_CONNRSP, XWS_WAITING_ACKS },
|
||||
{ XWS_WAITING_ACKS, XWE_GOTONEACK, XWA_NOTEACK, XWS_WAITING_ACKS },
|
||||
{ XWS_WAITING_ACKS, XWE_GOTLASTACK, XWA_NOTEACKCHECK, XWS_CHK_ALLHERE },
|
||||
{ XWS_WAITING_ACKS, XWE_ACKTIMEOUT, XWA_DROPDEVICE, XWS_WAITMORE },
|
||||
|
||||
{ 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 }, */
|
||||
|
@ -173,6 +176,7 @@ stateString( XW_RELAY_STATE state )
|
|||
CASESTR(XWS_ANY);
|
||||
CASESTR(XWS_INITED);
|
||||
CASESTR(XWS_WAITMORE);
|
||||
CASESTR(XWS_WAITING_ACKS);
|
||||
CASESTR(XWS_ALLCONND);
|
||||
CASESTR(XWS_DEAD);
|
||||
CASESTR(XWS_MISSING);
|
||||
|
@ -199,6 +203,9 @@ eventString( XW_RELAY_EVENT evt )
|
|||
CASESTR(XWE_NONE);
|
||||
CASESTR(XWE_DEVCONNECT);
|
||||
CASESTR(XWE_RECONNECT);
|
||||
CASESTR(XWE_GOTONEACK);
|
||||
CASESTR(XWE_GOTLASTACK);
|
||||
CASESTR(XWE_ACKTIMEOUT);
|
||||
CASESTR(XWE_DISCONN);
|
||||
CASESTR(XWE_FORWARDMSG);
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
|
@ -236,6 +243,10 @@ actString( XW_RELAY_ACTION act )
|
|||
CASESTR(XWA_SEND_DUP_ROOM);
|
||||
CASESTR(XWA_SEND_INITRSP);
|
||||
CASESTR(XWA_SEND_CONNRSP);
|
||||
CASESTR(XWA_NOTEACK);
|
||||
CASESTR(XWA_NOTEACKCHECK);
|
||||
/* CASESTR(XWA_ADDDEVICE); */
|
||||
CASESTR(XWA_DROPDEVICE);
|
||||
CASESTR(XWA_SNDALLHERE_2);
|
||||
CASESTR(XWA_FWD);
|
||||
CASESTR(XWA_NOTEHEART);
|
||||
|
|
|
@ -32,7 +32,7 @@ enum {
|
|||
are here. Success should be an error,
|
||||
actually: 1-device game. */
|
||||
|
||||
,XWS_CHKCOUNTS_MISS /* from the missing state */
|
||||
,XWS_WAITING_ACKS
|
||||
|
||||
,XWS_CHK_ALLHERE /* Need to see if all expected devices/players
|
||||
are on board. */
|
||||
|
@ -83,6 +83,10 @@ typedef enum {
|
|||
,XWE_RECONNECT /* A device is re-connecting using the connID for
|
||||
this object */
|
||||
|
||||
,XWE_GOTONEACK
|
||||
,XWE_GOTLASTACK
|
||||
,XWE_ACKTIMEOUT
|
||||
|
||||
,XWE_DISCONN /* disconnect socket from this game/cref */
|
||||
|
||||
,XWE_FORWARDMSG /* A message needs forwarding */
|
||||
|
@ -116,10 +120,17 @@ 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_ADDDEVICE /* got ack, so device is in for sure */
|
||||
,XWA_NOTEACK
|
||||
,XWA_NOTEACKCHECK
|
||||
,XWA_DROPDEVICE /* no ack; remove all traces of device */
|
||||
|
||||
,XWA_SEND_INITRSP /* response to first to connect */
|
||||
,XWA_SEND_CONNRSP /* response to rest that connect */
|
||||
|
||||
,XWA_SEND_RERSP
|
||||
,XWA_GOTALLACKS
|
||||
|
||||
,XWA_CHECK_HAVE_ROOM /* check for number of players still sought */
|
||||
|
||||
|
|
|
@ -57,6 +57,7 @@ TimerMgr::SetTimer( time_t inMillis, TimerProc proc, void* closure,
|
|||
MutexLock ml( &m_timersMutex );
|
||||
|
||||
if ( getTimer( proc, closure ) ) {
|
||||
logf( XW_LOGINFO, "%s: clearing old timer", __func__ );
|
||||
clearTimerImpl( proc, closure );
|
||||
}
|
||||
|
||||
|
|
|
@ -157,6 +157,7 @@ cmdToStr( XWRELAY_Cmd cmd )
|
|||
CASESTR(XWRELAY_NONE);
|
||||
CASESTR(XWRELAY_GAME_CONNECT);
|
||||
CASESTR(XWRELAY_GAME_RECONNECT);
|
||||
CASESTR(XWRELAY_ACK);
|
||||
CASESTR(XWRELAY_GAME_DISCONNECT);
|
||||
CASESTR(XWRELAY_CONNECT_RESP);
|
||||
CASESTR(XWRELAY_RECONNECT_RESP);
|
||||
|
@ -393,6 +394,19 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
|
|||
return success;
|
||||
} /* processReconnect */
|
||||
|
||||
static bool
|
||||
processAck( unsigned char* bufp, int bufLen, int socket )
|
||||
{
|
||||
bool success = false;
|
||||
unsigned char* end = bufp + bufLen;
|
||||
HostID srcID;
|
||||
if ( getNetByte( &bufp, end, &srcID ) ) {
|
||||
SafeCref scr( socket );
|
||||
success = scr.HandleAck( srcID );
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
static bool
|
||||
processDisconnect( unsigned char* bufp, int bufLen, int socket )
|
||||
{
|
||||
|
@ -480,6 +494,9 @@ processMessage( unsigned char* buf, int bufLen, int socket )
|
|||
case XWRELAY_GAME_RECONNECT:
|
||||
success = processReconnect( buf+1, bufLen-1, socket );
|
||||
break;
|
||||
case XWRELAY_ACK:
|
||||
success = processAck( buf+1, bufLen-1, socket );
|
||||
break;
|
||||
case XWRELAY_GAME_DISCONNECT:
|
||||
success = processDisconnect( buf+1, bufLen-1, socket );
|
||||
break;
|
||||
|
|
|
@ -44,6 +44,8 @@ enum { XWRELAY_NONE /* 0 is an illegal value */
|
|||
cookieLen: 1; cookie: <cookieLen>; hostID: 1; nPlayers: 1;
|
||||
nPlayersTotal: 1; connNameLen: 1; connName<connNameLen>*/
|
||||
|
||||
, XWRELAY_ACK
|
||||
|
||||
, 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.
|
||||
|
|
Loading…
Add table
Reference in a new issue