mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-18 22:26:30 +01:00
Address problems matching [re]connections to games: first, go back to
setting connName when all in a game are present. Second, have every host include in connections a random number. That number is made part of the connName and in general used to test whether a host belongs in a particular game. Add this "seed" to web interface. Means new versions for relay protocol and game stream format. Latter is handled correctly so older games can be opened.
This commit is contained in:
parent
edde3e2fd5
commit
0e43675abf
10 changed files with 332 additions and 158 deletions
|
@ -95,7 +95,8 @@ struct CommsCtxt {
|
|||
MsgQueueElem* msgQueueHead;
|
||||
MsgQueueElem* msgQueueTail;
|
||||
XP_U16 queueLen;
|
||||
|
||||
XP_U16 channelSeed; /* tries to be unique per device to aid
|
||||
dupe elimination at start */
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
XP_Bool doHeartbeat;
|
||||
XP_U32 lastMsgRcvdTime;
|
||||
|
@ -158,7 +159,7 @@ static void updateChannelAddress( AddressRecord* rec, const CommsAddrRec* addr )
|
|||
static XP_Bool channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
||||
const CommsAddrRec** addr );
|
||||
static AddressRecord* getRecordFor( CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
XP_PlayerAddr channelNo );
|
||||
XP_PlayerAddr channelNo, XP_Bool maskChnl );
|
||||
static XP_S16 sendMsg( CommsCtxt* comms, MsgQueueElem* elem );
|
||||
static void addToQueue( CommsCtxt* comms, MsgQueueElem* newMsgElem );
|
||||
static void freeElem( const CommsCtxt* comms, MsgQueueElem* elem );
|
||||
|
@ -300,6 +301,7 @@ comms_reset( CommsCtxt* comms, XP_Bool isServer,
|
|||
cleanupAddrRecs( comms );
|
||||
|
||||
comms->nextChannelNo = 0;
|
||||
comms->channelSeed = 0;
|
||||
|
||||
comms->connID = CONN_ID_NONE;
|
||||
#ifdef XWFEATURE_RELAY
|
||||
|
@ -317,7 +319,8 @@ p_comms_resetTimer( void* closure, XWTimerReason XP_UNUSED_DBG(why) )
|
|||
XP_Bool success;
|
||||
LOG_FUNC();
|
||||
XP_ASSERT( why == TIMER_COMMS );
|
||||
success = relayConnect( comms );
|
||||
success = comms->r.relayState >= COMMS_RELAYSTATE_CONNECTED
|
||||
|| relayConnect( comms );
|
||||
|
||||
if ( success ) {
|
||||
comms->reconTimerPending = XP_FALSE;
|
||||
|
@ -458,6 +461,11 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
|
|||
|
||||
comms->connID = stream_getU32( stream );
|
||||
comms->nextChannelNo = stream_getU16( stream );
|
||||
if ( version < STREAM_VERS_CHANNELSEED ) {
|
||||
comms->channelSeed = 0;
|
||||
} else {
|
||||
comms->channelSeed = stream_getU16( stream );
|
||||
}
|
||||
if ( addr.conType == COMMS_CONN_RELAY ) {
|
||||
comms->r.myHostID = stream_getU8( stream );
|
||||
stringFromStreamHere( stream, comms->r.connName,
|
||||
|
@ -633,6 +641,7 @@ comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
|
||||
stream_putU32( stream, comms->connID );
|
||||
stream_putU16( stream, comms->nextChannelNo );
|
||||
stream_putU16( stream, comms->channelSeed );
|
||||
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
||||
stream_putU8( stream, comms->r.myHostID );
|
||||
stringToStream( stream, comms->r.connName );
|
||||
|
@ -806,6 +815,15 @@ makeElemWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
|
|||
return newMsgElem;
|
||||
} /* makeElemWithID */
|
||||
|
||||
static XP_U16
|
||||
getChannelSeed( CommsCtxt* comms )
|
||||
{
|
||||
while ( comms->channelSeed == 0 ) {
|
||||
comms->channelSeed = XP_RANDOM();
|
||||
}
|
||||
return comms->channelSeed;
|
||||
}
|
||||
|
||||
/* Send a message using the sequentially next MsgID. Save the message so
|
||||
* resend can work. */
|
||||
XP_S16
|
||||
|
@ -813,13 +831,16 @@ comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
{
|
||||
XP_ASSERT( !!comms );
|
||||
XP_PlayerAddr channelNo = stream_getAddress( stream );
|
||||
AddressRecord* rec = getRecordFor( comms, NULL, channelNo );
|
||||
AddressRecord* rec = getRecordFor( comms, NULL, channelNo, XP_FALSE );
|
||||
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
|
||||
MsgQueueElem* elem;
|
||||
XP_S16 result = -1;
|
||||
|
||||
if ( 0 == channelNo ) {
|
||||
channelNo = getChannelSeed(comms) & ~CHANNEL_MASK;
|
||||
}
|
||||
|
||||
XP_DEBUGF( "%s: assigning msgID=" XP_LD " on chnl %d", __func__,
|
||||
XP_DEBUGF( "%s: assigning msgID=" XP_LD " on chnl %x", __func__,
|
||||
msgID, channelNo );
|
||||
|
||||
elem = makeElemWithID( comms, msgID, rec, channelNo, stream );
|
||||
|
@ -861,7 +882,7 @@ printQueue( const CommsCtxt* comms )
|
|||
|
||||
for ( elem = comms->msgQueueHead, i = 0; i < comms->queueLen;
|
||||
elem = elem->next, ++i ) {
|
||||
XP_STATUSF( "\t%d: channel: %d; msgID=" XP_LD,
|
||||
XP_STATUSF( "\t%d: channel: %x; msgID=" XP_LD,
|
||||
i+1, elem->channelNo, elem->msgID );
|
||||
}
|
||||
}
|
||||
|
@ -899,10 +920,11 @@ freeElem( const CommsCtxt* XP_UNUSED_DBG(comms), MsgQueueElem* elem )
|
|||
static void
|
||||
removeFromQueue( CommsCtxt* comms, XP_PlayerAddr channelNo, MsgID msgID )
|
||||
{
|
||||
XP_STATUSF( "%s: remove msgs <= " XP_LD " for channel %d (queueLen: %d)",
|
||||
XP_STATUSF( "%s: remove msgs <= " XP_LD " for channel %x (queueLen: %d)",
|
||||
__func__, msgID, channelNo, comms->queueLen );
|
||||
|
||||
if ( (channelNo == 0) || !!getRecordFor(comms, NULL, channelNo) ) {
|
||||
if ( (channelNo == 0) || !!getRecordFor( comms, NULL, channelNo,
|
||||
XP_FALSE ) ) {
|
||||
|
||||
MsgQueueElem* elem = comms->msgQueueHead;
|
||||
MsgQueueElem* next;
|
||||
|
@ -1075,24 +1097,32 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
|||
comms->r.cookieID = stream_getU16( stream );
|
||||
XP_LOGF( "set cookieID = %d", comms->r.cookieID );
|
||||
setHeartbeatTimer( comms );
|
||||
if ( XWRELAY_CONNECT_RESP == cmd ) {
|
||||
XP_ASSERT( comms->r.connName[0] == '\0' );
|
||||
stringFromStreamHere( stream, comms->r.connName,
|
||||
sizeof(comms->r.connName) );
|
||||
}
|
||||
break;
|
||||
|
||||
case XWRELAY_ALLHERE:
|
||||
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 );
|
||||
|
||||
#ifdef DEBUG
|
||||
{
|
||||
XP_UCHAR connName[MAX_CONNNAME_LEN+1];
|
||||
stringFromStreamHere( stream, connName, sizeof(connName) );
|
||||
XP_ASSERT( comms->r.connName[0] == '\0'
|
||||
|| 0 == XP_STRCMP( comms->r.connName, connName ) );
|
||||
XP_MEMCPY( comms->r.connName, connName, sizeof(comms->r.connName) );
|
||||
}
|
||||
#else
|
||||
stringFromStreamHere( stream, comms->r.connName,
|
||||
sizeof(comms->r.connName) );
|
||||
#endif
|
||||
set_relay_state( comms, COMMS_RELAYSTATE_ALLCONNECTED );
|
||||
|
||||
/* We're [re-]connected now. Send any pending messages. This may
|
||||
need to be done later since we're inside the platform's socket
|
||||
read proc now. */
|
||||
need to be done later since we're inside the platform's socket read
|
||||
proc now. */
|
||||
comms_resendAll( comms );
|
||||
break;
|
||||
case XWRELAY_MSG_FROMRELAY:
|
||||
|
@ -1198,11 +1228,12 @@ preProcess( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
|
||||
static AddressRecord*
|
||||
getRecordFor( CommsCtxt* comms, const CommsAddrRec* addr,
|
||||
XP_PlayerAddr channelNo )
|
||||
XP_PlayerAddr channelNo, XP_Bool maskChannel )
|
||||
{
|
||||
CommsConnType conType;
|
||||
AddressRecord* rec;
|
||||
XP_Bool matched = XP_FALSE;
|
||||
XP_U16 mask = maskChannel? ~CHANNEL_MASK : ~0;
|
||||
|
||||
/* Use addr if we have it. Otherwise use channelNo if non-0 */
|
||||
conType = !!addr? addr->conType : COMMS_CONN_NONE;
|
||||
|
@ -1211,6 +1242,7 @@ getRecordFor( CommsCtxt* comms, const CommsAddrRec* addr,
|
|||
XP_ASSERT( !addr || (conType == rec->addr.conType) );
|
||||
switch( conType ) {
|
||||
case COMMS_CONN_RELAY:
|
||||
XP_ASSERT(0); /* is this being used? */
|
||||
if ( (addr->u.ip_relay.ipAddr == rec->addr.u.ip_relay.ipAddr)
|
||||
&& (addr->u.ip_relay.port == rec->addr.u.ip_relay.port ) ) {
|
||||
matched = XP_TRUE;
|
||||
|
@ -1238,7 +1270,7 @@ getRecordFor( CommsCtxt* comms, const CommsAddrRec* addr,
|
|||
}
|
||||
break;
|
||||
case COMMS_CONN_NONE:
|
||||
matched = channelNo == rec->channelNo;
|
||||
matched = channelNo == (rec->channelNo & mask);
|
||||
break;
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
|
@ -1280,7 +1312,8 @@ validateInitialMessage( CommsCtxt* comms,
|
|||
#ifdef COMMS_HEARTBEAT
|
||||
} else if ( comms->doHeartbeat ) {
|
||||
XP_Bool addRec = XP_FALSE;
|
||||
rec = getRecordFor( comms, addr, *channelNo );
|
||||
/* This (with mask) is untested!!! */
|
||||
rec = getRecordFor( comms, addr, *channelNo, XP_TRUE );
|
||||
|
||||
if ( hasPayload ) {
|
||||
if ( rec ) {
|
||||
|
@ -1299,8 +1332,9 @@ validateInitialMessage( CommsCtxt* comms,
|
|||
|
||||
if ( addRec ) {
|
||||
if ( comms->isServer ) {
|
||||
XP_ASSERT( *channelNo == 0 );
|
||||
*channelNo = ++comms->nextChannelNo;
|
||||
XP_ASSERT( (*channelNo && CHANNEL_MASK) == 0 );
|
||||
*channelNo |= ++comms->nextChannelNo;
|
||||
XP_ASSERT( comms->nextChannelNo <= CHANNEL_MASK );
|
||||
}
|
||||
rec = rememberChannelAddress( comms, *channelNo, senderID, addr );
|
||||
if ( hasPayload ) {
|
||||
|
@ -1311,13 +1345,15 @@ validateInitialMessage( CommsCtxt* comms,
|
|||
}
|
||||
#endif
|
||||
} else {
|
||||
rec = getRecordFor( comms, addr, *channelNo );
|
||||
rec = getRecordFor( comms, addr, *channelNo, XP_TRUE );
|
||||
if ( !!rec ) {
|
||||
rec = NULL; /* reject: we've already seen init message on channel */
|
||||
/* reject: we've already seen init message on channel */
|
||||
rec = NULL;
|
||||
} else {
|
||||
if ( comms->isServer ) {
|
||||
XP_ASSERT( *channelNo == 0 );
|
||||
*channelNo = ++comms->nextChannelNo;
|
||||
XP_ASSERT( (*channelNo & CHANNEL_MASK) == 0 );
|
||||
*channelNo |= ++comms->nextChannelNo;
|
||||
XP_ASSERT( comms->nextChannelNo <= CHANNEL_MASK );
|
||||
}
|
||||
rec = rememberChannelAddress( comms, *channelNo, senderID, addr );
|
||||
}
|
||||
|
@ -1340,7 +1376,7 @@ validateChannelMessage( CommsCtxt* comms, const CommsAddrRec* addr,
|
|||
AddressRecord* rec;
|
||||
LOG_FUNC();
|
||||
|
||||
rec = getRecordFor( comms, NULL, channelNo );
|
||||
rec = getRecordFor( comms, NULL, channelNo, XP_FALSE );
|
||||
if ( !!rec ) {
|
||||
removeFromQueue( comms, channelNo, lastMsgRcd );
|
||||
if ( msgID == rec->lastMsgRcd + 1 ) {
|
||||
|
@ -1354,7 +1390,7 @@ validateChannelMessage( CommsCtxt* comms, const CommsAddrRec* addr,
|
|||
rec = NULL;
|
||||
}
|
||||
} else {
|
||||
XP_LOGF( "%s: no rec for channelNo %d", __func__, channelNo );
|
||||
XP_LOGF( "%s: no rec for channelNo %x", __func__, channelNo );
|
||||
}
|
||||
|
||||
LOG_RETURNF( XP_P, rec );
|
||||
|
@ -1390,7 +1426,7 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
channelNo = stream_getU16( stream );
|
||||
msgID = stream_getU32( stream );
|
||||
lastMsgRcd = stream_getU32( stream );
|
||||
XP_DEBUGF( "rcd on channelNo %d: msgID=%ld,lastMsgRcd=%ld ",
|
||||
XP_DEBUGF( "rcd on channelNo %x: msgID=%ld,lastMsgRcd=%ld ",
|
||||
channelNo, msgID, lastMsgRcd );
|
||||
|
||||
payloadSize = stream_getSize( stream ) > 0; /* anything left? */
|
||||
|
@ -1407,7 +1443,7 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
messageValid = NULL != rec;
|
||||
if ( messageValid ) {
|
||||
rec->lastMsgRcd = msgID;
|
||||
XP_LOGF( "%s: set channel %d's lastMsgRcd to " XP_LD,
|
||||
XP_LOGF( "%s: set channel %x's lastMsgRcd to " XP_LD,
|
||||
__func__, channelNo, msgID );
|
||||
stream_setAddress( stream, channelNo );
|
||||
messageValid = payloadSize > 0;
|
||||
|
@ -1576,7 +1612,7 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
|
||||
for ( elem = comms->msgQueueHead; !!elem; elem = elem->next ) {
|
||||
XP_SNPRINTF( buf, sizeof(buf),
|
||||
" - channelNo=%d; msgID=" XP_LD "; len=%d\n",
|
||||
" - channelNo=%x; msgID=" XP_LD "; len=%d\n",
|
||||
elem->channelNo, elem->msgID, elem->len );
|
||||
stream_catString( stream, buf );
|
||||
}
|
||||
|
@ -1589,7 +1625,7 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
now = util_getCurSeconds( comms->util );
|
||||
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
||||
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
||||
(XP_UCHAR*)" Stats for channel: %d\n",
|
||||
(XP_UCHAR*)" Stats for channel: %x\n",
|
||||
rec->channelNo );
|
||||
stream_catString( stream, buf );
|
||||
|
||||
|
@ -1617,7 +1653,7 @@ rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|||
XWHostID hostID, const CommsAddrRec* addr )
|
||||
{
|
||||
AddressRecord* recs = NULL;
|
||||
recs = getRecordFor( comms, NULL, channelNo );
|
||||
recs = getRecordFor( comms, NULL, channelNo, XP_FALSE );
|
||||
if ( !recs ) {
|
||||
/* not found; add a new entry */
|
||||
recs = (AddressRecord*)XP_MALLOC( comms->mpool, sizeof(*recs) );
|
||||
|
@ -1656,7 +1692,7 @@ static XP_Bool
|
|||
channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
||||
const CommsAddrRec** addr )
|
||||
{
|
||||
AddressRecord* recs = getRecordFor( comms, NULL, channelNo );
|
||||
AddressRecord* recs = getRecordFor( comms, NULL, channelNo, XP_FALSE );
|
||||
XP_Bool found = !!recs;
|
||||
*addr = found? &recs->addr : NULL;
|
||||
return found;
|
||||
|
@ -1678,7 +1714,7 @@ static XWHostID
|
|||
getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo )
|
||||
{
|
||||
XWHostID id = HOST_ID_NONE;
|
||||
if ( channelNo == CHANNEL_NONE ) {
|
||||
if ( (channelNo & CHANNEL_MASK) == CHANNEL_NONE ) {
|
||||
id = HOST_ID_SERVER;
|
||||
} else {
|
||||
AddressRecord* recs;
|
||||
|
@ -1688,7 +1724,7 @@ getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo )
|
|||
}
|
||||
}
|
||||
}
|
||||
XP_LOGF( "%s(%d) => %x", __func__, channelNo, id );
|
||||
XP_LOGF( "%s(%x) => %x", __func__, channelNo, id );
|
||||
return id;
|
||||
} /* getDestID */
|
||||
|
||||
|
@ -1721,25 +1757,19 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
|||
}
|
||||
break;
|
||||
case XWRELAY_GAME_CONNECT:
|
||||
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
||||
stringToStream( tmpStream, addr.u.ip_relay.invite );
|
||||
XP_ASSERT( comms->r.myHostID == (comms->isServer?
|
||||
HOST_ID_SERVER: HOST_ID_NONE ) );
|
||||
stream_putU8( tmpStream, comms->r.myHostID );
|
||||
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
||||
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
||||
|
||||
set_relay_state( comms,COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||
break;
|
||||
|
||||
case XWRELAY_GAME_RECONNECT:
|
||||
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
||||
stringToStream( tmpStream, addr.u.ip_relay.invite );
|
||||
stream_putU8( tmpStream, comms->r.myHostID );
|
||||
XP_ASSERT( cmd == XWRELAY_GAME_RECONNECT
|
||||
|| comms->r.myHostID == HOST_ID_NONE
|
||||
|| comms->r.myHostID == HOST_ID_SERVER );
|
||||
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
||||
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
||||
stringToStream( tmpStream, comms->r.connName );
|
||||
|
||||
stream_putU16( tmpStream, getChannelSeed(comms) );
|
||||
if ( XWRELAY_GAME_RECONNECT == cmd ) {
|
||||
stringToStream( tmpStream, comms->r.connName );
|
||||
}
|
||||
set_relay_state( comms, COMMS_RELAYSTATE_CONNECT_PENDING );
|
||||
break;
|
||||
|
||||
|
|
|
@ -97,7 +97,10 @@ typedef struct TrayContext TrayContext;
|
|||
typedef struct PoolContext PoolContext;
|
||||
typedef struct XW_UtilCtxt XW_UtilCtxt;
|
||||
|
||||
typedef XP_S16 XP_PlayerAddr;
|
||||
/* Low two bits treated as channel; rest can be random to aid detection of
|
||||
* duplicate packets. */
|
||||
#define CHANNEL_MASK 0x0003
|
||||
typedef XP_U16 XP_PlayerAddr;
|
||||
|
||||
typedef enum {
|
||||
TIMER_PENDOWN = 1, /* ARM doesn't like ids of 0... */
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define STREAM_VERS_CHANNELSEED 0x09 /* new short in relay connect must be
|
||||
saved in comms */
|
||||
#define STREAM_VERS_UTF8 0x08
|
||||
#define STREAM_VERS_ALWAYS_MULTI 0x07 /* stream format same for multi and
|
||||
one-device game builds */
|
||||
|
@ -41,7 +43,7 @@ extern "C" {
|
|||
#define STREAM_VERS_41B4 0x02
|
||||
#define STREAM_VERS_405 0x01
|
||||
|
||||
#define CUR_STREAM_VERS STREAM_VERS_UTF8
|
||||
#define CUR_STREAM_VERS STREAM_VERS_CHANNELSEED
|
||||
|
||||
typedef struct LocalPlayer {
|
||||
XP_UCHAR* name;
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "timermgr.h"
|
||||
#include "configs.h"
|
||||
#include "crefmgr.h"
|
||||
#include "permid.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
@ -168,7 +169,8 @@ CookieRef::Unlock() {
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
||||
CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT,
|
||||
int seed )
|
||||
{
|
||||
if ( CRefMgr::Get()->Associate( socket, this ) ) {
|
||||
if ( hid == HOST_ID_NONE ) {
|
||||
|
@ -176,7 +178,7 @@ CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
|||
} else {
|
||||
logf( XW_LOGINFO, "NOT assigned host id; why?" );
|
||||
}
|
||||
pushConnectEvent( socket, hid, nPlayersH, nPlayersT );
|
||||
pushConnectEvent( socket, hid, nPlayersH, nPlayersT, seed );
|
||||
handleEvents();
|
||||
} else {
|
||||
logf( XW_LOGINFO, "dropping connect event; already connected" );
|
||||
|
@ -184,10 +186,11 @@ CookieRef::_Connect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
|||
}
|
||||
|
||||
void
|
||||
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersT )
|
||||
CookieRef::_Reconnect( int socket, HostID hid, int nPlayersH, int nPlayersT,
|
||||
int seed )
|
||||
{
|
||||
(void)CRefMgr::Get()->Associate( socket, this );
|
||||
pushReconnectEvent( socket, hid, nPlayersH, nPlayersT );
|
||||
pushReconnectEvent( socket, hid, nPlayersH, nPlayersT, seed );
|
||||
handleEvents();
|
||||
}
|
||||
|
||||
|
@ -222,6 +225,7 @@ CookieRef::SocketForHost( HostID dest )
|
|||
int socket = -1;
|
||||
ASSERT_LOCKED();
|
||||
vector<HostRec>::const_iterator iter;
|
||||
assert( dest != 0 ); /* don't use as lookup before assigned */
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_hostID == dest ) {
|
||||
socket = iter->m_socket;
|
||||
|
@ -236,7 +240,7 @@ CookieRef::SocketForHost( HostID dest )
|
|||
/* The idea here is: have we never seen the XW_ST_ALLCONNECTED state. This
|
||||
needs to include any states reachable from XW_ST_ALLCONNECTED from which
|
||||
recovery back to XW_ST_ALLCONNECTED is possible. This is used to decide
|
||||
whether to admit a connection based on its cookie -- whether that cookie
|
||||
whether to admit a connection based on its cookie -- whether that coookie
|
||||
should join an existing cref or get a new one? */
|
||||
bool
|
||||
CookieRef::NeverFullyConnected()
|
||||
|
@ -246,10 +250,11 @@ CookieRef::NeverFullyConnected()
|
|||
}
|
||||
|
||||
bool
|
||||
CookieRef::GameOpen( HostID hid, const char* cookie,
|
||||
int nPlayersH, bool isNew )
|
||||
CookieRef::GameOpen( const char* cookie, int nPlayersH, bool isNew,
|
||||
bool* alreadyHere )
|
||||
{
|
||||
bool accept = false;
|
||||
*alreadyHere = false;
|
||||
/* First, do we have room. Second, are we missing this guy? */
|
||||
|
||||
if ( isNew && m_gameFull ) {
|
||||
|
@ -260,9 +265,6 @@ CookieRef::GameOpen( HostID hid, const char* cookie,
|
|||
&& m_curState != XWS_MISSING ) {
|
||||
/* do nothing; reject */
|
||||
logf( XW_LOGINFO, "reject: bad state %s", stateString(m_curState) );
|
||||
} else if ( HostKnown( hid ) ) {
|
||||
logf( XW_LOGINFO, "reject: known hid" );
|
||||
/* do nothing: reject */
|
||||
} else {
|
||||
if ( m_nPlayersSought == 0 ) {
|
||||
accept = true;
|
||||
|
@ -305,15 +307,17 @@ CookieRef::removeSocket( int socket )
|
|||
ASSERT_LOCKED();
|
||||
|
||||
count = m_sockets.size();
|
||||
assert( count > 0 );
|
||||
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_socket == socket ) {
|
||||
m_sockets.erase(iter);
|
||||
--count;
|
||||
break;
|
||||
if ( count > 0 ) {
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
if ( iter->m_socket == socket ) {
|
||||
m_sockets.erase(iter);
|
||||
--count;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logf( XW_LOGERROR, "%s: no socket %d to remove", __func__, socket );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,7 +395,8 @@ CookieRef::_Remove( int socket )
|
|||
|
||||
void
|
||||
CookieRef::pushConnectEvent( int socket, HostID srcID,
|
||||
int nPlayersH, int nPlayersT )
|
||||
int nPlayersH, int nPlayersT,
|
||||
int seed )
|
||||
{
|
||||
CRefEvent evt;
|
||||
evt.type = XWE_CONNECTMSG;
|
||||
|
@ -399,12 +404,13 @@ CookieRef::pushConnectEvent( int socket, HostID srcID,
|
|||
evt.u.con.srcID = srcID;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersT = nPlayersT;
|
||||
evt.u.con.seed = seed;
|
||||
m_eventQueue.push_back( evt );
|
||||
} /* pushConnectEvent */
|
||||
|
||||
void
|
||||
CookieRef::pushReconnectEvent( int socket, HostID srcID,
|
||||
int nPlayersH, int nPlayersT )
|
||||
CookieRef::pushReconnectEvent( int socket, HostID srcID, int nPlayersH,
|
||||
int nPlayersT, int seed )
|
||||
{
|
||||
CRefEvent evt;
|
||||
evt.type = XWE_RECONNECTMSG;
|
||||
|
@ -412,6 +418,7 @@ CookieRef::pushReconnectEvent( int socket, HostID srcID,
|
|||
evt.u.con.srcID = srcID;
|
||||
evt.u.con.nPlayersH = nPlayersH;
|
||||
evt.u.con.nPlayersT = nPlayersT;
|
||||
evt.u.con.seed = seed;
|
||||
m_eventQueue.push_back( evt );
|
||||
} /* pushReconnectEvent */
|
||||
|
||||
|
@ -562,6 +569,7 @@ CookieRef::handleEvents()
|
|||
case XWA_SNDALLHERE_2:
|
||||
cancelAllConnectedTimer();
|
||||
assignHostIds();
|
||||
assignConnName();
|
||||
sendAllHere( );
|
||||
break;
|
||||
|
||||
|
@ -613,6 +621,7 @@ CookieRef::increasePlayerCounts( const CRefEvent* evt )
|
|||
int nPlayersH = evt->u.con.nPlayersH;
|
||||
int nPlayersT = evt->u.con.nPlayersT;
|
||||
HostID hid = evt->u.con.srcID;
|
||||
assert( hid <= 4 );
|
||||
|
||||
logf( XW_LOGINFO, "%s: hid=%d, nPlayersH=%d, ", __func__,
|
||||
"nPlayersT=%d", hid, nPlayersH, nPlayersT );
|
||||
|
@ -713,22 +722,23 @@ void
|
|||
CookieRef::sendResponse( const CRefEvent* evt, bool initial )
|
||||
{
|
||||
int socket = evt->u.con.socket;
|
||||
HostID id = evt->u.con.srcID;
|
||||
HostID hid = evt->u.con.srcID;
|
||||
int nPlayersH = evt->u.con.nPlayersH;
|
||||
int nPlayersT = evt->u.con.nPlayersT;
|
||||
int seed = evt->u.con.seed;
|
||||
|
||||
ASSERT_LOCKED();
|
||||
|
||||
logf( XW_LOGINFO, "%s: remembering pair: hostid=%x, socket=%d (size=%d)",
|
||||
__func__, id, socket, m_sockets.size());
|
||||
HostRec hr(id, socket, nPlayersH, nPlayersT);
|
||||
__func__, hid, socket, m_sockets.size());
|
||||
HostRec hr(hid, socket, nPlayersH, nPlayersT, seed );
|
||||
m_sockets.push_back( hr );
|
||||
logf( XW_LOGINFO, "m_sockets.size() now %d", m_sockets.size() );
|
||||
|
||||
/* Now send the response */
|
||||
unsigned char buf[1 + /* cmd */
|
||||
sizeof(short) + /* heartbeat */
|
||||
sizeof(CookieID) +
|
||||
1 + MAX_CONNNAME_LEN
|
||||
sizeof(CookieID)
|
||||
];
|
||||
|
||||
unsigned char* bufp = buf;
|
||||
|
@ -737,16 +747,6 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial )
|
|||
putNetShort( &bufp, GetHeartbeat() );
|
||||
putNetShort( &bufp, GetCookieID() );
|
||||
|
||||
if ( initial ) {
|
||||
const char* connName = ConnName();
|
||||
assert( !!connName && connName[0] );
|
||||
int len = strlen( connName );
|
||||
assert( len < MAX_CONNNAME_LEN );
|
||||
*bufp++ = (char)len;
|
||||
memcpy( bufp, connName, len );
|
||||
bufp += len;
|
||||
}
|
||||
|
||||
send_with_length( socket, buf, bufp - buf, true );
|
||||
logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) );
|
||||
} /* sendResponse */
|
||||
|
@ -818,13 +818,21 @@ CookieRef::notifyOthers( int socket, XWRelayMsg msg, XWREASON why )
|
|||
void
|
||||
CookieRef::sendAllHere( void )
|
||||
{
|
||||
unsigned char buf[1 + 1];
|
||||
unsigned char buf[1 + 1 + 1 + MAX_CONNNAME_LEN];
|
||||
unsigned char* bufp = buf;
|
||||
unsigned char* idLoc;
|
||||
|
||||
*bufp++ = XWRELAY_ALLHERE;
|
||||
idLoc = bufp++; /* space for hostId, remembering address */
|
||||
|
||||
const char* connName = ConnName();
|
||||
assert( !!connName && connName[0] );
|
||||
int len = strlen( connName );
|
||||
assert( len < MAX_CONNNAME_LEN );
|
||||
*bufp++ = (char)len;
|
||||
memcpy( bufp, connName, len );
|
||||
bufp += len;
|
||||
|
||||
ASSERT_LOCKED();
|
||||
vector<HostRec>::iterator iter = m_sockets.begin();
|
||||
while ( iter != m_sockets.end() ) {
|
||||
|
@ -863,6 +871,72 @@ CookieRef::assignHostIds( void )
|
|||
}
|
||||
}
|
||||
|
||||
#define CONNNAME_DELIM ' ' /* ' ' so will wrap in browser */
|
||||
/* Does my seed belong as part of existing connName */
|
||||
bool
|
||||
CookieRef::SeedBelongs( int gameSeed )
|
||||
{
|
||||
bool belongs = false;
|
||||
const char* ptr = ConnName();
|
||||
const char* end = ptr + strlen(ptr);
|
||||
assert( '\0' != ptr[0] );
|
||||
char buf[5];
|
||||
snprintf( buf, sizeof(buf), "%.4X", gameSeed );
|
||||
|
||||
for ( ; *ptr != CONNNAME_DELIM && ptr < end; ptr += 4 ) {
|
||||
if ( 0 == strncmp( ptr, buf, 4 ) ) {
|
||||
belongs = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return belongs;
|
||||
} /* SeedBelongs */
|
||||
|
||||
/* does my connName provide a home for seeds already in this connName-less
|
||||
ref? */
|
||||
bool
|
||||
CookieRef::SeedsBelong( const char* connName )
|
||||
{
|
||||
bool found = true;
|
||||
assert( !m_connName[0] );
|
||||
const char* delim = strchr( connName, CONNNAME_DELIM );
|
||||
assert( !!delim );
|
||||
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
char buf[5];
|
||||
snprintf( buf, sizeof(buf), "%.4X", iter->m_seed );
|
||||
const char* match = strstr( connName, buf );
|
||||
if ( !match || match > delim ) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
} /* SeedsBelong */
|
||||
|
||||
void
|
||||
CookieRef::assignConnName( void )
|
||||
{
|
||||
if ( '\0' == ConnName()[0] ) {
|
||||
|
||||
vector<HostRec>::iterator iter;
|
||||
for ( iter = m_sockets.begin(); iter != m_sockets.end(); ++iter ) {
|
||||
char buf[5];
|
||||
snprintf( buf, sizeof(buf), "%.4X", iter->m_seed );
|
||||
m_connName += buf;
|
||||
}
|
||||
|
||||
m_connName += CONNNAME_DELIM + PermID::GetNextUniqueID();
|
||||
|
||||
logf( XW_LOGINFO, "%s: assigning name: %s", __func__, ConnName() );
|
||||
} else {
|
||||
logf( XW_LOGINFO, "%s: already named: %s", __func__, ConnName() );
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CookieRef::disconnectSockets( int socket, XWREASON why )
|
||||
{
|
||||
|
@ -997,7 +1071,7 @@ CookieRef::_PrintCookieInfo( string& out )
|
|||
} /* PrintCookieInfo */
|
||||
|
||||
void
|
||||
CookieRef::_FormatHostInfo( string* hostIds, string* addrs )
|
||||
CookieRef::_FormatHostInfo( string* hostIds, string* seeds, string* addrs )
|
||||
{
|
||||
ASSERT_LOCKED();
|
||||
vector<HostRec>::iterator iter;
|
||||
|
@ -1009,6 +1083,12 @@ CookieRef::_FormatHostInfo( string* hostIds, string* addrs )
|
|||
*hostIds += buf;
|
||||
}
|
||||
|
||||
if ( !!seeds ) {
|
||||
char buf[6];
|
||||
snprintf( buf, sizeof(buf), "%.4X ", iter->m_seed );
|
||||
*seeds += buf;
|
||||
}
|
||||
|
||||
if ( !!addrs ) {
|
||||
int s = iter->m_socket;
|
||||
struct sockaddr_in name;
|
||||
|
|
|
@ -37,17 +37,20 @@ class CookieMapIterator; /* forward */
|
|||
|
||||
struct HostRec {
|
||||
public:
|
||||
HostRec(HostID hostID, int socket, int nPlayersH, int nPlayersT)
|
||||
HostRec(HostID hostID, int socket, int nPlayersH, int nPlayersT,
|
||||
int seed )
|
||||
: m_hostID(hostID)
|
||||
, m_socket(socket)
|
||||
, m_nPlayersH(nPlayersH)
|
||||
, m_nPlayersT(nPlayersT)
|
||||
, m_seed(seed)
|
||||
, m_lastHeartbeat(uptime())
|
||||
{}
|
||||
HostID m_hostID;
|
||||
int m_socket;
|
||||
int m_nPlayersH;
|
||||
int m_nPlayersT;
|
||||
int m_seed;
|
||||
time_t m_lastHeartbeat;
|
||||
};
|
||||
|
||||
|
@ -76,8 +79,6 @@ class CookieRef {
|
|||
int GetPlayersSought() { return m_nPlayersSought; }
|
||||
int GetPlayersHere() { return m_nPlayersHere; }
|
||||
|
||||
|
||||
bool HostKnown( HostID host ) { return -1 != SocketForHost( host ); }
|
||||
int CountSockets() { return m_sockets.size(); }
|
||||
bool HasSocket( int socket );
|
||||
bool HasSocket_locked( int socket );
|
||||
|
@ -88,12 +89,13 @@ class CookieRef {
|
|||
int SocketForHost( HostID dest );
|
||||
|
||||
bool NeverFullyConnected();
|
||||
bool GameOpen( HostID hid, const char* cookie, int nPlayersH, bool isNew );
|
||||
bool GameOpen( const char* cookie, int nPlayersH, bool isNew,
|
||||
bool* alreadyHere );
|
||||
|
||||
/* for console */
|
||||
void _PrintCookieInfo( string& out );
|
||||
void PrintSocketInfo( string& out, int socket );
|
||||
void _FormatHostInfo( string* hostIds, string* addrs );
|
||||
void _FormatHostInfo( string* hostIds, string* seeds, string* addrs );
|
||||
|
||||
static CookieMapIterator GetCookieIterator();
|
||||
|
||||
|
@ -101,8 +103,10 @@ class CookieRef {
|
|||
static void Delete( CookieID id );
|
||||
static void Delete( const char* name );
|
||||
|
||||
void _Connect( int socket, HostID srcID, int nPlayersH, int nPlayersT );
|
||||
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersT );
|
||||
void _Connect( int socket, HostID srcID, int nPlayersH, int nPlayersT,
|
||||
int seed );
|
||||
void _Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersT,
|
||||
int seed );
|
||||
void _Disconnect(int socket, HostID hostID );
|
||||
void _Shutdown();
|
||||
void _HandleHeartbeat( HostID id, int socket );
|
||||
|
@ -129,6 +133,7 @@ class CookieRef {
|
|||
int socket;
|
||||
int nPlayersH;
|
||||
int nPlayersT;
|
||||
int seed;
|
||||
HostID srcID;
|
||||
} con;
|
||||
struct {
|
||||
|
@ -162,9 +167,11 @@ class CookieRef {
|
|||
}
|
||||
|
||||
void pushConnectEvent( int socket, HostID srcID,
|
||||
int nPlayersH, int nPlayersT );
|
||||
int nPlayersH, int nPlayersT,
|
||||
int seed );
|
||||
void pushReconnectEvent( int socket, HostID srcID,
|
||||
int nPlayersH, int nPlayersT );
|
||||
int nPlayersH, int nPlayersT,
|
||||
int seed );
|
||||
void pushHeartbeatEvent( HostID id, int socket );
|
||||
void pushHeartFailedEvent( int socket );
|
||||
|
||||
|
@ -194,6 +201,8 @@ class CookieRef {
|
|||
void notifyDisconn(const CRefEvent* evt);
|
||||
void removeSocket( int socket );
|
||||
void sendAllHere( void );
|
||||
bool SeedBelongs( int gameSeed );
|
||||
bool SeedsBelong( const char* connName );
|
||||
void assignConnName( void );
|
||||
void assignHostIds( void );
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@
|
|||
#include "mlock.h"
|
||||
#include "configs.h"
|
||||
#include "timermgr.h"
|
||||
#include "permid.h"
|
||||
|
||||
class SocketStuff {
|
||||
public:
|
||||
|
@ -104,19 +103,35 @@ CRefMgr::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.)
|
||||
/* Find a game to which this guy belongs. Return NULL if none's found and
|
||||
* presumably a new one will be created.
|
||||
*
|
||||
* Match by connName if provided. If I match, great. But what if there isn't
|
||||
* room, which would normally mean I'm already there and this is a duplicate
|
||||
* packet. Should a dup be simply dropped, or should I reply? If the dup
|
||||
* happened because our earlier reply was dropped then we should in fact
|
||||
* reply.
|
||||
*
|
||||
* If match is by cookie (called Room in the UI) we need to be careful. If
|
||||
* this is an established game, meaning that at some point all devices were
|
||||
* there and a connName was established, then check if the incoming seed is in
|
||||
* that connName, otherwise reject it (to form its own game.) But otherwise,
|
||||
* if either we can't match seeds yet or this guy's does match, let him in.
|
||||
* Again there's the duplicate packet issue if the game is "full" already.
|
||||
*
|
||||
* Match can also occur on cookie only -- device has no connName perhaps
|
||||
* because the relay crashed before sending it -- where the device belongs in
|
||||
* an existing game. That we detect by checking if the new arrival's seed is
|
||||
* a component of the candidate's connName.
|
||||
*/
|
||||
|
||||
CookieRef*
|
||||
CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
|
||||
HostID hid, int socket, int nPlayersH, int nPlayersT )
|
||||
HostID hid, int socket, int nPlayersH, int nPlayersT,
|
||||
int gameSeed, bool* alreadyHere )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s(cookie=%s,connName=%s,hid=%d,socket=%d)", __func__,
|
||||
cookie, connName, hid, socket );
|
||||
logf( XW_LOGINFO, "%s(cookie=%s,connName=%s,hid=%d,seed=%x,socket=%d)", __func__,
|
||||
cookie, connName, hid, gameSeed, socket );
|
||||
CookieRef* found = NULL;
|
||||
|
||||
if ( !!cookie || !!connName ) { /* drop if both are null */
|
||||
|
@ -133,28 +148,46 @@ CRefMgr::FindOpenGameFor( const char* cookie, const char* connName,
|
|||
if ( 0 == strcmp( cref->ConnName(), connName ) ) {
|
||||
if ( cref->Lock() ) {
|
||||
assert( !cookie || 0 == strcmp( cookie, cref->Cookie() ) );
|
||||
if ( cref->GameOpen( hid, cookie,
|
||||
nPlayersH, false ) ) {
|
||||
if ( cref->SeedBelongs( gameSeed ) ) {
|
||||
logf( XW_LOGINFO, "%s: SeedBelongs: dup packet?", __func__ );
|
||||
*alreadyHere = true;
|
||||
found = cref;
|
||||
} else if ( cref->GameOpen( cookie, nPlayersH,
|
||||
false, alreadyHere ) ) {
|
||||
found = cref;
|
||||
} else {
|
||||
/* drop if we match on connName and it's not
|
||||
wanted; must be dup. */
|
||||
*alreadyHere = true;
|
||||
}
|
||||
cref->Unlock();
|
||||
}
|
||||
}
|
||||
} else if ( !!cookie ) {
|
||||
}
|
||||
|
||||
if ( !found && !!cookie ) {
|
||||
if ( 0 == strcmp( cref->Cookie(), cookie ) ) {
|
||||
if ( cref->NeverFullyConnected() ) {
|
||||
found = cref;
|
||||
} else {
|
||||
if ( cref->Lock() ) {
|
||||
if ( cref->GameOpen( hid, cookie,
|
||||
nPlayersH, true ) ) {
|
||||
found = cref;
|
||||
} else if ( cref->HasSocket_locked(socket) ) {
|
||||
logf( XW_LOGINFO, "%s: HasSocket case", __func__);
|
||||
if ( cref->Lock() ) {
|
||||
if ( cref->ConnName()[0] ) {
|
||||
/* if has a connName, we can tell if belongs */
|
||||
if ( cref->SeedBelongs( gameSeed ) ) {
|
||||
found = cref;
|
||||
}
|
||||
cref->Unlock();
|
||||
} else if ( !!connName ) {
|
||||
/* Or, if we have a connName and it doesn't,
|
||||
perhaps we have its name. Does our name
|
||||
contain its other members? */
|
||||
if ( cref->SeedsBelong( connName ) ) {
|
||||
found = cref;
|
||||
}
|
||||
} else if ( cref->GameOpen( cookie, nPlayersH,
|
||||
true, alreadyHere ) ) {
|
||||
found = cref;
|
||||
} else if ( cref->HasSocket_locked(socket) ) {
|
||||
logf( XW_LOGINFO, "%s: HasSocket case", __func__);
|
||||
found = cref;
|
||||
}
|
||||
cref->Unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -212,7 +245,7 @@ CRefMgr::GetStats( CrefMgrInfo& mgrInfo )
|
|||
info.m_startTime = cref->GetStarttime();
|
||||
|
||||
SafeCref sc(cref);
|
||||
sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostIps );
|
||||
sc.GetHostsConnected( &info.m_hostsIds, &info.m_hostSeeds, &info.m_hostIps );
|
||||
|
||||
mgrInfo.m_crefInfo.push_back( info );
|
||||
}
|
||||
|
@ -263,7 +296,7 @@ CRefMgr::getFromFreeList( void )
|
|||
CookieRef*
|
||||
CRefMgr::getMakeCookieRef_locked( const char* cookie, const char* connName,
|
||||
HostID hid, int socket, int nPlayersH,
|
||||
int nPlayersT )
|
||||
int nPlayersT, int gameSeed )
|
||||
{
|
||||
CookieRef* cref;
|
||||
|
||||
|
@ -275,14 +308,11 @@ CRefMgr::getMakeCookieRef_locked( const char* cookie, const char* connName,
|
|||
later when the game is complete.
|
||||
*/
|
||||
|
||||
cref = FindOpenGameFor( cookie, connName, hid, socket, nPlayersH, nPlayersT );
|
||||
if ( cref == NULL ) {
|
||||
string s;
|
||||
if ( NULL == connName ) {
|
||||
s = PermID::GetNextUniqueID();
|
||||
connName = s.c_str();
|
||||
}
|
||||
cref = AddNew( cookie, connName, nextCID( NULL ) );
|
||||
bool alreadyHere;
|
||||
cref = FindOpenGameFor( cookie, connName, hid, socket, nPlayersH, nPlayersT,
|
||||
gameSeed, &alreadyHere );
|
||||
if ( cref == NULL && !alreadyHere ) {
|
||||
cref = AddNew( cookie, connName, gameSeed, nextCID( NULL ) );
|
||||
}
|
||||
|
||||
return cref;
|
||||
|
@ -411,10 +441,11 @@ CRefMgr::heartbeatProc( void* closure )
|
|||
#endif
|
||||
|
||||
CookieRef*
|
||||
CRefMgr::AddNew( const char* cookie, const char* connName, CookieID id )
|
||||
CRefMgr::AddNew( const char* cookie, const char* connName, int seed,
|
||||
CookieID id )
|
||||
{
|
||||
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, cid=%d)", __func__,
|
||||
cookie, connName, id );
|
||||
logf( XW_LOGINFO, "%s( cookie=%s, connName=%s, seed=%.4X, cid=%d)", __func__,
|
||||
cookie, connName, seed, id );
|
||||
|
||||
CookieRef* ref = getFromFreeList();
|
||||
|
||||
|
@ -575,7 +606,8 @@ CookieMapIterator::Next()
|
|||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SafeCref::SafeCref( const char* cookie, const char* connName, HostID hid,
|
||||
int socket, int nPlayersH, int nPlayersT )
|
||||
int socket, int nPlayersH, int nPlayersT,
|
||||
unsigned short gameSeed )
|
||||
: m_cref( NULL )
|
||||
, m_mgr( CRefMgr::Get() )
|
||||
, m_isValid( false )
|
||||
|
@ -583,7 +615,7 @@ SafeCref::SafeCref( const char* cookie, const char* connName, HostID hid,
|
|||
CookieRef* cref;
|
||||
|
||||
cref = m_mgr->getMakeCookieRef_locked( cookie, connName, hid, socket,
|
||||
nPlayersH, nPlayersT );
|
||||
nPlayersH, nPlayersT, gameSeed );
|
||||
if ( cref != NULL ) {
|
||||
m_locked = cref->Lock();
|
||||
m_cref = cref;
|
||||
|
|
|
@ -56,6 +56,7 @@ class CrefInfo {
|
|||
time_t m_startTime;
|
||||
int m_nHosts;
|
||||
string m_hostsIds;
|
||||
string m_hostSeeds;
|
||||
string m_hostIps;
|
||||
};
|
||||
|
||||
|
@ -126,15 +127,17 @@ class CRefMgr {
|
|||
|
||||
CookieRef* getMakeCookieRef_locked( const char* cookie, const char* connName,
|
||||
HostID hid, int socket,
|
||||
int nPlayersH, int nPlayersT );
|
||||
int nPlayersH, int nPlayersT, int seed );
|
||||
CookieRef* getCookieRef( CookieID cookieID );
|
||||
CookieRef* getCookieRef( int socket );
|
||||
bool checkCookieRef_locked( CookieRef* cref );
|
||||
CookieRef* getCookieRef_impl( CookieID cookieID );
|
||||
CookieRef* AddNew( const char* cookie, const char* connName, CookieID id );
|
||||
CookieRef* AddNew( const char* cookie, const char* connName, int seed,
|
||||
CookieID id );
|
||||
CookieRef* FindOpenGameFor( const char* cookie, const char* connName,
|
||||
HostID hid, int socket, int nPlayersH,
|
||||
int nPlayersT );
|
||||
int nPlayersT, int gameSeed,
|
||||
bool* alreadyHere );
|
||||
|
||||
CookieID cookieIDForConnName( const char* connName );
|
||||
CookieID nextCID( const char* connName );
|
||||
|
@ -164,7 +167,8 @@ class SafeCref {
|
|||
|
||||
public:
|
||||
SafeCref( const char* cookie, const char* connName, HostID hid,
|
||||
int socket, int nPlayersH, int nPlayersT );
|
||||
int socket, int nPlayersH, int nPlayersT,
|
||||
unsigned short gameSeed );
|
||||
SafeCref( CookieID cid, bool failOk = false );
|
||||
SafeCref( int socket );
|
||||
SafeCref( CookieRef* cref );
|
||||
|
@ -178,17 +182,19 @@ class SafeCref {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
bool Connect( int socket, HostID srcID, int nPlayersH, int nPlayersT ) {
|
||||
bool Connect( int socket, HostID srcID, int nPlayersH, int nPlayersT,
|
||||
int seed ) {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_Connect( socket, srcID, nPlayersH, nPlayersT );
|
||||
m_cref->_Connect( socket, srcID, nPlayersH, nPlayersT, seed );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersT ) {
|
||||
bool Reconnect( int socket, HostID srcID, int nPlayersH, int nPlayersT,
|
||||
int seed ) {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_Reconnect( socket, srcID, nPlayersH, nPlayersT );
|
||||
m_cref->_Reconnect( socket, srcID, nPlayersH, nPlayersT, seed );
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
@ -290,9 +296,9 @@ class SafeCref {
|
|||
}
|
||||
}
|
||||
|
||||
void GetHostsConnected( string* hosts, string* addrs ) {
|
||||
void GetHostsConnected( string* hosts, string* seeds, string* addrs ) {
|
||||
if ( IsValid() ) {
|
||||
m_cref->_FormatHostInfo( hosts, addrs );
|
||||
m_cref->_FormatHostInfo( hosts, seeds, addrs );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -305,13 +311,13 @@ class SafeCref {
|
|||
}
|
||||
|
||||
bool IsValid() { return m_isValid; }
|
||||
private:
|
||||
|
||||
private:
|
||||
CookieRef* m_cref;
|
||||
CRefMgr* m_mgr;
|
||||
bool m_isValid;
|
||||
bool m_locked;
|
||||
};
|
||||
}; /* SafeCref class */
|
||||
|
||||
|
||||
class CookieMapIterator {
|
||||
|
|
|
@ -126,6 +126,7 @@ printCrefs( FILE* fil, const CrefMgrInfo* info, bool isLocal )
|
|||
"<th>Here</th>"
|
||||
"<th>State</th>"
|
||||
"<th>Host IDs</th>"
|
||||
"<th>Seeds</th>"
|
||||
);
|
||||
if ( isLocal ) {
|
||||
fprintf( fil, "<th>Host IPs</th>" );
|
||||
|
@ -150,7 +151,8 @@ printCrefs( FILE* fil, const CrefMgrInfo* info, bool isLocal )
|
|||
"<td>%d</td>" /* players */
|
||||
"<td>%d</td>" /* players here */
|
||||
"<td>%s</td>" /* State */
|
||||
"<td>%s</td>" /* Hosts */
|
||||
"<td>%s</td>" /* Hosts */
|
||||
"<td>%s</td>" /* Seeds */
|
||||
,
|
||||
crefInfo->m_cookie.c_str(),
|
||||
crefInfo->m_connName.c_str(),
|
||||
|
@ -159,7 +161,8 @@ printCrefs( FILE* fil, const CrefMgrInfo* info, bool isLocal )
|
|||
crefInfo->m_totalSent,
|
||||
crefInfo->m_nPlayersSought, crefInfo->m_nPlayersHere,
|
||||
stateString( crefInfo->m_curState ),
|
||||
crefInfo->m_hostsIds.c_str()
|
||||
crefInfo->m_hostsIds.c_str(),
|
||||
crefInfo->m_hostSeeds.c_str()
|
||||
);
|
||||
|
||||
if ( isLocal ) {
|
||||
|
|
|
@ -296,18 +296,22 @@ processConnect( unsigned char* bufp, int bufLen, int socket )
|
|||
HostID srcID;
|
||||
unsigned char nPlayersH;
|
||||
unsigned char nPlayersT;
|
||||
unsigned short gameSeed;
|
||||
if ( readStr( &bufp, end, cookie, sizeof(cookie) )
|
||||
&& getNetByte( &bufp, end, &srcID )
|
||||
&& getNetByte( &bufp, end, &nPlayersH )
|
||||
&& getNetByte( &bufp, end, &nPlayersT ) ) {
|
||||
&& getNetByte( &bufp, end, &nPlayersT )
|
||||
&& getNetShort( &bufp, end, &gameSeed ) ) {
|
||||
|
||||
/* Make sure second thread can't create new cref for same cookie
|
||||
this one just handled.*/
|
||||
static pthread_mutex_t s_newCookieLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
MutexLock ml( &s_newCookieLock );
|
||||
|
||||
SafeCref scr( cookie, NULL, srcID, socket, nPlayersH, nPlayersT );
|
||||
success = scr.Connect( socket, srcID, nPlayersH, nPlayersT );
|
||||
SafeCref scr( cookie, NULL, srcID, socket, nPlayersH, nPlayersT, gameSeed );
|
||||
/* nPlayersT etc could be slots in SafeCref to avoid passing
|
||||
here */
|
||||
success = scr.Connect( socket, srcID, nPlayersH, nPlayersT, gameSeed );
|
||||
}
|
||||
|
||||
if ( !success ) {
|
||||
|
@ -335,19 +339,22 @@ processReconnect( unsigned char* bufp, int bufLen, int socket )
|
|||
HostID srcID;
|
||||
unsigned char nPlayersH;
|
||||
unsigned char nPlayersT;
|
||||
unsigned short gameSeed;
|
||||
|
||||
connName[0] = '\0';
|
||||
if ( readStr( &bufp, end, cookie, sizeof(cookie) )
|
||||
&& getNetByte( &bufp, end, &srcID )
|
||||
&& getNetByte( &bufp, end, &nPlayersH )
|
||||
&& getNetByte( &bufp, end, &nPlayersT )
|
||||
&& getNetShort( &bufp, end, &gameSeed )
|
||||
&& readStr( &bufp, end, connName, sizeof(connName) ) ) {
|
||||
|
||||
SafeCref scr( cookie[0]? cookie : NULL,
|
||||
connName[0]? connName : NULL,
|
||||
srcID, socket, nPlayersH,
|
||||
nPlayersT );
|
||||
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT );
|
||||
nPlayersT, gameSeed );
|
||||
success = scr.Reconnect( socket, srcID, nPlayersH, nPlayersT,
|
||||
gameSeed );
|
||||
}
|
||||
|
||||
if ( !success ) {
|
||||
|
@ -770,6 +777,8 @@ main( int argc, char** argv )
|
|||
/* Needs to be reset after a crash/respawn */
|
||||
PermID::SetStartTime( time(NULL) );
|
||||
|
||||
logf( XW_LOGERROR, "***** forked %dth new process *****", s_nSpawns );
|
||||
|
||||
/* Arrange to be sent SIGUSR1 on death of parent. */
|
||||
prctl( PR_SET_PDEATHSIG, SIGUSR1 );
|
||||
|
||||
|
@ -829,13 +838,11 @@ main( int argc, char** argv )
|
|||
struct sigaction act;
|
||||
memset( &act, 0, sizeof(act) );
|
||||
act.sa_handler = SIGINT_handler;
|
||||
int err = sigaction( SIGINT, &act, NULL );
|
||||
logf( XW_LOGERROR, "sigaction=>%d", err );
|
||||
(void)sigaction( SIGINT, &act, NULL );
|
||||
|
||||
XWThreadPool* tPool = XWThreadPool::GetTPool();
|
||||
tPool->Setup( nWorkerThreads, processMessage );
|
||||
|
||||
|
||||
/* set up select call */
|
||||
fd_set rfds;
|
||||
for ( ; ; ) {
|
||||
|
|
|
@ -101,9 +101,11 @@ typedef unsigned char XWRELAY_Cmd;
|
|||
|
||||
#define MAX_INVITE_LEN 15
|
||||
#define MAX_MSG_LEN 256 /* 100 is more like it */
|
||||
#define MAX_CONNNAME_LEN 35 /* host id plus a small integer, typically */
|
||||
#define MAX_CONNNAME_LEN 48 /* host ID, boot time, and seeds as hex? */
|
||||
|
||||
#define XWRELAY_PROTO_VERSION 0x01
|
||||
#define XWRELAY_PROTO_VERSION_ORIG 0x01
|
||||
#define XWRELAY_PROTO_VERSION_LATE_NAME 0x02
|
||||
#define XWRELAY_PROTO_VERSION XWRELAY_PROTO_VERSION_LATE_NAME
|
||||
|
||||
/* Errors passed with denied */
|
||||
#ifndef CANT_DO_TYPEDEF
|
||||
|
|
Loading…
Reference in a new issue