add support for relay for use by NAT'd/firewalled devices: cellphones.

Include cookie users will agree on on for relay rendevouz, and
sender/receiver IDs for when there are >2 devices in game.  Supports
games between linux clients now, but needs a lot more work.
This commit is contained in:
ehouse 2005-03-06 17:56:34 +00:00
parent 71870695cc
commit cb3a3854e9

View file

@ -27,6 +27,7 @@
#include "game.h" #include "game.h"
#include "xwstream.h" #include "xwstream.h"
#include "memstream.h" #include "memstream.h"
#include "strutils.h"
#define cEND 0x65454e44 #define cEND 0x65454e44
@ -42,6 +43,8 @@ typedef struct MsgQueueElem {
MsgID msgID; MsgID msgID;
} MsgQueueElem; } MsgQueueElem;
typedef XP_U16 HostID;
typedef struct AddressRecord { typedef struct AddressRecord {
struct AddressRecord* next; struct AddressRecord* next;
CommsAddrRec addr; CommsAddrRec addr;
@ -52,6 +55,7 @@ typedef struct AddressRecord {
MsgID nextMsgID; /* on a per-channel basis */ MsgID nextMsgID; /* on a per-channel basis */
MsgID lastMsgReceived; /* on a per-channel basis */ MsgID lastMsgReceived; /* on a per-channel basis */
XP_PlayerAddr channelNo; XP_PlayerAddr channelNo;
HostID remotesID;
} AddressRecord; } AddressRecord;
#define ADDRESSRECORD_SIZE_68K 20 #define ADDRESSRECORD_SIZE_68K 20
@ -62,6 +66,7 @@ struct CommsCtxt {
XP_U32 connID; /* 0 means ignore; otherwise must match */ XP_U32 connID; /* 0 means ignore; otherwise must match */
XP_U16 nextChannelNo; XP_U16 nextChannelNo;
AddressRecord* recs; /* return addresses */ AddressRecord* recs; /* return addresses */
HostID localID; /* allows relay to match host with socket */
TransportSend sendproc; TransportSend sendproc;
void* sendClosure; void* sendClosure;
@ -87,6 +92,7 @@ struct CommsCtxt {
****************************************************************************/ ****************************************************************************/
static AddressRecord* rememberChannelAddress( CommsCtxt* comms, static AddressRecord* rememberChannelAddress( CommsCtxt* comms,
XP_PlayerAddr channelNo, XP_PlayerAddr channelNo,
HostID hostID,
CommsAddrRec* addr ); CommsAddrRec* addr );
static XP_Bool channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo, static XP_Bool channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
CommsAddrRec** addr ); CommsAddrRec** addr );
@ -103,6 +109,7 @@ CommsCtxt*
comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer, comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
TransportSend sendproc, void* closure ) TransportSend sendproc, void* closure )
{ {
HostID localID;
CommsCtxt* result = (CommsCtxt*)XP_MALLOC( mpool, sizeof(*result) ); CommsCtxt* result = (CommsCtxt*)XP_MALLOC( mpool, sizeof(*result) );
XP_MEMSET( result, 0, sizeof(*result) ); XP_MEMSET( result, 0, sizeof(*result) );
@ -124,6 +131,10 @@ comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
XP_MEMCPY( result->addr.u.ip.hostName, name, XP_STRLEN(name) ); XP_MEMCPY( result->addr.u.ip.hostName, name, XP_STRLEN(name) );
} }
#endif #endif
do {
localID = XP_RANDOM();
} while ( localID == 0 );
result->localID = localID;
return result; return result;
} /* comms_make */ } /* comms_make */
@ -375,6 +386,7 @@ comms_send( CommsCtxt* comms, CommsConnType conType, XWStreamCtxt* stream )
AddressRecord* rec = getRecordFor( comms, channelNo ); AddressRecord* rec = getRecordFor( comms, channelNo );
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0; MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
MsgID lastMsgRcd = (!!rec)? rec->lastMsgReceived : 0; MsgID lastMsgRcd = (!!rec)? rec->lastMsgReceived : 0;
HostID remotesID = (!!rec)? rec->remotesID : 0;
MsgQueueElem* newMsgElem; MsgQueueElem* newMsgElem;
XWStreamCtxt* msgStream; XWStreamCtxt* msgStream;
@ -398,16 +410,24 @@ comms_send( CommsCtxt* comms, CommsConnType conType, XWStreamCtxt* stream )
NULL, 0, NULL, 0,
(MemStreamCloseCallback)NULL ); (MemStreamCloseCallback)NULL );
stream_open( msgStream ); stream_open( msgStream );
stream_putU32( msgStream, comms->connID );
#ifdef BEYOND_IR #ifdef BEYOND_IR
if ( conType == COMMS_CONN_IP ) { /* This will change, of course!!! */
stream_putU16( msgStream, comms->listenPort ); stringToStream( msgStream, "COOKIE" );
XP_LOGF( "wrote return port to stream: %d", comms->listenPort ); stream_putU16( msgStream, comms->localID );
} XP_LOGF( "localID = 0x%x", comms->localID );
#endif #endif
stream_putU32( msgStream, comms->connID );
XP_LOGF( "connID: %ld", comms->connID );
stream_putU16( msgStream, channelNo ); stream_putU16( msgStream, channelNo );
XP_LOGF( "channelNo: %d", channelNo );
#ifdef BEYOND_IR
stream_putU16( msgStream, remotesID ); /* for the relay's use */
XP_LOGF( "remotesID = %ld", remotesID );
#endif
/* Beyond this point the relay doesn't peek */
stream_putU32( msgStream, msgID ); stream_putU32( msgStream, msgID );
stream_putU32( msgStream, lastMsgRcd ); stream_putU32( msgStream, lastMsgRcd );
@ -585,20 +605,30 @@ comms_checkIncommingStream( CommsCtxt* comms, XWStreamCtxt* stream,
MsgID lastMsgRcd; MsgID lastMsgRcd;
XP_Bool validMessage = XP_TRUE; XP_Bool validMessage = XP_TRUE;
AddressRecord* recs = (AddressRecord*)NULL; AddressRecord* recs = (AddressRecord*)NULL;
XP_UCHAR* cookie;
HostID senderID, hostID;
#ifdef BEYOND_IR
cookie = stringFromStream( MPPARM(comms->mpool) stream );
XP_LOGF( "got cookie %s from message", cookie );
XP_ASSERT( 0 == XP_MEMCMP( cookie, "COOKIE", 6 ) );
senderID = stream_getU16( stream );
XP_LOGF( "senderID = 0x%x", senderID );
#endif
connID = stream_getU32( stream ); connID = stream_getU32( stream );
XP_STATUSF( "read connID of %lx", connID ); XP_STATUSF( "read connID of %lx", connID );
#ifdef BEYOND_IR if ( senderID != 0 && senderID == comms->localID ) {
if ( addr->conType == COMMS_CONN_IP ) { validMessage = XP_FALSE; /* hack around relay bug */
addr->u.ip.port = stream_getU16( stream ); } else if ( comms->connID == connID || comms->connID == CONN_ID_NONE ) {
XP_LOGF( "read return port from stream: %d", addr->u.ip.port );
}
#endif
if ( comms->connID == connID || comms->connID == CONN_ID_NONE ) {
channelNo = stream_getU16( stream ); channelNo = stream_getU16( stream );
#ifdef BEYOND_IR
hostID = stream_getU16( stream );
XP_LOGF( "got hostID: %d", hostID );
XP_ASSERT( hostID == 0 || hostID == comms->localID );
#endif
msgID = stream_getU32( stream ); msgID = stream_getU32( stream );
lastMsgRcd = stream_getU32( stream ); lastMsgRcd = stream_getU32( stream );
@ -607,10 +637,13 @@ comms_checkIncommingStream( CommsCtxt* comms, XWStreamCtxt* stream,
removeFromQueue( comms, channelNo, lastMsgRcd ); removeFromQueue( comms, channelNo, lastMsgRcd );
if ( channelNo == 0 ) { if ( channelNo == 0 ) {
XP_ASSERT( comms->isServer ); if ( !comms->isServer ) {
validMessage = XP_FALSE;
} else {
XP_ASSERT( msgID == 0 ); XP_ASSERT( msgID == 0 );
channelNo = ++comms->nextChannelNo; channelNo = ++comms->nextChannelNo;
XP_STATUSF( "assigning channelNo=%d", channelNo ); XP_STATUSF( "assigning channelNo=%d", channelNo );
}
} else { } else {
recs = getRecordFor( comms, channelNo ); recs = getRecordFor( comms, channelNo );
/* messageID for an incomming message should be one greater than /* messageID for an incomming message should be one greater than
@ -629,7 +662,7 @@ comms_checkIncommingStream( CommsCtxt* comms, XWStreamCtxt* stream,
} }
if ( validMessage ) { if ( validMessage ) {
recs = rememberChannelAddress( comms, channelNo, addr ); recs = rememberChannelAddress( comms, channelNo, senderID, addr);
stream_setAddress( stream, channelNo ); stream_setAddress( stream, channelNo );
@ -689,28 +722,33 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
static AddressRecord* static AddressRecord*
rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo, rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
CommsAddrRec* addr ) HostID hostID, CommsAddrRec* addr )
{ {
AddressRecord* recs = NULL; AddressRecord* recs = NULL;
if ( addr != NULL ) {
recs = getRecordFor( comms, channelNo ); recs = getRecordFor( comms, channelNo );
if ( !!recs ) { if ( !recs ) {
/* Looks as if this will overwrite the address each time a new
message comes in. I *guess* that's right... */
XP_MEMCPY( &recs->addr, addr, sizeof(recs->addr) );
} else {
/* not found; add a new entry */ /* not found; add a new entry */
recs = (AddressRecord*)XP_MALLOC( comms->mpool, sizeof(*recs) ); recs = (AddressRecord*)XP_MALLOC( comms->mpool, sizeof(*recs) );
recs->nextMsgID = 0; recs->nextMsgID = 0;
recs->channelNo = channelNo; recs->channelNo = channelNo;
XP_MEMCPY( &recs->addr, addr, sizeof(recs->addr) ); recs->remotesID = hostID;
#ifdef DEBUG #ifdef DEBUG
recs->nUniqueBytes = 0; recs->nUniqueBytes = 0;
#endif #endif
recs->next = comms->recs; recs->next = comms->recs;
comms->recs = recs; comms->recs = recs;
} }
/* overwrite existing address with new one. I assume that's the right
move. */
if ( !!recs ) {
if ( !!addr ) {
XP_MEMCPY( &recs->addr, addr, sizeof(recs->addr) );
XP_ASSERT( recs->remotesID == hostID );
} else {
XP_MEMSET( &recs->addr, 0, sizeof(recs->addr) );
}
} }
return recs; return recs;
} /* rememberChannelAddress */ } /* rememberChannelAddress */