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:
Andy2 2010-09-14 13:54:52 -07:00
parent f8c1c016cc
commit 821e4d9c39
9 changed files with 174 additions and 14 deletions

View file

@ -1079,6 +1079,12 @@ sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
return result; return result;
} /* sendMsg */ } /* sendMsg */
static void
send_ack( CommsCtxt* comms )
{
send_via_relay( comms, XWRELAY_ACK, comms->r.myHostID, NULL, 0 );
}
XP_S16 XP_S16
comms_resendAll( CommsCtxt* comms ) comms_resendAll( CommsCtxt* comms )
{ {
@ -1190,6 +1196,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
case XWRELAY_CONNECT_RESP: case XWRELAY_CONNECT_RESP:
got_connect_cmd( comms, stream, XP_FALSE ); got_connect_cmd( comms, stream, XP_FALSE );
send_ack( comms );
break; break;
case XWRELAY_RECONNECT_RESP: case XWRELAY_RECONNECT_RESP:
got_connect_cmd( comms, stream, XP_TRUE ); 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 ); set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
break; break;
case XWRELAY_ACK:
stream_putU8( tmpStream, destID );
break;
case XWRELAY_GAME_DISCONNECT: case XWRELAY_GAME_DISCONNECT:
stream_putU16( tmpStream, comms->r.cookieID ); stream_putU16( tmpStream, comms->r.cookieID );
stream_putU8( tmpStream, comms->r.myHostID ); stream_putU8( tmpStream, comms->r.myHostID );

View file

@ -97,6 +97,7 @@ CookieRef::ReInit( const char* cookie, const char* connName, CookieID id,
m_nHostMsgs = 0; m_nHostMsgs = 0;
m_in_handleEvents = false; m_in_handleEvents = false;
m_langCode = langCode; m_langCode = langCode;
m_nPendingAcks = 0;
if ( RelayConfigs::GetConfigs()->GetValueFor( "SEND_DELAY_MILLIS", if ( RelayConfigs::GetConfigs()->GetValueFor( "SEND_DELAY_MILLIS",
&m_delayMicros ) ) { &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 void
CookieRef::_Disconnect( int socket, HostID hostID ) CookieRef::_Disconnect( int socket, HostID hostID )
{ {
@ -557,9 +569,21 @@ CookieRef::handleEvents()
if ( increasePlayerCounts( &evt, false ) ) { if ( increasePlayerCounts( &evt, false ) ) {
setAllConnectedTimer(); setAllConnectedTimer();
sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP ); sendResponse( &evt, takeAction != XWA_SEND_1ST_RERSP );
postCheckAllHere(); setAckTimer();
} }
break; 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: */ /* case XWA_SEND_1ST_RERSP: */
/* if ( increasePlayerCounts( &evt, false ) ) { */ /* if ( increasePlayerCounts( &evt, false ) ) { */
/* setAllConnectedTimer(); */ /* setAllConnectedTimer(); */
@ -753,6 +777,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
int socket = evt->u.con.socket; int socket = evt->u.con.socket;
int seed = evt->u.con.seed; int seed = evt->u.con.seed;
bool addHost = false; bool addHost = false;
bool addAck = false;
/* XW_RELAY_EVENT newEvt = XWE_NONE; */ /* XW_RELAY_EVENT newEvt = XWE_NONE; */
assert( m_nPlayersSought > 0 ); assert( m_nPlayersSought > 0 );
@ -790,8 +815,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
} else { /* a host; init values */ } else { /* a host; init values */
m_nPlayersHere += nPlayersH; m_nPlayersHere += nPlayersH;
assert( m_nPlayersHere <= m_nPlayersSought ); assert( m_nPlayersHere <= m_nPlayersSought );
addHost = true; addAck = true;
DBMgr::Get()->AddPlayers( ConnName(), nPlayersH ); DBMgr::Get()->AddPlayers( ConnName(), nPlayersH );
/* if ( m_nPlayersHere == m_nPlayersSought ) { /\* complete! *\/ */ /* 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__ ); */ /* logf( XW_LOGERROR, "%s: not pushing an event", __func__ ); */
/* } */ /* } */
if ( addHost ) { if ( addHost || addAck ) {
HostID hostid = evt->u.con.srcID; HostID hostid = evt->u.con.srcID;
/* first add the rec here, whether it'll stay for not */ /* first add the rec here, whether it'll stay for not */
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, " logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, "
"socket=%d (size=%d)", "socket=%d (size=%d)",
__func__, hostid, socket, m_sockets.size()); __func__, hostid, socket, m_sockets.size());
HostRec hr( hostid, socket, nPlayersH, seed ); HostRec hr( hostid, socket, nPlayersH, seed, addAck );
m_sockets.push_back( hr ); m_sockets.push_back( hr );
assert( !AlreadyHere( evt->u.con.seed, -1 ) ); assert( !AlreadyHere( evt->u.con.seed, -1 ) );
@ -843,9 +867,28 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt, bool reconn )
assert( 0 ); assert( 0 );
} }
drop: drop:
return addHost; return addHost || addAck;
} /* increasePlayerCounts */ } /* 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 void
CookieRef::postCheckAllHere() 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 void
CookieRef::cancelAllConnectedTimer() CookieRef::cancelAllConnectedTimer()
{ {
@ -1224,6 +1287,14 @@ CookieRef::s_checkAllConnected( void* closure )
scr.CheckAllConnected(); scr.CheckAllConnected();
} }
/* static */ void
CookieRef::s_checkAck( void* closure )
{
CookieRef* self = (CookieRef*)closure;
SafeCref scr(self);
scr.CheckNotAcked();
}
void void
CookieRef::_CheckAllConnected() CookieRef::_CheckAllConnected()
{ {
@ -1234,6 +1305,17 @@ CookieRef::_CheckAllConnected()
handleEvents(); 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 void
CookieRef::logf( XW_LogLevel level, const char* format, ... ) CookieRef::logf( XW_LogLevel level, const char* format, ... )

View file

@ -39,13 +39,14 @@ using namespace std;
class CookieMapIterator; /* forward */ class CookieMapIterator; /* forward */
struct HostRec { struct HostRec {
public: public:
HostRec(HostID hostID, int socket, int nPlayersH, int seed ) HostRec(HostID hostID, int socket, int nPlayersH, int seed, bool ackPending )
: m_hostID(hostID) : m_hostID(hostID)
, m_socket(socket) , m_socket(socket)
, m_nPlayersH(nPlayersH) , m_nPlayersH(nPlayersH)
, m_seed(seed) , m_seed(seed)
, m_lastHeartbeat(uptime()) , m_lastHeartbeat(uptime())
, m_ackPending(ackPending)
{ {
::logf( XW_LOGINFO, "created HostRec with id %d", m_hostID); ::logf( XW_LOGINFO, "created HostRec with id %d", m_hostID);
} }
@ -54,6 +55,7 @@ struct HostRec {
int m_nPlayersH; int m_nPlayersH;
int m_seed; int m_seed;
time_t m_lastHeartbeat; time_t m_lastHeartbeat;
bool m_ackPending;
}; };
class CookieRef { class CookieRef {
@ -110,6 +112,7 @@ class CookieRef {
bool _Connect( int socket, 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, void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersS,
int seed ); int seed );
void _HandleAck( HostID hostID );
void _Disconnect(int socket, HostID hostID ); void _Disconnect(int socket, HostID hostID );
void _Shutdown(); void _Shutdown();
void _HandleHeartbeat( HostID id, int socket ); void _HandleHeartbeat( HostID id, int socket );
@ -117,6 +120,7 @@ class CookieRef {
void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen ); void _Forward( HostID src, HostID dest, unsigned char* buf, int buflen );
void _Remove( int socket ); void _Remove( int socket );
void _CheckAllConnected(); void _CheckAllConnected();
void _CheckNotAcked();
bool ShouldDie() { return m_curState == XWS_DEAD; } bool ShouldDie() { return m_curState == XWS_DEAD; }
XW_RELAY_STATE CurState() { return m_curState; } XW_RELAY_STATE CurState() { return m_curState; }
@ -142,6 +146,9 @@ class CookieRef {
int seed; int seed;
HostID srcID; HostID srcID;
} con; } con;
struct {
HostID srcID;
} ack;
struct { struct {
int socket; int socket;
HostID srcID; HostID srcID;
@ -194,6 +201,8 @@ class CookieRef {
void sendAnyStored( const CRefEvent* evt ); void sendAnyStored( const CRefEvent* evt );
void initPlayerCounts( const CRefEvent* evt ); void initPlayerCounts( const CRefEvent* evt );
bool increasePlayerCounts( const CRefEvent* evt, bool reconn ); bool increasePlayerCounts( const CRefEvent* evt, bool reconn );
void modPending( const CRefEvent* evt, bool keep );
void postCheckAllHere(); void postCheckAllHere();
bool hostAlreadyHere( int seed, int socket ); bool hostAlreadyHere( int seed, int socket );
@ -201,6 +210,8 @@ class CookieRef {
void setAllConnectedTimer(); void setAllConnectedTimer();
void cancelAllConnectedTimer(); void cancelAllConnectedTimer();
void setAckTimer();
void cancelAckTimer();
void forward_or_store( const CRefEvent* evt ); void forward_or_store( const CRefEvent* evt );
void send_denied( const CRefEvent* evt, XWREASON why ); void send_denied( const CRefEvent* evt, XWREASON why );
@ -235,6 +246,7 @@ class CookieRef {
/* timer callback */ /* timer callback */
static void s_checkAllConnected( void* closure ); static void s_checkAllConnected( void* closure );
static void s_checkAck( void* closure );
unsigned int m_nHostMsgs; unsigned int m_nHostMsgs;
MsgBufQueue m_hostMsgQueues[4]; MsgBufQueue m_hostMsgQueues[4];
@ -262,12 +274,12 @@ class CookieRef {
int m_langCode; int m_langCode;
time_t m_starttime; time_t m_starttime;
int m_nPendingAcks;
pthread_mutex_t m_mutex; pthread_mutex_t m_mutex;
pthread_t m_locking_thread; /* for debugging only */ pthread_t m_locking_thread; /* for debugging only */
bool m_in_handleEvents; /* for debugging only */ bool m_in_handleEvents; /* for debugging only */
int m_delayMicros; int m_delayMicros;
vector<unsigned short> m_seeds; vector<unsigned short> m_seeds;
}; /* CookieRef */ }; /* CookieRef */

View file

@ -225,6 +225,14 @@ class SafeCref {
m_cref->_Disconnect( socket, hostID ); m_cref->_Disconnect( socket, hostID );
} }
} }
bool HandleAck(HostID hostID ) {
if ( IsValid() ) {
m_cref->_HandleAck( hostID );
return true;
} else {
return false;
}
}
void Shutdown() { void Shutdown() {
if ( IsValid() ) { if ( IsValid() ) {
m_cref->_Shutdown(); m_cref->_Shutdown();
@ -262,6 +270,11 @@ class SafeCref {
m_cref->_CheckAllConnected(); m_cref->_CheckAllConnected();
} }
} }
void CheckNotAcked() {
if ( IsValid() ) {
m_cref->_CheckNotAcked();
}
}
const char* Cookie() { const char* Cookie() {
if ( IsValid() ) { if ( IsValid() ) {
return m_cref->Cookie(); return m_cref->Cookie();

View file

@ -62,11 +62,14 @@ typedef struct StateTable {
static StateTable g_stateTable[] = { static StateTable g_stateTable[] = {
{ XWS_INITED, 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_CHK_ALLHERE }, { 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_WAITMORE, XWE_RECONNECT, XWA_SEND_RERSP, XWS_WAITMORE },
{ XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND }, { XWS_ALLCONND, XWE_RECONNECT, XWA_SEND_RERSP, XWS_ALLCONND },
/* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */ /* { XWS_WAITMORE, XWE_GAMEFULL, XWA_SENDALLHERE, XWS_ALLCONND }, */
@ -173,6 +176,7 @@ stateString( XW_RELAY_STATE state )
CASESTR(XWS_ANY); CASESTR(XWS_ANY);
CASESTR(XWS_INITED); CASESTR(XWS_INITED);
CASESTR(XWS_WAITMORE); CASESTR(XWS_WAITMORE);
CASESTR(XWS_WAITING_ACKS);
CASESTR(XWS_ALLCONND); CASESTR(XWS_ALLCONND);
CASESTR(XWS_DEAD); CASESTR(XWS_DEAD);
CASESTR(XWS_MISSING); CASESTR(XWS_MISSING);
@ -199,6 +203,9 @@ eventString( XW_RELAY_EVENT evt )
CASESTR(XWE_NONE); CASESTR(XWE_NONE);
CASESTR(XWE_DEVCONNECT); CASESTR(XWE_DEVCONNECT);
CASESTR(XWE_RECONNECT); CASESTR(XWE_RECONNECT);
CASESTR(XWE_GOTONEACK);
CASESTR(XWE_GOTLASTACK);
CASESTR(XWE_ACKTIMEOUT);
CASESTR(XWE_DISCONN); CASESTR(XWE_DISCONN);
CASESTR(XWE_FORWARDMSG); CASESTR(XWE_FORWARDMSG);
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
@ -236,6 +243,10 @@ actString( XW_RELAY_ACTION act )
CASESTR(XWA_SEND_DUP_ROOM); CASESTR(XWA_SEND_DUP_ROOM);
CASESTR(XWA_SEND_INITRSP); CASESTR(XWA_SEND_INITRSP);
CASESTR(XWA_SEND_CONNRSP); CASESTR(XWA_SEND_CONNRSP);
CASESTR(XWA_NOTEACK);
CASESTR(XWA_NOTEACKCHECK);
/* CASESTR(XWA_ADDDEVICE); */
CASESTR(XWA_DROPDEVICE);
CASESTR(XWA_SNDALLHERE_2); CASESTR(XWA_SNDALLHERE_2);
CASESTR(XWA_FWD); CASESTR(XWA_FWD);
CASESTR(XWA_NOTEHEART); CASESTR(XWA_NOTEHEART);

View file

@ -32,7 +32,7 @@ enum {
are here. Success should be an error, are here. Success should be an error,
actually: 1-device game. */ 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 ,XWS_CHK_ALLHERE /* Need to see if all expected devices/players
are on board. */ are on board. */
@ -83,6 +83,10 @@ typedef enum {
,XWE_RECONNECT /* A device is re-connecting using the connID for ,XWE_RECONNECT /* A device is re-connecting using the connID for
this object */ this object */
,XWE_GOTONEACK
,XWE_GOTLASTACK
,XWE_ACKTIMEOUT
,XWE_DISCONN /* disconnect socket from this game/cref */ ,XWE_DISCONN /* disconnect socket from this game/cref */
,XWE_FORWARDMSG /* A message needs forwarding */ ,XWE_FORWARDMSG /* A message needs forwarding */
@ -116,10 +120,17 @@ typedef enum {
,XWA_SEND_DUP_ROOM /* host comes in while game open */ ,XWA_SEND_DUP_ROOM /* host comes in while game open */
,XWA_SEND_NO_ROOM /* guest comes in when no game open */ ,XWA_SEND_NO_ROOM /* guest comes in when no game open */
,XWA_SEND_TOO_MANY ,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_INITRSP /* response to first to connect */
,XWA_SEND_CONNRSP /* response to rest that connect */ ,XWA_SEND_CONNRSP /* response to rest that connect */
,XWA_SEND_RERSP ,XWA_SEND_RERSP
,XWA_GOTALLACKS
,XWA_CHECK_HAVE_ROOM /* check for number of players still sought */ ,XWA_CHECK_HAVE_ROOM /* check for number of players still sought */

View file

@ -57,6 +57,7 @@ TimerMgr::SetTimer( time_t inMillis, TimerProc proc, void* closure,
MutexLock ml( &m_timersMutex ); MutexLock ml( &m_timersMutex );
if ( getTimer( proc, closure ) ) { if ( getTimer( proc, closure ) ) {
logf( XW_LOGINFO, "%s: clearing old timer", __func__ );
clearTimerImpl( proc, closure ); clearTimerImpl( proc, closure );
} }

View file

@ -157,6 +157,7 @@ cmdToStr( XWRELAY_Cmd cmd )
CASESTR(XWRELAY_NONE); CASESTR(XWRELAY_NONE);
CASESTR(XWRELAY_GAME_CONNECT); CASESTR(XWRELAY_GAME_CONNECT);
CASESTR(XWRELAY_GAME_RECONNECT); CASESTR(XWRELAY_GAME_RECONNECT);
CASESTR(XWRELAY_ACK);
CASESTR(XWRELAY_GAME_DISCONNECT); CASESTR(XWRELAY_GAME_DISCONNECT);
CASESTR(XWRELAY_CONNECT_RESP); CASESTR(XWRELAY_CONNECT_RESP);
CASESTR(XWRELAY_RECONNECT_RESP); CASESTR(XWRELAY_RECONNECT_RESP);
@ -393,6 +394,19 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
return success; return success;
} /* processReconnect */ } /* 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 static bool
processDisconnect( unsigned char* bufp, int bufLen, int socket ) processDisconnect( unsigned char* bufp, int bufLen, int socket )
{ {
@ -480,6 +494,9 @@ processMessage( unsigned char* buf, int bufLen, int socket )
case XWRELAY_GAME_RECONNECT: case XWRELAY_GAME_RECONNECT:
success = processReconnect( buf+1, bufLen-1, socket ); success = processReconnect( buf+1, bufLen-1, socket );
break; break;
case XWRELAY_ACK:
success = processAck( buf+1, bufLen-1, socket );
break;
case XWRELAY_GAME_DISCONNECT: case XWRELAY_GAME_DISCONNECT:
success = processDisconnect( buf+1, bufLen-1, socket ); success = processDisconnect( buf+1, bufLen-1, socket );
break; break;

View file

@ -44,6 +44,8 @@ enum { XWRELAY_NONE /* 0 is an illegal value */
cookieLen: 1; cookie: <cookieLen>; hostID: 1; nPlayers: 1; cookieLen: 1; cookie: <cookieLen>; hostID: 1; nPlayers: 1;
nPlayersTotal: 1; connNameLen: 1; connName<connNameLen>*/ nPlayersTotal: 1; connNameLen: 1; connName<connNameLen>*/
, XWRELAY_ACK
, XWRELAY_GAME_DISCONNECT , XWRELAY_GAME_DISCONNECT
/* Tell the relay that we're gone for this game. After this message is /* 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. sent, the host can reconnect on the same socket for a new game.