mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-28 07:58:08 +01:00
Fix problems reconnecting hosts where some but not all received the
ALLHERE message and connName: change relay protocol so cookie is included in RECONNECT message, and hostIDs are not assigned until ALLHERE, and change host-to-game matching to use connName first but fall back to cookie. This fixes nearly all cases failing to reconnect after relay goes down.
This commit is contained in:
parent
f5f5df990e
commit
dbf9daf71b
8 changed files with 313 additions and 208 deletions
|
@ -87,7 +87,8 @@ typedef enum {
|
||||||
struct CommsCtxt {
|
struct CommsCtxt {
|
||||||
XW_UtilCtxt* util;
|
XW_UtilCtxt* util;
|
||||||
|
|
||||||
XP_U32 connID; /* 0 means ignore; otherwise must match */
|
XP_U32 connID; /* set from gameID: 0 means ignore; otherwise
|
||||||
|
must match. Set by server. */
|
||||||
XP_PlayerAddr nextChannelNo;
|
XP_PlayerAddr nextChannelNo;
|
||||||
|
|
||||||
AddressRecord* recs; /* return addresses */
|
AddressRecord* recs; /* return addresses */
|
||||||
|
@ -136,6 +137,7 @@ struct CommsCtxt {
|
||||||
XP_U16 nPlayersHere;
|
XP_U16 nPlayersHere;
|
||||||
XP_U16 nPlayersTotal;
|
XP_U16 nPlayersTotal;
|
||||||
XP_Bool connecting;
|
XP_Bool connecting;
|
||||||
|
XP_Bool connNameValid; /* this can probably go. PENDING */
|
||||||
} r;
|
} r;
|
||||||
|
|
||||||
XP_Bool isServer;
|
XP_Bool isServer;
|
||||||
|
@ -195,16 +197,47 @@ static XP_S16 send_via_bt_or_ip( CommsCtxt* comms, BTIPMsgType typ,
|
||||||
* implementation
|
* implementation
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
#ifdef XWFEATURE_RELAY
|
#ifdef XWFEATURE_RELAY
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
static const char*
|
||||||
|
CommsRelayState2Str( CommsRelayState state )
|
||||||
|
{
|
||||||
|
#define CASE_STR(s) case s: return #s
|
||||||
|
switch( state ) {
|
||||||
|
CASE_STR(COMMS_RELAYSTATE_UNCONNECTED);
|
||||||
|
CASE_STR(COMMS_RELAYSTATE_CONNECT_PENDING);
|
||||||
|
CASE_STR(COMMS_RELAYSTATE_CONNECTED);
|
||||||
|
CASE_STR(COMMS_RELAYSTATE_ALLCONNECTED);
|
||||||
|
default:
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
#undef CASE_STR
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void
|
||||||
|
set_relay_state( CommsCtxt* comms, CommsRelayState state )
|
||||||
|
{
|
||||||
|
if ( comms->r.relayState != state ) {
|
||||||
|
XP_LOGF( "%s: %s => %s", __func__,
|
||||||
|
CommsRelayState2Str(comms->r.relayState),
|
||||||
|
CommsRelayState2Str(state) );
|
||||||
|
comms->r.relayState = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_relay( CommsCtxt* comms, XP_U16 nPlayersHere, XP_U16 nPlayersTotal )
|
init_relay( CommsCtxt* comms, XP_U16 nPlayersHere, XP_U16 nPlayersTotal )
|
||||||
{
|
{
|
||||||
comms->r.myHostID = comms->isServer? HOST_ID_SERVER: HOST_ID_NONE;
|
comms->r.myHostID = comms->isServer? HOST_ID_SERVER: HOST_ID_NONE;
|
||||||
XP_LOGF( "%s: set myHostID to %d", __func__, comms->r.myHostID );
|
XP_LOGF( "%s: set myHostID to %d", __func__, comms->r.myHostID );
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_UNCONNECTED );
|
||||||
comms->r.nPlayersHere = nPlayersHere;
|
comms->r.nPlayersHere = nPlayersHere;
|
||||||
comms->r.nPlayersTotal = nPlayersTotal;
|
comms->r.nPlayersTotal = nPlayersTotal;
|
||||||
comms->r.cookieID = COOKIE_ID_NONE;
|
comms->r.cookieID = COOKIE_ID_NONE;
|
||||||
comms->r.connName[0] = '\0';
|
comms->r.connName[0] = '\0';
|
||||||
|
comms->r.connNameValid = XP_FALSE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -350,7 +383,7 @@ comms_setConnID( CommsCtxt* comms, XP_U32 connID )
|
||||||
{
|
{
|
||||||
XP_ASSERT( CONN_ID_NONE != connID );
|
XP_ASSERT( CONN_ID_NONE != connID );
|
||||||
comms->connID = connID;
|
comms->connID = connID;
|
||||||
XP_STATUSF( "%s: set connID to %lx", __func__, connID );
|
XP_STATUSF( "%s: set connID (gameID) to %lx", __func__, connID );
|
||||||
} /* comms_setConnID */
|
} /* comms_setConnID */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -437,9 +470,12 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
|
||||||
comms->nextChannelNo = stream_getU16( stream );
|
comms->nextChannelNo = stream_getU16( stream );
|
||||||
if ( addr.conType == COMMS_CONN_RELAY ) {
|
if ( addr.conType == COMMS_CONN_RELAY ) {
|
||||||
comms->r.myHostID = stream_getU8( stream );
|
comms->r.myHostID = stream_getU8( stream );
|
||||||
|
comms->r.connNameValid = stream_getU8( stream );
|
||||||
|
if ( comms->r.connNameValid ) {
|
||||||
stringFromStreamHere( stream, comms->r.connName,
|
stringFromStreamHere( stream, comms->r.connName,
|
||||||
sizeof(comms->r.connName) );
|
sizeof(comms->r.connName) );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
comms->nUniqueBytes = stream_getU16( stream );
|
comms->nUniqueBytes = stream_getU16( stream );
|
||||||
|
@ -528,7 +564,7 @@ sendConnect( CommsCtxt* comms, XP_Bool breakExisting )
|
||||||
case COMMS_CONN_RELAY:
|
case COMMS_CONN_RELAY:
|
||||||
if ( breakExisting
|
if ( breakExisting
|
||||||
|| COMMS_RELAYSTATE_UNCONNECTED == comms->r.relayState ) {
|
|| COMMS_RELAYSTATE_UNCONNECTED == comms->r.relayState ) {
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_UNCONNECTED );
|
||||||
relayConnect( comms );
|
relayConnect( comms );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -608,8 +644,11 @@ comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream )
|
||||||
stream_putU16( stream, comms->nextChannelNo );
|
stream_putU16( stream, comms->nextChannelNo );
|
||||||
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
||||||
stream_putU8( stream, comms->r.myHostID );
|
stream_putU8( stream, comms->r.myHostID );
|
||||||
|
stream_putU8( stream, comms->r.connNameValid );
|
||||||
|
if ( comms->r.connNameValid ) {
|
||||||
stringToStream( stream, comms->r.connName );
|
stringToStream( stream, comms->r.connName );
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
stream_putU16( stream, comms->nUniqueBytes );
|
stream_putU16( stream, comms->nUniqueBytes );
|
||||||
|
@ -1043,17 +1082,20 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
||||||
|
|
||||||
case XWRELAY_CONNECT_RESP:
|
case XWRELAY_CONNECT_RESP:
|
||||||
case XWRELAY_RECONNECT_RESP:
|
case XWRELAY_RECONNECT_RESP:
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_CONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_CONNECTED );
|
||||||
comms->r.heartbeat = stream_getU16( stream );
|
comms->r.heartbeat = stream_getU16( stream );
|
||||||
comms->r.cookieID = stream_getU16( stream );
|
comms->r.cookieID = stream_getU16( stream );
|
||||||
comms->r.myHostID = (XWHostID)stream_getU8( stream );
|
XP_LOGF( "set cookieID = %d", comms->r.cookieID );
|
||||||
XP_LOGF( "set cookieID = %d; set hostid: %x",
|
|
||||||
comms->r.cookieID, comms->r.myHostID );
|
|
||||||
setHeartbeatTimer( comms );
|
setHeartbeatTimer( comms );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XWRELAY_ALLHERE:
|
case XWRELAY_ALLHERE:
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_ALLCONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_ALLCONNECTED );
|
||||||
|
srcID = (XWHostID)stream_getU8( stream );
|
||||||
|
XP_ASSERT( comms->r.myHostID == HOST_ID_NONE
|
||||||
|
|| comms->r.myHostID == srcID );
|
||||||
|
comms->r.myHostID = srcID;
|
||||||
|
XP_LOGF( "set hostid: %x", comms->r.myHostID );
|
||||||
hasName = stream_getU8( stream );
|
hasName = stream_getU8( stream );
|
||||||
if ( hasName ) {
|
if ( hasName ) {
|
||||||
stringFromStreamHere( stream, comms->r.connName,
|
stringFromStreamHere( stream, comms->r.connName,
|
||||||
|
@ -1081,6 +1123,10 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
||||||
XP_LOGF( "%s: rejecting data message", __func__ );
|
XP_LOGF( "%s: rejecting data message", __func__ );
|
||||||
} else {
|
} else {
|
||||||
*senderID = srcID;
|
*senderID = srcID;
|
||||||
|
if ( !comms->r.connNameValid ) {
|
||||||
|
XP_LOGF( "%s: setting connNameValid", __func__ );
|
||||||
|
comms->r.connNameValid = XP_TRUE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1096,7 +1142,7 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
||||||
case XWRELAY_CONNECTDENIED: /* Close socket for this? */
|
case XWRELAY_CONNECTDENIED: /* Close socket for this? */
|
||||||
relayErr = stream_getU8( stream );
|
relayErr = stream_getU8( stream );
|
||||||
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
|
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_UNCONNECTED );
|
||||||
/* fallthru */
|
/* fallthru */
|
||||||
default:
|
default:
|
||||||
XP_LOGF( "%s: dropping relay msg with cmd %d", __func__, (XP_U16)cmd );
|
XP_LOGF( "%s: dropping relay msg with cmd %d", __func__, (XP_U16)cmd );
|
||||||
|
@ -1202,7 +1248,7 @@ getRecordFor( CommsCtxt* comms, const CommsAddrRec* addr,
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_IR: /* no way to test */
|
case COMMS_CONN_IR: /* no way to test */
|
||||||
break;
|
break;
|
||||||
case COMMS_CONN_SMS: /* no way to test */
|
case COMMS_CONN_SMS:
|
||||||
if ( ( 0 == XP_MEMCMP( &addr->u.sms.phone, &rec->addr.u.sms.phone,
|
if ( ( 0 == XP_MEMCMP( &addr->u.sms.phone, &rec->addr.u.sms.phone,
|
||||||
sizeof(addr->u.sms.phone) ) )
|
sizeof(addr->u.sms.phone) ) )
|
||||||
&& addr->u.sms.port == rec->addr.u.sms.port ) {
|
&& addr->u.sms.port == rec->addr.u.sms.port ) {
|
||||||
|
@ -1326,7 +1372,7 @@ validateChannelMessage( CommsCtxt* comms, const CommsAddrRec* addr,
|
||||||
rec = NULL;
|
rec = NULL;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
XP_LOGF( "%s: no rec for addr", __func__ );
|
XP_LOGF( "%s: no rec for channelNo %d", __func__, channelNo );
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_RETURNF( XP_P, rec );
|
LOG_RETURNF( XP_P, rec );
|
||||||
|
@ -1337,7 +1383,7 @@ XP_Bool
|
||||||
comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
const CommsAddrRec* retAddr )
|
const CommsAddrRec* retAddr )
|
||||||
{
|
{
|
||||||
XP_Bool validMessage = XP_FALSE;
|
XP_Bool messageValid = XP_FALSE;
|
||||||
XWHostID senderID = 0; /* unset; default for non-relay cases */
|
XWHostID senderID = 0; /* unset; default for non-relay cases */
|
||||||
XP_Bool usingRelay = XP_FALSE;
|
XP_Bool usingRelay = XP_FALSE;
|
||||||
AddressRecord* rec = NULL;
|
AddressRecord* rec = NULL;
|
||||||
|
@ -1357,15 +1403,15 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
XP_U16 payloadSize;
|
XP_U16 payloadSize;
|
||||||
|
|
||||||
connID = stream_getU32( stream );
|
connID = stream_getU32( stream );
|
||||||
XP_STATUSF( "%s: read connID of %lx", __func__, connID );
|
XP_STATUSF( "%s: read connID (gameID) of %lx", __func__, connID );
|
||||||
channelNo = stream_getU16( stream );
|
channelNo = stream_getU16( stream );
|
||||||
XP_STATUSF( "read channelNo %d", channelNo );
|
|
||||||
msgID = stream_getU32( stream );
|
msgID = stream_getU32( stream );
|
||||||
lastMsgRcd = stream_getU32( stream );
|
lastMsgRcd = stream_getU32( stream );
|
||||||
XP_DEBUGF( "rcd: msgID=" XP_LD ",lastMsgRcd=" XP_LD " on chnl %d",
|
XP_DEBUGF( "rcd on channelNo %d: msgID=%ld,lastMsgRcd=%ld ",
|
||||||
msgID, lastMsgRcd, channelNo );
|
channelNo, msgID, lastMsgRcd );
|
||||||
|
|
||||||
payloadSize = stream_getSize( stream ) > 0; /* anything left? */
|
payloadSize = stream_getSize( stream ) > 0; /* anything left? */
|
||||||
|
|
||||||
if ( connID == CONN_ID_NONE ) {
|
if ( connID == CONN_ID_NONE ) {
|
||||||
/* special case: initial message from client */
|
/* special case: initial message from client */
|
||||||
rec = validateInitialMessage( comms, payloadSize > 0, retAddr,
|
rec = validateInitialMessage( comms, payloadSize > 0, retAddr,
|
||||||
|
@ -1375,13 +1421,13 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
lastMsgRcd );
|
lastMsgRcd );
|
||||||
}
|
}
|
||||||
|
|
||||||
validMessage = NULL != rec;
|
messageValid = NULL != rec;
|
||||||
if ( validMessage ) {
|
if ( messageValid ) {
|
||||||
rec->lastMsgRcd = msgID;
|
rec->lastMsgRcd = msgID;
|
||||||
XP_LOGF( "%s: set channel %d's lastMsgRcd to " XP_LD,
|
XP_LOGF( "%s: set channel %d's lastMsgRcd to " XP_LD,
|
||||||
__func__, channelNo, msgID );
|
__func__, channelNo, msgID );
|
||||||
stream_setAddress( stream, channelNo );
|
stream_setAddress( stream, channelNo );
|
||||||
validMessage = payloadSize > 0;
|
messageValid = payloadSize > 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
XP_LOGF( "%s: message too small", __func__ );
|
XP_LOGF( "%s: message too small", __func__ );
|
||||||
|
@ -1391,8 +1437,8 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
||||||
/* Call after we've had a chance to create rec for addr */
|
/* Call after we've had a chance to create rec for addr */
|
||||||
noteHBReceived( comms/* , addr */ );
|
noteHBReceived( comms/* , addr */ );
|
||||||
|
|
||||||
LOG_RETURNF( "%d", (XP_U16)validMessage );
|
LOG_RETURNF( "%d", (XP_U16)messageValid );
|
||||||
return validMessage;
|
return messageValid;
|
||||||
} /* comms_checkIncomingStream */
|
} /* comms_checkIncomingStream */
|
||||||
|
|
||||||
#ifdef COMMS_HEARTBEAT
|
#ifdef COMMS_HEARTBEAT
|
||||||
|
@ -1680,17 +1726,18 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
||||||
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
||||||
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
||||||
|
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_CONNECT_PENDING;
|
set_relay_state( comms,COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XWRELAY_GAME_RECONNECT:
|
case XWRELAY_GAME_RECONNECT:
|
||||||
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
||||||
|
stringToStream( tmpStream, addr.u.ip_relay.cookie );
|
||||||
stream_putU8( tmpStream, comms->r.myHostID );
|
stream_putU8( tmpStream, comms->r.myHostID );
|
||||||
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
||||||
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
||||||
stringToStream( tmpStream, comms->r.connName );
|
stringToStream( tmpStream, comms->r.connName );
|
||||||
|
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_CONNECT_PENDING;
|
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case XWRELAY_GAME_DISCONNECT:
|
case XWRELAY_GAME_DISCONNECT:
|
||||||
|
@ -1741,9 +1788,8 @@ relayConnect( CommsCtxt* comms )
|
||||||
LOG_FUNC();
|
LOG_FUNC();
|
||||||
if ( comms->addr.conType == COMMS_CONN_RELAY && !comms->r.connecting ) {
|
if ( comms->addr.conType == COMMS_CONN_RELAY && !comms->r.connecting ) {
|
||||||
comms->r.connecting = XP_TRUE;
|
comms->r.connecting = XP_TRUE;
|
||||||
success = send_via_relay( comms,
|
success = send_via_relay( comms, comms->r.connNameValid?
|
||||||
comms->r.connName[0] == '\0' ?
|
XWRELAY_GAME_RECONNECT : XWRELAY_GAME_CONNECT,
|
||||||
XWRELAY_GAME_CONNECT:XWRELAY_GAME_RECONNECT,
|
|
||||||
comms->r.myHostID, NULL, 0 );
|
comms->r.myHostID, NULL, 0 );
|
||||||
comms->r.connecting = XP_FALSE;
|
comms->r.connecting = XP_FALSE;
|
||||||
}
|
}
|
||||||
|
@ -1788,7 +1834,7 @@ relayDisconnect( CommsCtxt* comms )
|
||||||
LOG_FUNC();
|
LOG_FUNC();
|
||||||
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
||||||
if ( comms->r.relayState != COMMS_RELAYSTATE_UNCONNECTED ) {
|
if ( comms->r.relayState != COMMS_RELAYSTATE_UNCONNECTED ) {
|
||||||
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
set_relay_state( comms, COMMS_RELAYSTATE_UNCONNECTED );
|
||||||
send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE,
|
send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE,
|
||||||
NULL, 0 );
|
NULL, 0 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "timermgr.h"
|
#include "timermgr.h"
|
||||||
#include "configs.h"
|
#include "configs.h"
|
||||||
#include "crefmgr.h"
|
#include "crefmgr.h"
|
||||||
|
#include "permid.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -82,7 +83,7 @@ void
|
||||||
CookieRef::ReInit( const char* cookie, const char* connName, CookieID id )
|
CookieRef::ReInit( const char* cookie, const char* connName, CookieID id )
|
||||||
{
|
{
|
||||||
m_cookie = cookie==NULL?"":cookie;
|
m_cookie = cookie==NULL?"":cookie;
|
||||||
m_connName = connName;
|
m_connName = connName==NULL?"":connName;
|
||||||
m_cookieID = id;
|
m_cookieID = id;
|
||||||
m_totalSent = 0;
|
m_totalSent = 0;
|
||||||
m_curState = XWS_INITED;
|
m_curState = XWS_INITED;
|
||||||
|
@ -113,14 +114,9 @@ CookieRef::~CookieRef()
|
||||||
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
||||||
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
for ( ; ; ) {
|
vector<HostRec>::iterator iter;
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
int socket = iter->m_socket;
|
||||||
if ( iter == m_sockets.end() ) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
int socket = iter->second.m_socket;
|
|
||||||
tPool->CloseSocket( socket );
|
tPool->CloseSocket( socket );
|
||||||
m_sockets.erase( iter );
|
m_sockets.erase( iter );
|
||||||
}
|
}
|
||||||
|
@ -175,12 +171,6 @@ void
|
||||||
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
||||||
{
|
{
|
||||||
if ( CRefMgr::Get()->Associate( socket, this ) ) {
|
if ( CRefMgr::Get()->Associate( socket, this ) ) {
|
||||||
if ( hid == HOST_ID_NONE ) {
|
|
||||||
hid = nextHostID();
|
|
||||||
logf( XW_LOGINFO, "assigned host id: %x", hid );
|
|
||||||
} else {
|
|
||||||
logf( XW_LOGINFO, "NOT assigned host id; why?" );
|
|
||||||
}
|
|
||||||
pushConnectEvent( socket, hid, nPlayersH, nPlayersT );
|
pushConnectEvent( socket, hid, nPlayersH, nPlayersT );
|
||||||
handleEvents();
|
handleEvents();
|
||||||
} else {
|
} else {
|
||||||
|
@ -192,7 +182,6 @@ void
|
||||||
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
||||||
{
|
{
|
||||||
(void)CRefMgr::Get()->Associate( socket, this );
|
(void)CRefMgr::Get()->Associate( socket, this );
|
||||||
/* MutexLock ml( &m_EventsMutex ); */
|
|
||||||
pushReconnectEvent( socket, hid, nPlayersH, nPlayersT );
|
pushReconnectEvent( socket, hid, nPlayersH, nPlayersT );
|
||||||
handleEvents();
|
handleEvents();
|
||||||
}
|
}
|
||||||
|
@ -225,14 +214,16 @@ CookieRef::_Shutdown()
|
||||||
int
|
int
|
||||||
CookieRef::SocketForHost( HostID dest )
|
CookieRef::SocketForHost( HostID dest )
|
||||||
{
|
{
|
||||||
int socket;
|
int socket = -1;
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.find( dest );
|
vector<HostRec>::const_iterator iter;
|
||||||
if ( iter == m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
socket = -1;
|
if ( iter->m_hostID == dest ) {
|
||||||
} else {
|
socket = iter->m_socket;
|
||||||
socket = iter->second.m_socket;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logf( XW_LOGVERBOSE0, "returning socket=%d for hostid=%x", socket, dest );
|
logf( XW_LOGVERBOSE0, "returning socket=%d for hostid=%x", socket, dest );
|
||||||
return socket;
|
return socket;
|
||||||
}
|
}
|
||||||
|
@ -250,7 +241,8 @@ CookieRef::NeverFullyConnected()
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CookieRef::AcceptingReconnections( HostID hid, int nPlayersH, int nPlayersT )
|
CookieRef::AcceptingReconnections( HostID hid, const char* cookie,
|
||||||
|
int nPlayersH )
|
||||||
{
|
{
|
||||||
bool accept = false;
|
bool accept = false;
|
||||||
/* First, do we have room. Second, are we missing this guy? */
|
/* First, do we have room. Second, are we missing this guy? */
|
||||||
|
@ -274,6 +266,13 @@ CookieRef::AcceptingReconnections( HostID hid, int nPlayersH, int nPlayersT )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Error to connect if cookie doesn't match. */
|
||||||
|
if ( accept && !!cookie && 0 != strcmp( cookie, Cookie() ) ) {
|
||||||
|
logf( XW_LOGERROR, "%s: not accepting b/c cookie mismatch: %s vs %s",
|
||||||
|
__func__, cookie, Cookie() );
|
||||||
|
accept = false;
|
||||||
|
}
|
||||||
|
|
||||||
return accept;
|
return accept;
|
||||||
} /* AcceptingReconnections */
|
} /* AcceptingReconnections */
|
||||||
|
|
||||||
|
@ -295,19 +294,18 @@ CookieRef::removeSocket( int socket )
|
||||||
logf( XW_LOGINFO, "%s(socket=%d)", __func__, socket );
|
logf( XW_LOGINFO, "%s(socket=%d)", __func__, socket );
|
||||||
int count;
|
int count;
|
||||||
{
|
{
|
||||||
/* RWWriteLock rwl( &m_sockets_rwlock ); */
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
|
|
||||||
count = m_sockets.size();
|
count = m_sockets.size();
|
||||||
assert( count > 0 );
|
assert( count > 0 );
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
|
||||||
while ( iter != m_sockets.end() ) {
|
vector<HostRec>::iterator iter;
|
||||||
if ( iter->second.m_socket == socket ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
if ( iter->m_socket == socket ) {
|
||||||
m_sockets.erase(iter);
|
m_sockets.erase(iter);
|
||||||
--count;
|
--count;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -333,13 +331,12 @@ CookieRef::HasSocket_locked( int socket )
|
||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
if ( iter->second.m_socket == socket ) {
|
if ( iter->m_socket == socket ) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return found;
|
return found;
|
||||||
|
@ -349,7 +346,6 @@ CookieRef::HasSocket_locked( int socket )
|
||||||
void
|
void
|
||||||
CookieRef::_HandleHeartbeat( HostID id, int socket )
|
CookieRef::_HandleHeartbeat( HostID id, int socket )
|
||||||
{
|
{
|
||||||
/* MutexLock ml( &m_EventsMutex ); */
|
|
||||||
pushHeartbeatEvent( id, socket );
|
pushHeartbeatEvent( id, socket );
|
||||||
handleEvents();
|
handleEvents();
|
||||||
} /* HandleHeartbeat */
|
} /* HandleHeartbeat */
|
||||||
|
@ -357,15 +353,14 @@ CookieRef::_HandleHeartbeat( HostID id, int socket )
|
||||||
void
|
void
|
||||||
CookieRef::_CheckHeartbeats( time_t now )
|
CookieRef::_CheckHeartbeats( time_t now )
|
||||||
{
|
{
|
||||||
logf( XW_LOGINFO, "CookieRef::_CheckHeartbeats" );
|
logf( XW_LOGINFO, "%s", __func__ );
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
time_t last = iter->second.m_lastHeartbeat;
|
time_t last = iter->m_lastHeartbeat;
|
||||||
if ( (now - last) > GetHeartbeat() ) {
|
if ( (now - last) > GetHeartbeat() ) {
|
||||||
pushHeartFailedEvent( iter->second.m_socket );
|
pushHeartFailedEvent( iter->m_socket );
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEvents();
|
handleEvents();
|
||||||
|
@ -426,6 +421,7 @@ CookieRef::pushHeartbeatEvent( HostID id, int socket )
|
||||||
void
|
void
|
||||||
CookieRef::pushHeartFailedEvent( int socket )
|
CookieRef::pushHeartFailedEvent( int socket )
|
||||||
{
|
{
|
||||||
|
logf( XW_LOGINFO, "%s", __func__ );
|
||||||
CRefEvent evt;
|
CRefEvent evt;
|
||||||
evt.type = XWE_HEARTFAILED;
|
evt.type = XWE_HEARTFAILED;
|
||||||
evt.u.heart.socket = socket;
|
evt.u.heart.socket = socket;
|
||||||
|
@ -555,6 +551,8 @@ CookieRef::handleEvents()
|
||||||
case XWA_SENDALLHERE:
|
case XWA_SENDALLHERE:
|
||||||
case XWA_SNDALLHERE_2:
|
case XWA_SNDALLHERE_2:
|
||||||
cancelAllConnectedTimer();
|
cancelAllConnectedTimer();
|
||||||
|
assignConnName();
|
||||||
|
assignHostIds();
|
||||||
sendAllHere( takeAction == XWA_SENDALLHERE );
|
sendAllHere( takeAction == XWA_SENDALLHERE );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -607,7 +605,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt )
|
||||||
int nPlayersT = evt->u.con.nPlayersT;
|
int nPlayersT = evt->u.con.nPlayersT;
|
||||||
HostID hid = evt->u.con.srcID;
|
HostID hid = evt->u.con.srcID;
|
||||||
|
|
||||||
logf( XW_LOGVERBOSE1, "increasePlayerCounts: hid=%d, nPlayersH=%d, "
|
logf( XW_LOGINFO, "increasePlayerCounts: hid=%d, nPlayersH=%d, "
|
||||||
"nPlayersT=%d", hid, nPlayersH, nPlayersT );
|
"nPlayersT=%d", hid, nPlayersH, nPlayersT );
|
||||||
|
|
||||||
if ( hid == HOST_ID_SERVER ) {
|
if ( hid == HOST_ID_SERVER ) {
|
||||||
|
@ -633,25 +631,21 @@ CookieRef::reducePlayerCounts( int socket )
|
||||||
{
|
{
|
||||||
logf( XW_LOGVERBOSE1, "reducePlayerCounts on socket %d", socket );
|
logf( XW_LOGVERBOSE1, "reducePlayerCounts on socket %d", socket );
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
if ( iter->m_socket == socket ) {
|
||||||
if ( iter->second.m_socket == socket ) {
|
if ( iter->m_hostID == HOST_ID_SERVER ) {
|
||||||
assert( iter->first != 0 );
|
|
||||||
|
|
||||||
if ( iter->first == HOST_ID_SERVER ) {
|
|
||||||
m_nPlayersSought = 0;
|
m_nPlayersSought = 0;
|
||||||
} else {
|
} else {
|
||||||
assert( iter->second.m_nPlayersT == 0 );
|
assert( iter->m_nPlayersT == 0 );
|
||||||
}
|
}
|
||||||
m_nPlayersHere -= iter->second.m_nPlayersH;
|
m_nPlayersHere -= iter->m_nPlayersH;
|
||||||
|
|
||||||
logf( XW_LOGVERBOSE1, "reducePlayerCounts: m_nPlayersHere=%d; m_nPlayersSought=%d",
|
logf( XW_LOGVERBOSE1, "reducePlayerCounts: m_nPlayersHere=%d; m_nPlayersSought=%d",
|
||||||
m_nPlayersHere, m_nPlayersSought );
|
m_nPlayersHere, m_nPlayersSought );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
} /* reducePlayerCounts */
|
} /* reducePlayerCounts */
|
||||||
|
|
||||||
|
@ -710,11 +704,12 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial )
|
||||||
int nPlayersH = evt->u.con.nPlayersH;
|
int nPlayersH = evt->u.con.nPlayersH;
|
||||||
int nPlayersT = evt->u.con.nPlayersT;
|
int nPlayersT = evt->u.con.nPlayersT;
|
||||||
|
|
||||||
assert( id != HOST_ID_NONE );
|
|
||||||
logf( XW_LOGINFO, "remembering pair: hostid=%x, socket=%d", id, socket );
|
|
||||||
HostRec hr(socket, nPlayersH, nPlayersT);
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
m_sockets.insert( pair<HostID,HostRec>(id,hr) );
|
|
||||||
|
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, socket=%d (size=%d)",
|
||||||
|
__func__, id, socket, m_sockets.size());
|
||||||
|
HostRec hr(id, socket, nPlayersH, nPlayersT);
|
||||||
|
m_sockets.push_back( hr );
|
||||||
|
|
||||||
/* Now send the response */
|
/* Now send the response */
|
||||||
unsigned char buf[1 + /* cmd */
|
unsigned char buf[1 + /* cmd */
|
||||||
|
@ -728,11 +723,9 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial )
|
||||||
*bufp++ = initial ? XWRELAY_CONNECT_RESP : XWRELAY_RECONNECT_RESP;
|
*bufp++ = initial ? XWRELAY_CONNECT_RESP : XWRELAY_RECONNECT_RESP;
|
||||||
putNetShort( &bufp, GetHeartbeat() );
|
putNetShort( &bufp, GetHeartbeat() );
|
||||||
putNetShort( &bufp, GetCookieID() );
|
putNetShort( &bufp, GetCookieID() );
|
||||||
logf( XW_LOGVERBOSE0, "writing hostID of %d into msg", id );
|
|
||||||
*bufp++ = (char)id;
|
|
||||||
|
|
||||||
send_with_length( socket, buf, bufp - buf, true );
|
send_with_length( socket, buf, bufp - buf, true );
|
||||||
logf( XW_LOGVERBOSE0, "sent XWRELAY_CONNECTRESP" );
|
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
|
||||||
} /* sendResponse */
|
} /* sendResponse */
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -789,15 +782,13 @@ CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
|
||||||
{
|
{
|
||||||
assert( socket != 0 );
|
assert( socket != 0 );
|
||||||
|
|
||||||
/* RWReadLock ml( &m_sockets_rwlock ); */
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
int other = iter->second.m_socket;
|
int other = iter->m_socket;
|
||||||
if ( other != socket ) {
|
if ( other != socket ) {
|
||||||
send_msg( other, iter->first, msg, why, false );
|
send_msg( other, iter->m_hostID, msg, why, false );
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
} /* notifyOthers */
|
} /* notifyOthers */
|
||||||
|
|
||||||
|
@ -806,38 +797,82 @@ CookieRef::sendAllHere( bool includeName )
|
||||||
{
|
{
|
||||||
unsigned char buf[1 + 1 + MAX_CONNNAME_LEN];
|
unsigned char buf[1 + 1 + MAX_CONNNAME_LEN];
|
||||||
unsigned char* bufp = buf;
|
unsigned char* bufp = buf;
|
||||||
|
unsigned char* idLoc;
|
||||||
|
|
||||||
*bufp++ = XWRELAY_ALLHERE;
|
*bufp++ = XWRELAY_ALLHERE;
|
||||||
|
idLoc = bufp++; /* space for hostId, remembering address */
|
||||||
*bufp++ = includeName? 1 : 0;
|
*bufp++ = includeName? 1 : 0;
|
||||||
|
|
||||||
if ( includeName ) {
|
if ( includeName ) {
|
||||||
const char* connName = ConnName();
|
const char* connName = ConnName();
|
||||||
|
assert( !!connName && connName[0] );
|
||||||
int len = strlen( connName );
|
int len = strlen( connName );
|
||||||
assert( len < MAX_CONNNAME_LEN );
|
assert( len < MAX_CONNNAME_LEN );
|
||||||
*bufp++ = (char)len;
|
*bufp++ = (char)len;
|
||||||
memcpy( bufp, connName, len );
|
memcpy( bufp, connName, len );
|
||||||
bufp += len;
|
bufp += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter = m_sockets.begin();
|
||||||
while ( iter != m_sockets.end() ) {
|
while ( iter != m_sockets.end() ) {
|
||||||
send_with_length( iter->second.m_socket, buf, bufp-buf,
|
logf( XW_LOGINFO, "%s: sending to hostid %d", __func__,
|
||||||
|
iter->m_hostID );
|
||||||
|
*idLoc = iter->m_hostID; /* write in this target's hostId */
|
||||||
|
send_with_length( iter->m_socket, buf, bufp-buf,
|
||||||
true );
|
true );
|
||||||
++iter;
|
++iter;
|
||||||
}
|
}
|
||||||
} /* sendAllHere */
|
} /* sendAllHere */
|
||||||
|
|
||||||
|
void
|
||||||
|
CookieRef::assignConnName( void )
|
||||||
|
{
|
||||||
|
if ( !ConnName()[0] ) {
|
||||||
|
m_connName = PermID::GetNextUniqueID();
|
||||||
|
logf( XW_LOGINFO, "%s: assigning name: %s", __func__, ConnName() );
|
||||||
|
assert( GetCookieID() != 0 );
|
||||||
|
} else {
|
||||||
|
logf( XW_LOGINFO, "%s: has name: %s", __func__, ConnName() );
|
||||||
|
}
|
||||||
|
} /* assignConnName */
|
||||||
|
|
||||||
|
void
|
||||||
|
CookieRef::assignHostIds( void )
|
||||||
|
{
|
||||||
|
ASSERT_LOCKED();
|
||||||
|
HostID nextId = HOST_ID_SERVER;
|
||||||
|
|
||||||
|
unsigned int bits = 0;
|
||||||
|
|
||||||
|
vector<HostRec>::iterator iter;
|
||||||
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
if ( iter->m_hostID != HOST_ID_NONE ) {
|
||||||
|
bits |= 1 << iter->m_hostID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert( (bits & (1 << HOST_ID_SERVER)) != 0 );
|
||||||
|
|
||||||
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
if ( iter->m_hostID == HOST_ID_NONE ) {
|
||||||
|
while ( ((1 << nextId) & bits) != 0 ) {
|
||||||
|
++nextId;
|
||||||
|
}
|
||||||
|
iter->m_hostID = nextId++; /* ++: don't reuse */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CookieRef::disconnectSockets( int socket, XWREASON why )
|
CookieRef::disconnectSockets( int socket, XWREASON why )
|
||||||
{
|
{
|
||||||
if ( socket == 0 ) {
|
if ( socket == 0 ) {
|
||||||
/* RWReadLock ml( &m_sockets_rwlock ); */
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
assert( iter->second.m_socket != 0 );
|
assert( iter->m_socket != 0 );
|
||||||
disconnectSockets( iter->second.m_socket, why );
|
disconnectSockets( iter->m_socket, why );
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pushNotifyDisconEvent( socket, why );
|
pushNotifyDisconEvent( socket, why );
|
||||||
|
@ -851,21 +886,30 @@ CookieRef::noteHeartbeat( const CRefEvent* evt )
|
||||||
int socket = evt->u.heart.socket;
|
int socket = evt->u.heart.socket;
|
||||||
HostID id = evt->u.heart.id;
|
HostID id = evt->u.heart.id;
|
||||||
|
|
||||||
/* RWWriteLock rwl( &m_sockets_rwlock ); */
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.find(id);
|
vector<HostRec>::iterator iter;
|
||||||
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
if ( iter->m_hostID == id ) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ( iter == m_sockets.end() ) {
|
if ( iter == m_sockets.end() ) {
|
||||||
logf( XW_LOGERROR, "no socket for HostID %x", id );
|
logf( XW_LOGERROR, "no socket for HostID %x", id );
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
/* PENDING If the message came on an unexpected socket, kill the
|
int second_socket = iter->m_socket;
|
||||||
connection. An attack is the most likely explanation. */
|
if ( second_socket == socket ) {
|
||||||
assert( iter->second.m_socket == socket );
|
|
||||||
/* if see this again recover from it */
|
|
||||||
|
|
||||||
logf( XW_LOGVERBOSE1, "upping m_lastHeartbeat from %d to %d",
|
logf( XW_LOGVERBOSE1, "upping m_lastHeartbeat from %d to %d",
|
||||||
iter->second.m_lastHeartbeat, uptime() );
|
iter->m_lastHeartbeat, uptime() );
|
||||||
iter->second.m_lastHeartbeat = uptime();
|
iter->m_lastHeartbeat = uptime();
|
||||||
|
} else {
|
||||||
|
/* PENDING If the message came on an unexpected socket, kill the
|
||||||
|
connection. An attack is the most likely explanation. But:
|
||||||
|
now it's happening after a crash and clients reconnect. */
|
||||||
|
logf( XW_LOGERROR, "wrong socket record for HostID %x; wanted %d, found %d",
|
||||||
|
id, socket, second_socket );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} /* noteHeartbeat */
|
} /* noteHeartbeat */
|
||||||
|
|
||||||
|
@ -882,7 +926,7 @@ CookieRef::s_checkAllConnected( void* closure )
|
||||||
void
|
void
|
||||||
CookieRef::_CheckAllConnected()
|
CookieRef::_CheckAllConnected()
|
||||||
{
|
{
|
||||||
logf( XW_LOGVERBOSE0, "checkAllConnected" );
|
logf( XW_LOGVERBOSE0, "%s", __func__ );
|
||||||
/* MutexLock ml( &m_EventsMutex ); */
|
/* MutexLock ml( &m_EventsMutex ); */
|
||||||
CRefEvent newEvt;
|
CRefEvent newEvt;
|
||||||
newEvt.type = XWE_CONNTIMER;
|
newEvt.type = XWE_CONNTIMER;
|
||||||
|
@ -943,13 +987,12 @@ CookieRef::_PrintCookieInfo( string& out )
|
||||||
snprintf( buf, sizeof(buf), "Hosts connected=%d; cur time = %ld\n",
|
snprintf( buf, sizeof(buf), "Hosts connected=%d; cur time = %ld\n",
|
||||||
m_sockets.size(), uptime() );
|
m_sockets.size(), uptime() );
|
||||||
out += buf;
|
out += buf;
|
||||||
map<HostID,HostRec>::iterator iter = m_sockets.begin();
|
vector<HostRec>::iterator iter;
|
||||||
while ( iter != m_sockets.end() ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
snprintf( buf, sizeof(buf), " HostID=%d; socket=%d;last hbeat=%ld\n",
|
snprintf( buf, sizeof(buf), " HostID=%d; socket=%d;last hbeat=%ld\n",
|
||||||
iter->first, iter->second.m_socket,
|
iter->m_hostID, iter->m_socket,
|
||||||
iter->second.m_lastHeartbeat );
|
iter->m_lastHeartbeat );
|
||||||
out += buf;
|
out += buf;
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} /* PrintCookieInfo */
|
} /* PrintCookieInfo */
|
||||||
|
@ -957,20 +1000,18 @@ CookieRef::_PrintCookieInfo( string& out )
|
||||||
void
|
void
|
||||||
CookieRef::_FormatHostInfo( string* hostIds, string* addrs )
|
CookieRef::_FormatHostInfo( string* hostIds, string* addrs )
|
||||||
{
|
{
|
||||||
logf( XW_LOGINFO, "%s", __func__ );
|
|
||||||
|
|
||||||
ASSERT_LOCKED();
|
ASSERT_LOCKED();
|
||||||
map<HostID,HostRec>::iterator iter;
|
vector<HostRec>::iterator iter;
|
||||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||||
|
|
||||||
if ( !!hostIds ) {
|
if ( !!hostIds ) {
|
||||||
char buf[8];
|
char buf[8];
|
||||||
snprintf( buf, sizeof(buf), "%d ", iter->first );
|
snprintf( buf, sizeof(buf), "%d ", iter->m_hostID );
|
||||||
*hostIds += buf;
|
*hostIds += buf;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( !!addrs ) {
|
if ( !!addrs ) {
|
||||||
int s = iter->second.m_socket;
|
int s = iter->m_socket;
|
||||||
struct sockaddr_in name;
|
struct sockaddr_in name;
|
||||||
socklen_t siz = sizeof(name);
|
socklen_t siz = sizeof(name);
|
||||||
if ( 0 == getpeername( s, (struct sockaddr*)&name, &siz) ) {
|
if ( 0 == getpeername( s, (struct sockaddr*)&name, &siz) ) {
|
||||||
|
|
|
@ -35,15 +35,16 @@ using namespace std;
|
||||||
|
|
||||||
class CookieMapIterator; /* forward */
|
class CookieMapIterator; /* forward */
|
||||||
|
|
||||||
class HostRec {
|
struct HostRec {
|
||||||
public:
|
public:
|
||||||
HostRec(int socket, int nPlayersH, int nPlayersT)
|
HostRec(HostID hostID, int socket, int nPlayersH, int nPlayersT)
|
||||||
: m_socket(socket)
|
: m_hostID(hostID)
|
||||||
|
, m_socket(socket)
|
||||||
, m_nPlayersH(nPlayersH)
|
, m_nPlayersH(nPlayersH)
|
||||||
, m_nPlayersT(nPlayersT)
|
, m_nPlayersT(nPlayersT)
|
||||||
, m_lastHeartbeat(uptime())
|
, m_lastHeartbeat(uptime())
|
||||||
{}
|
{}
|
||||||
~HostRec() {}
|
HostID m_hostID;
|
||||||
int m_socket;
|
int m_socket;
|
||||||
int m_nPlayersH;
|
int m_nPlayersH;
|
||||||
int m_nPlayersT;
|
int m_nPlayersT;
|
||||||
|
@ -87,7 +88,8 @@ class CookieRef {
|
||||||
int SocketForHost( HostID dest );
|
int SocketForHost( HostID dest );
|
||||||
|
|
||||||
bool NeverFullyConnected();
|
bool NeverFullyConnected();
|
||||||
bool AcceptingReconnections( HostID hid, int nPlayersH, int nPlayersT );
|
bool AcceptingReconnections( HostID hid, const char* cookie,
|
||||||
|
int nPlayersH );
|
||||||
|
|
||||||
/* for console */
|
/* for console */
|
||||||
void _PrintCookieInfo( string& out );
|
void _PrintCookieInfo( string& out );
|
||||||
|
@ -193,6 +195,8 @@ class CookieRef {
|
||||||
void notifyDisconn(const CRefEvent* evt);
|
void notifyDisconn(const CRefEvent* evt);
|
||||||
void removeSocket( int socket );
|
void removeSocket( int socket );
|
||||||
void sendAllHere( bool includeName );
|
void sendAllHere( bool includeName );
|
||||||
|
void assignConnName( void );
|
||||||
|
void assignHostIds( void );
|
||||||
|
|
||||||
HostID nextHostID() { return ++m_nextHostID; }
|
HostID nextHostID() { return ++m_nextHostID; }
|
||||||
|
|
||||||
|
@ -203,8 +207,7 @@ class CookieRef {
|
||||||
/* timer callback */
|
/* timer callback */
|
||||||
static void s_checkAllConnected( void* closure );
|
static void s_checkAllConnected( void* closure );
|
||||||
|
|
||||||
map<HostID,HostRec> m_sockets;
|
vector<HostRec> m_sockets;
|
||||||
/* pthread_rwlock_t m_sockets_rwlock; */
|
|
||||||
|
|
||||||
int m_heatbeat; /* might change per carrier or something. */
|
int m_heatbeat; /* might change per carrier or something. */
|
||||||
string m_cookie; /* cookie used for initial connections */
|
string m_cookie; /* cookie used for initial connections */
|
||||||
|
|
|
@ -28,7 +28,6 @@
|
||||||
#include "crefmgr.h"
|
#include "crefmgr.h"
|
||||||
#include "cref.h"
|
#include "cref.h"
|
||||||
#include "mlock.h"
|
#include "mlock.h"
|
||||||
#include "permid.h"
|
|
||||||
#include "configs.h"
|
#include "configs.h"
|
||||||
#include "timermgr.h"
|
#include "timermgr.h"
|
||||||
|
|
||||||
|
@ -61,6 +60,7 @@ CRefMgr::CRefMgr()
|
||||||
{
|
{
|
||||||
/* should be using pthread_once() here */
|
/* should be using pthread_once() here */
|
||||||
pthread_mutex_init( &m_SocketStuffMutex, NULL );
|
pthread_mutex_init( &m_SocketStuffMutex, NULL );
|
||||||
|
pthread_mutex_init( &m_nextCIDMutex, NULL );
|
||||||
pthread_mutex_init( &m_freeList_mutex, NULL );
|
pthread_mutex_init( &m_freeList_mutex, NULL );
|
||||||
pthread_rwlock_init( &m_cookieMapRWLock, NULL );
|
pthread_rwlock_init( &m_cookieMapRWLock, NULL );
|
||||||
}
|
}
|
||||||
|
@ -103,44 +103,57 @@ CRefMgr::CloseAll()
|
||||||
}
|
}
|
||||||
} /* CloseAll */
|
} /* CloseAll */
|
||||||
|
|
||||||
|
/* Matching hosts to games. If they have a connName, it's easy. That's the
|
||||||
|
* only thing we'll match on, and it must match, and the game must have room.
|
||||||
|
* If they have a cookie as well, it must match. If only a cookie is
|
||||||
|
* provided, we may be dealing with a new game *or* a reconnect from somebody
|
||||||
|
* who didn't get his connName yet (even if other participants did.)
|
||||||
|
*/
|
||||||
|
|
||||||
CookieRef*
|
CookieRef*
|
||||||
CRefMgr::FindOpenGameFor( const char* cORn, bool isCookie,
|
CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
|
||||||
HostID hid, int socket, int nPlayersH, int nPlayersT )
|
HostID hid, int socket, int nPlayersH, int nPlayersT )
|
||||||
{
|
{
|
||||||
logf( XW_LOGINFO, "%s(cORn=%s,hid=%d,socket=%d)", __func__, cORn, hid,
|
logf( XW_LOGINFO, "%s(cookie=%s,connName=%s,hid=%d,socket=%d)", __func__,
|
||||||
socket );
|
cookie, connName, hid, socket );
|
||||||
CookieRef* cref = NULL;
|
CookieRef* found = NULL;
|
||||||
|
|
||||||
|
if ( !!cookie || !!connName ) { /* drop if both are null */
|
||||||
|
|
||||||
RWReadLock rwl( &m_cookieMapRWLock );
|
RWReadLock rwl( &m_cookieMapRWLock );
|
||||||
|
|
||||||
CookieMap::iterator iter = m_cookieMap.begin();
|
CookieMap::iterator iter;
|
||||||
while ( iter != m_cookieMap.end() ) {
|
for ( iter = m_cookieMap.begin();
|
||||||
cref = iter->second;
|
NULL == found && iter != m_cookieMap.end();
|
||||||
if ( isCookie ) {
|
++iter ) {
|
||||||
if ( 0 == strcmp( cref->Cookie(), cORn ) ) {
|
CookieRef* cref = iter->second;
|
||||||
if ( cref->NeverFullyConnected() ) {
|
|
||||||
break;
|
if ( !!connName ) {
|
||||||
} else if ( cref->HasSocket(socket) ) {
|
if ( 0 == strcmp( cref->ConnName(), connName ) ) {
|
||||||
logf( XW_LOGINFO, "%s: HasSocket case", __func__ );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if ( 0 == strcmp( cref->ConnName(), cORn ) ) {
|
|
||||||
bool found = false;
|
|
||||||
if ( cref->Lock() ) {
|
if ( cref->Lock() ) {
|
||||||
found = cref->AcceptingReconnections( hid, nPlayersH,
|
assert( !cookie || 0 == strcmp( cookie, cref->Cookie() ) );
|
||||||
nPlayersH );
|
if ( cref->AcceptingReconnections( hid, cookie,
|
||||||
|
nPlayersH ) ) {
|
||||||
|
found = cref;
|
||||||
|
}
|
||||||
cref->Unlock();
|
cref->Unlock();
|
||||||
}
|
}
|
||||||
if ( found ) {
|
}
|
||||||
break;
|
} else if ( !!cookie ) {
|
||||||
|
if ( 0 == strcmp( cref->Cookie(), cookie ) ) {
|
||||||
|
if ( cref->NeverFullyConnected() ) {
|
||||||
|
found = cref;
|
||||||
|
} else if ( cref->HasSocket(socket) ) {
|
||||||
|
logf( XW_LOGINFO, "%s: HasSocket case", __func__ );
|
||||||
|
found = cref;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++iter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (iter == m_cookieMap.end()) ? NULL : cref;
|
logf( XW_LOGINFO, "%s=>%p", __func__, found );
|
||||||
|
return found;
|
||||||
} /* FindOpenGameFor */
|
} /* FindOpenGameFor */
|
||||||
|
|
||||||
CookieID
|
CookieID
|
||||||
|
@ -148,12 +161,14 @@ CRefMgr::nextCID( const char* connName )
|
||||||
{
|
{
|
||||||
/* Later may want to guarantee that wrap-around doesn't cause an overlap.
|
/* Later may want to guarantee that wrap-around doesn't cause an overlap.
|
||||||
But that's really only a theoretical possibility. */
|
But that's really only a theoretical possibility. */
|
||||||
|
MutexLock ml(&m_nextCIDMutex);
|
||||||
return ++m_nextCID;
|
return ++m_nextCID;
|
||||||
} /* nextCID */
|
} /* nextCID */
|
||||||
|
|
||||||
int
|
int
|
||||||
CRefMgr::GetNumGamesSeen( void )
|
CRefMgr::GetNumGamesSeen( void )
|
||||||
{
|
{
|
||||||
|
MutexLock ml(&m_nextCIDMutex);
|
||||||
return m_nextCID;
|
return m_nextCID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,36 +222,23 @@ CRefMgr::getFromFreeList( void )
|
||||||
|
|
||||||
|
|
||||||
CookieRef*
|
CookieRef*
|
||||||
CRefMgr::getMakeCookieRef_locked( const char* cORn, bool isCookie, HostID hid,
|
CRefMgr::getMakeCookieRef_locked( const char* cookie, const char* connName,
|
||||||
int socket, int nPlayersH, int nPlayersT )
|
HostID hid, int socket, int nPlayersH,
|
||||||
|
int nPlayersT )
|
||||||
{
|
{
|
||||||
CookieRef* cref;
|
CookieRef* cref;
|
||||||
|
|
||||||
/* We have a cookie from a new connection. This may be the first time
|
/* We have a cookie from a new connection or from a reconnect. This may
|
||||||
it's been seen, or there may be a game currently in the
|
be the first time it's been seen, or there may be a game currently in
|
||||||
XW_ST_CONNECTING state, or it may be a dupe of a connect packet. So we
|
the XW_ST_CONNECTING state, or it may be a dupe of a connect packet.
|
||||||
need to look up the cookie first, then generate new connName and
|
If there's a game, cool. Otherwise add a new one. Pass the connName
|
||||||
cookieIDs if it's not found. */
|
which will be used if set, but if not set we'll be generating another
|
||||||
|
later when the game is complete.
|
||||||
|
*/
|
||||||
|
|
||||||
cref = FindOpenGameFor( cORn, isCookie, hid, socket, nPlayersH, nPlayersT );
|
cref = FindOpenGameFor( cookie, connName, hid, socket, nPlayersH, nPlayersT );
|
||||||
if ( cref == NULL ) {
|
if ( cref == NULL ) {
|
||||||
string s;
|
cref = AddNew( cookie, connName, nextCID( NULL ) );
|
||||||
const char* connName;
|
|
||||||
const char* cookie = NULL;
|
|
||||||
if ( isCookie ) {
|
|
||||||
cookie = cORn;
|
|
||||||
s = PermID::GetNextUniqueID();
|
|
||||||
connName = s.c_str();
|
|
||||||
} else {
|
|
||||||
connName = cORn;
|
|
||||||
}
|
|
||||||
|
|
||||||
CookieID cid = cookieIDForConnName( connName );
|
|
||||||
if ( cid == 0 ) {
|
|
||||||
cid = nextCID( connName );
|
|
||||||
}
|
|
||||||
|
|
||||||
cref = AddNew( cookie, connName, cid );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cref;
|
return cref;
|
||||||
|
@ -369,8 +371,6 @@ CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id )
|
||||||
{
|
{
|
||||||
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, id=%d", __func__,
|
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, id=%d", __func__,
|
||||||
cookie, connName, id );
|
cookie, connName, id );
|
||||||
CookieRef* exists = getCookieRef_impl( id );
|
|
||||||
assert( exists == NULL ); /* failed once */
|
|
||||||
|
|
||||||
CookieRef* ref = getFromFreeList();
|
CookieRef* ref = getFromFreeList();
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id )
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cookieMap.insert( pair<CookieID, CookieRef*>(ref->GetCookieID(), ref ) );
|
m_cookieMap.insert( pair<CookieID, CookieRef*>(ref->GetCookieID(), ref ) );
|
||||||
logf( XW_LOGINFO, "paired cookie %s/connName %s with id %d",
|
logf( XW_LOGINFO, "%s: paired cookie %s/connName %s with id %d", __func__,
|
||||||
(cookie?cookie:"NULL"), connName, ref->GetCookieID() );
|
(cookie?cookie:"NULL"), connName, ref->GetCookieID() );
|
||||||
|
|
||||||
#ifdef RELAY_HEARTBEAT
|
#ifdef RELAY_HEARTBEAT
|
||||||
|
@ -529,15 +529,15 @@ CookieMapIterator::Next()
|
||||||
// SafeCref
|
// SafeCref
|
||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
SafeCref::SafeCref( const char* cORn, bool isCookie, HostID hid, int socket,
|
SafeCref::SafeCref( const char* cookie, const char* connName, HostID hid,
|
||||||
int nPlayersH, int nPlayersT )
|
int socket, int nPlayersH, int nPlayersT )
|
||||||
: m_cref( NULL )
|
: m_cref( NULL )
|
||||||
, m_mgr( CRefMgr::Get() )
|
, m_mgr( CRefMgr::Get() )
|
||||||
, m_isValid( false )
|
, m_isValid( false )
|
||||||
{
|
{
|
||||||
CookieRef* cref;
|
CookieRef* cref;
|
||||||
|
|
||||||
cref = m_mgr->getMakeCookieRef_locked( cORn, isCookie, hid, socket,
|
cref = m_mgr->getMakeCookieRef_locked( cookie, connName, hid, socket,
|
||||||
nPlayersH, nPlayersT );
|
nPlayersH, nPlayersT );
|
||||||
if ( cref != NULL ) {
|
if ( cref != NULL ) {
|
||||||
m_locked = cref->Lock();
|
m_locked = cref->Lock();
|
||||||
|
|
|
@ -100,7 +100,7 @@ class CRefMgr {
|
||||||
void addToFreeList( CookieRef* cref );
|
void addToFreeList( CookieRef* cref );
|
||||||
CookieRef* getFromFreeList( void );
|
CookieRef* getFromFreeList( void );
|
||||||
|
|
||||||
CookieRef* getMakeCookieRef_locked( const char* cORn, bool isCookie,
|
CookieRef* getMakeCookieRef_locked( const char* cookie, const char* connName,
|
||||||
HostID hid, int socket,
|
HostID hid, int socket,
|
||||||
int nPlayersH, int nPlayersT );
|
int nPlayersH, int nPlayersT );
|
||||||
CookieRef* getCookieRef( CookieID cookieID );
|
CookieRef* getCookieRef( CookieID cookieID );
|
||||||
|
@ -108,8 +108,9 @@ class CRefMgr {
|
||||||
bool checkCookieRef_locked( CookieRef* cref );
|
bool checkCookieRef_locked( CookieRef* cref );
|
||||||
CookieRef* getCookieRef_impl( CookieID cookieID );
|
CookieRef* getCookieRef_impl( CookieID cookieID );
|
||||||
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id );
|
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id );
|
||||||
CookieRef* FindOpenGameFor( const char* cORn, bool isCookie,
|
CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
|
||||||
HostID hid, int socket, int nPlayersH, int nPlayersT );
|
HostID hid, int socket, int nPlayersH,
|
||||||
|
int nPlayersT );
|
||||||
|
|
||||||
CookieID cookieIDForConnName( const char* connName );
|
CookieID cookieIDForConnName( const char* connName );
|
||||||
CookieID nextCID( const char* connName );
|
CookieID nextCID( const char* connName );
|
||||||
|
@ -117,6 +118,7 @@ class CRefMgr {
|
||||||
static void heartbeatProc( void* closure );
|
static void heartbeatProc( void* closure );
|
||||||
void checkHeartbeats( time_t now );
|
void checkHeartbeats( time_t now );
|
||||||
|
|
||||||
|
pthread_mutex_t m_nextCIDMutex;
|
||||||
CookieID m_nextCID;
|
CookieID m_nextCID;
|
||||||
|
|
||||||
pthread_rwlock_t m_cookieMapRWLock;
|
pthread_rwlock_t m_cookieMapRWLock;
|
||||||
|
@ -137,7 +139,7 @@ class SafeCref {
|
||||||
CookieRef instance at a time. */
|
CookieRef instance at a time. */
|
||||||
|
|
||||||
public:
|
public:
|
||||||
SafeCref( const char* cookieOrConnName, bool cookie, HostID hid,
|
SafeCref( const char* cookie, const char* connName, HostID hid,
|
||||||
int socket, int nPlayersH, int nPlayersT );
|
int socket, int nPlayersH, int nPlayersT );
|
||||||
SafeCref( CookieID cid, bool failOk = false );
|
SafeCref( CookieID cid, bool failOk = false );
|
||||||
SafeCref( int socket );
|
SafeCref( int socket );
|
||||||
|
|
|
@ -137,7 +137,7 @@ logf( XW_LogLevel level, const char* format, ... )
|
||||||
}
|
}
|
||||||
} /* logf */
|
} /* logf */
|
||||||
|
|
||||||
static const char*
|
const char*
|
||||||
cmdToStr( XWRELAY_Cmd cmd )
|
cmdToStr( XWRELAY_Cmd cmd )
|
||||||
{
|
{
|
||||||
# define CASESTR(s) case s: return #s
|
# define CASESTR(s) case s: return #s
|
||||||
|
@ -257,6 +257,11 @@ send_with_length_unsafe( int socket, unsigned char* buf, int bufLen )
|
||||||
ok = true;
|
ok = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !ok ) {
|
||||||
|
logf( XW_LOGERROR, "%s(socket=%d) failed", __func__, socket );
|
||||||
|
}
|
||||||
|
|
||||||
return ok;
|
return ok;
|
||||||
} /* send_with_length_unsafe */
|
} /* send_with_length_unsafe */
|
||||||
|
|
||||||
|
@ -301,7 +306,7 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
|
||||||
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
MutexLock ml( &s_newCookieLock );
|
MutexLock ml( &s_newCookieLock );
|
||||||
|
|
||||||
SafeCref scr( cookie, true, srcID, socket, nPlayersH, nPlayersT );
|
SafeCref scr( cookie, NULL, srcID, socket, nPlayersH, nPlayersT );
|
||||||
success = scr.Connect( socket, srcID, nPlayersH, nPlayersT );
|
success = scr.Connect( socket, srcID, nPlayersH, nPlayersT );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -325,18 +330,22 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
|
||||||
if ( err != XWRELAY_ERROR_NONE ) {
|
if ( err != XWRELAY_ERROR_NONE ) {
|
||||||
denyConnection( socket, err );
|
denyConnection( socket, err );
|
||||||
} else {
|
} else {
|
||||||
|
char cookie[MAX_COOKIE_LEN+1];
|
||||||
char connName[MAX_CONNNAME_LEN+1];
|
char connName[MAX_CONNNAME_LEN+1];
|
||||||
HostID srcID;
|
HostID srcID;
|
||||||
unsigned char nPlayersH;
|
unsigned char nPlayersH;
|
||||||
unsigned char nPlayersT;
|
unsigned char nPlayersT;
|
||||||
|
|
||||||
connName[0] = '\0';
|
connName[0] = '\0';
|
||||||
if ( getNetByte( &bufp, end, &srcID )
|
if ( readStr( &bufp, end, cookie, sizeof(cookie) )
|
||||||
|
&& getNetByte( &bufp, end, &srcID )
|
||||||
&& getNetByte( &bufp, end, &nPlayersH )
|
&& getNetByte( &bufp, end, &nPlayersH )
|
||||||
&& getNetByte( &bufp, end, &nPlayersT )
|
&& getNetByte( &bufp, end, &nPlayersT )
|
||||||
&& readStr( &bufp, end, connName, sizeof(connName) ) ) {
|
&& readStr( &bufp, end, connName, sizeof(connName) ) ) {
|
||||||
|
|
||||||
SafeCref scr( connName, false, srcID, socket, nPlayersH,
|
SafeCref scr( cookie[0]? cookie : NULL,
|
||||||
|
connName[0]? connName : NULL,
|
||||||
|
srcID, socket, nPlayersH,
|
||||||
nPlayersT );
|
nPlayersT );
|
||||||
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT );
|
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT );
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,11 +38,11 @@ enum { XWRELAY_NONE /* 0 is an illegal value */
|
||||||
nPlayersTotal: 1 */
|
nPlayersTotal: 1 */
|
||||||
|
|
||||||
, XWRELAY_GAME_RECONNECT
|
, XWRELAY_GAME_RECONNECT
|
||||||
/* Connect using connName rather than cookie. Used by a device that's
|
/* Connect using connName as well as cookie. Used by a device that's
|
||||||
lost its connection to a game in progress. Once a game is locked
|
lost its connection to a game in progress. Once a game is locked
|
||||||
this is the only way a host can get (back) in. Format: flags: 1;
|
this is the only way a host can get (back) in. Format: flags: 1;
|
||||||
hostID: 1; nPlayers: 1; nPlayersTotal: 1; connNameLen: 1;
|
cookieLen: 1; cookie: <cookieLen>; hostID: 1; nPlayers: 1;
|
||||||
connName<connNameLen>*/
|
nPlayersTotal: 1; connNameLen: 1; connName<connNameLen>*/
|
||||||
|
|
||||||
, 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
|
||||||
|
@ -51,18 +51,19 @@ enum { XWRELAY_NONE /* 0 is an illegal value */
|
||||||
|
|
||||||
, XWRELAY_CONNECT_RESP
|
, XWRELAY_CONNECT_RESP
|
||||||
/* Sent from relay to device in response to XWRELAY_CONNECT. Format:
|
/* Sent from relay to device in response to XWRELAY_CONNECT. Format:
|
||||||
heartbeat_seconds: 2; connectionID: 2; assignedHostID: 1 */
|
heartbeat_seconds: 2; connectionID: 2; */
|
||||||
|
|
||||||
, XWRELAY_RECONNECT_RESP
|
, XWRELAY_RECONNECT_RESP
|
||||||
/* Sent from relay to device in response to XWRELAY_RECONNECT. Format:
|
/* Sent from relay to device in response to XWRELAY_RECONNECT. Format:
|
||||||
heartbeat_seconds: 2; connectionID: 2; */
|
heartbeat_seconds: 2; */
|
||||||
|
|
||||||
, XWRELAY_ALLHERE
|
, XWRELAY_ALLHERE
|
||||||
/* Sent from relay when it enters the state where all expected devices
|
/* 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
|
are here (at start of new game or after having been gone for a
|
||||||
while). Devices should not attempt to forward messages before this
|
while). Devices should not attempt to forward messages before this
|
||||||
message is received or after XWRELAY_DISCONNECT_OTHER is received.
|
message is received or after XWRELAY_DISCONNECT_OTHER is received.
|
||||||
Format: hasName: 1; [nameLen: 1; connName: <nameLen> */
|
Format: hostID: 1; hasName: 1; [connNameLen: 1; connName:
|
||||||
|
<connNameLen>]; */
|
||||||
|
|
||||||
, XWRELAY_DISCONNECT_YOU
|
, XWRELAY_DISCONNECT_YOU
|
||||||
/* Sent from relay when existing connection is terminated.
|
/* Sent from relay when existing connection is terminated.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "lstnrmgr.h"
|
#include "lstnrmgr.h"
|
||||||
|
#include "xwrelay.h"
|
||||||
|
|
||||||
typedef unsigned char HostID; /* see HOST_ID_SERVER */
|
typedef unsigned char HostID; /* see HOST_ID_SERVER */
|
||||||
|
|
||||||
|
@ -27,6 +28,8 @@ int GetNSpawns(void);
|
||||||
|
|
||||||
int make_socket( unsigned long addr, unsigned short port );
|
int make_socket( unsigned long addr, unsigned short port );
|
||||||
|
|
||||||
|
const char* cmdToStr( XWRELAY_Cmd cmd );
|
||||||
|
|
||||||
extern class ListenerMgr g_listeners;
|
extern class ListenerMgr g_listeners;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue