2003-11-01 06:35:29 +01:00
|
|
|
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */
|
|
|
|
/*
|
2006-01-08 02:25:02 +01:00
|
|
|
* Copyright 2001-2005 by Eric House (xwords@eehouse.org). All rights reserved.
|
2003-11-01 06:35:29 +01:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef USE_STDIO
|
|
|
|
# include <stdio.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include "comms.h"
|
|
|
|
|
|
|
|
#include "util.h"
|
2004-10-09 01:54:57 +02:00
|
|
|
#include "game.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
#include "xwstream.h"
|
|
|
|
#include "memstream.h"
|
2005-03-19 23:01:38 +01:00
|
|
|
#include "xwrelay.h"
|
2005-03-06 18:56:34 +01:00
|
|
|
#include "strutils.h"
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#define cEND 0x65454e44
|
2005-06-23 06:16:53 +02:00
|
|
|
#define HEARTBEAT_NONE 0
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#ifndef XWFEATURE_STANDALONE_ONLY
|
|
|
|
|
2005-01-31 04:31:50 +01:00
|
|
|
EXTERN_C_START
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
typedef struct MsgQueueElem {
|
|
|
|
struct MsgQueueElem* next;
|
|
|
|
XP_U8* msg;
|
|
|
|
XP_U16 len;
|
|
|
|
XP_U16 channelNo;
|
2005-03-19 23:01:38 +01:00
|
|
|
MsgID msgID; /* saved for ease of deletion */
|
2003-11-01 06:35:29 +01:00
|
|
|
} MsgQueueElem;
|
|
|
|
|
|
|
|
typedef struct AddressRecord {
|
|
|
|
struct AddressRecord* next;
|
|
|
|
CommsAddrRec addr;
|
|
|
|
#ifdef DEBUG
|
|
|
|
XP_U16 lastACK;
|
|
|
|
XP_U16 nUniqueBytes;
|
|
|
|
#endif
|
2005-03-19 23:01:38 +01:00
|
|
|
MsgID nextMsgID; /* on a per-channel basis */
|
|
|
|
MsgID lastMsgReceived; /* on a per-channel basis */
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_PlayerAddr channelNo;
|
2006-10-02 16:26:56 +02:00
|
|
|
struct {
|
|
|
|
XWHostID hostID; /* used for relay case */
|
|
|
|
} r;
|
2003-11-01 06:35:29 +01:00
|
|
|
} AddressRecord;
|
|
|
|
|
2004-10-09 01:54:57 +02:00
|
|
|
#define ADDRESSRECORD_SIZE_68K 20
|
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
typedef enum {
|
|
|
|
COMMS_RELAYSTATE_UNCONNECTED
|
|
|
|
, COMMS_RELAYSTATE_CONNECT_PENDING
|
|
|
|
, COMMS_RELAYSTATE_CONNECTED
|
2005-10-02 17:39:38 +02:00
|
|
|
, COMMS_RELAYSTATE_ALLCONNECTED
|
2006-10-07 05:37:40 +02:00
|
|
|
} CommsRelayState;
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
struct CommsCtxt {
|
|
|
|
XW_UtilCtxt* util;
|
|
|
|
|
|
|
|
XP_U32 connID; /* 0 means ignore; otherwise must match */
|
|
|
|
XP_U16 nextChannelNo;
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
AddressRecord* recs; /* return addresses */
|
|
|
|
|
|
|
|
TransportSend sendproc;
|
|
|
|
void* sendClosure;
|
|
|
|
|
|
|
|
MsgQueueElem* msgQueueHead;
|
|
|
|
MsgQueueElem* msgQueueTail;
|
|
|
|
XP_U16 queueLen;
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
/* The following fields, down to isServer, are only used if
|
|
|
|
XWFEATURE_RELAY is defined, but I'm leaving them in here so apps built
|
|
|
|
both ways can open each other's saved games files.*/
|
2003-11-01 06:35:29 +01:00
|
|
|
CommsAddrRec addr;
|
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
/* Stuff for relays */
|
2006-10-02 16:26:56 +02:00
|
|
|
struct {
|
|
|
|
XWHostID myHostID; /* 0 if unset, 1 if acting as server,
|
|
|
|
random for client */
|
2006-10-07 05:37:40 +02:00
|
|
|
CommsRelayState relayState; /* not saved: starts at UNCONNECTED */
|
2006-10-02 16:26:56 +02:00
|
|
|
CookieID cookieID; /* not saved; temp standin for cookie; set
|
|
|
|
by relay */
|
|
|
|
/* permanent globally unique name, set by relay and forever after
|
|
|
|
associated with this game. Used to reconnect. */
|
|
|
|
XP_UCHAR connName[MAX_CONNNAME_LEN+1];
|
|
|
|
|
|
|
|
/* heartbeat: for periodic pings if relay thinks the network the
|
|
|
|
device is on requires them. Not saved since only valid when
|
|
|
|
connected, and we reconnect for every game and after restarting. */
|
|
|
|
XP_U16 heartbeat;
|
|
|
|
XP_U16 nPlayersHere;
|
|
|
|
XP_U16 nPlayersTotal;
|
|
|
|
XP_Bool connecting;
|
|
|
|
} r;
|
2006-04-07 05:08:23 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_Bool isServer;
|
|
|
|
#ifdef DEBUG
|
|
|
|
XP_U16 nUniqueBytes;
|
|
|
|
#endif
|
|
|
|
MPSLOT
|
|
|
|
};
|
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* prototypes
|
|
|
|
****************************************************************************/
|
|
|
|
static AddressRecord* rememberChannelAddress( CommsCtxt* comms,
|
|
|
|
XP_PlayerAddr channelNo,
|
2006-09-14 03:25:40 +02:00
|
|
|
XWHostID id,
|
|
|
|
const CommsAddrRec* addr );
|
2003-11-01 06:35:29 +01:00
|
|
|
static XP_Bool channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|
|
|
CommsAddrRec** addr );
|
|
|
|
static AddressRecord* getRecordFor( CommsCtxt* comms,
|
|
|
|
XP_PlayerAddr channelNo );
|
|
|
|
static XP_S16 sendMsg( CommsCtxt* comms, MsgQueueElem* elem );
|
|
|
|
static void addToQueue( CommsCtxt* comms, MsgQueueElem* newMsgElem );
|
2006-10-15 15:53:17 +02:00
|
|
|
static XP_U16 countAddrRecs( const CommsCtxt* comms );
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-06-23 06:16:53 +02:00
|
|
|
static void relayConnect( CommsCtxt* comms );
|
2005-09-05 17:33:51 +02:00
|
|
|
static void relayDisconnect( CommsCtxt* comms );
|
2005-06-23 06:16:53 +02:00
|
|
|
static XP_Bool send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd,
|
|
|
|
XWHostID destID, void* data, int dlen );
|
2005-03-19 23:01:38 +01:00
|
|
|
static XWHostID getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo );
|
2005-06-23 06:16:53 +02:00
|
|
|
static void setHeartbeatTimer( CommsCtxt* comms );
|
2006-10-10 03:34:37 +02:00
|
|
|
#endif
|
|
|
|
#ifdef XWFEATURE_BLUETOOTH
|
2006-08-26 23:12:10 +02:00
|
|
|
static void btConnect( CommsCtxt* comms );
|
2006-06-16 03:46:47 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
/****************************************************************************
|
|
|
|
* implementation
|
|
|
|
****************************************************************************/
|
|
|
|
CommsCtxt*
|
|
|
|
comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
|
2006-10-10 03:34:37 +02:00
|
|
|
XP_U16 XP_UNUSED_RELAY(nPlayersHere),
|
|
|
|
XP_U16 XP_UNUSED_RELAY(nPlayersTotal),
|
2003-11-01 06:35:29 +01:00
|
|
|
TransportSend sendproc, void* closure )
|
|
|
|
{
|
|
|
|
CommsCtxt* result = (CommsCtxt*)XP_MALLOC( mpool, sizeof(*result) );
|
|
|
|
XP_MEMSET( result, 0, sizeof(*result) );
|
|
|
|
|
|
|
|
MPASSIGN(result->mpool, mpool);
|
|
|
|
|
|
|
|
result->isServer = isServer;
|
|
|
|
result->sendproc = sendproc;
|
|
|
|
result->sendClosure = closure;
|
|
|
|
result->util = util;
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2006-10-02 16:26:56 +02:00
|
|
|
result->r.myHostID = isServer? HOST_ID_SERVER: HOST_ID_NONE;
|
|
|
|
XP_LOGF( "set myHostID to %d", result->r.myHostID );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2006-10-02 16:26:56 +02:00
|
|
|
result->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
|
|
|
result->r.nPlayersHere = nPlayersHere;
|
|
|
|
result->r.nPlayersTotal = nPlayersTotal;
|
2006-04-07 05:08:23 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
return result;
|
|
|
|
} /* comms_make */
|
|
|
|
|
|
|
|
static void
|
|
|
|
cleanupInternal( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
MsgQueueElem* msg;
|
|
|
|
MsgQueueElem* next;
|
|
|
|
|
|
|
|
for ( msg = comms->msgQueueHead; !!msg; msg = next ) {
|
2005-01-31 04:31:50 +01:00
|
|
|
next = msg->next;
|
|
|
|
XP_FREE( comms->mpool, msg->msg );
|
|
|
|
XP_FREE( comms->mpool, msg );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
comms->queueLen = 0;
|
|
|
|
comms->msgQueueHead = comms->msgQueueTail = (MsgQueueElem*)NULL;
|
|
|
|
} /* cleanupInternal */
|
|
|
|
|
|
|
|
static void
|
|
|
|
cleanupAddrRecs( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
AddressRecord* recs;
|
|
|
|
AddressRecord* next;
|
|
|
|
|
|
|
|
for ( recs = comms->recs; !!recs; recs = next ) {
|
|
|
|
next = recs->next;
|
|
|
|
XP_FREE( comms->mpool, recs );
|
|
|
|
}
|
|
|
|
comms->recs = (AddressRecord*)NULL;
|
|
|
|
} /* cleanupAddrRecs */
|
|
|
|
|
|
|
|
void
|
2005-10-02 17:39:38 +02:00
|
|
|
comms_reset( CommsCtxt* comms, XP_Bool isServer,
|
2006-10-10 03:34:37 +02:00
|
|
|
XP_U16 XP_UNUSED_RELAY(nPlayersHere),
|
|
|
|
XP_U16 XP_UNUSED_RELAY(nPlayersTotal) )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2007-02-06 06:49:45 +01:00
|
|
|
LOG_FUNC();
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-09-05 17:33:51 +02:00
|
|
|
relayDisconnect( comms );
|
|
|
|
#endif
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
cleanupInternal( comms );
|
|
|
|
comms->isServer = isServer;
|
|
|
|
|
|
|
|
cleanupAddrRecs( comms );
|
|
|
|
|
|
|
|
comms->nextChannelNo = 0;
|
|
|
|
|
|
|
|
comms->connID = CONN_ID_NONE;
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.cookieID = COOKIE_ID_NONE;
|
|
|
|
comms->r.nPlayersHere = nPlayersHere;
|
|
|
|
comms->r.nPlayersTotal = nPlayersTotal;
|
2005-09-05 17:33:51 +02:00
|
|
|
relayConnect( comms );
|
2005-09-04 22:30:47 +02:00
|
|
|
#endif
|
2007-02-06 06:49:45 +01:00
|
|
|
LOG_RETURN_VOID();
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* comms_reset */
|
|
|
|
|
|
|
|
void
|
|
|
|
comms_destroy( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
cleanupInternal( comms );
|
|
|
|
cleanupAddrRecs( comms );
|
|
|
|
|
|
|
|
XP_FREE( comms->mpool, comms );
|
|
|
|
} /* comms_destroy */
|
|
|
|
|
|
|
|
void
|
|
|
|
comms_setConnID( CommsCtxt* comms, XP_U32 connID )
|
|
|
|
{
|
|
|
|
comms->connID = connID;
|
2004-10-01 03:25:55 +02:00
|
|
|
XP_STATUSF( "set connID to %lx", connID );
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* comms_setConnID */
|
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
static void
|
|
|
|
addrFromStream( CommsAddrRec* addrP, XWStreamCtxt* stream )
|
|
|
|
{
|
|
|
|
CommsAddrRec addr;
|
|
|
|
|
2006-10-05 03:17:03 +02:00
|
|
|
addr.conType = stream_getU8( stream );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
|
|
|
switch( addr.conType ) {
|
|
|
|
case COMMS_CONN_UNUSED:
|
2005-09-02 08:26:33 +02:00
|
|
|
/* XP_ASSERT( 0 ); */
|
2005-03-19 23:01:38 +01:00
|
|
|
break;
|
|
|
|
case COMMS_CONN_BT:
|
2006-09-08 09:14:24 +02:00
|
|
|
stringFromStreamHere( stream, addr.u.bt.hostName,
|
|
|
|
sizeof(addr.u.bt.hostName) );
|
2006-09-23 18:04:53 +02:00
|
|
|
stream_getBytes( stream, &addr.u.bt.btAddr.bits,
|
|
|
|
sizeof(addr.u.bt.btAddr.bits) );
|
2006-09-08 09:14:24 +02:00
|
|
|
break;
|
2005-03-19 23:01:38 +01:00
|
|
|
case COMMS_CONN_IR:
|
|
|
|
/* nothing to save */
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_IP_NOUSE:
|
|
|
|
stringFromStreamHere( stream, addr.u.ip.hostName_ip,
|
|
|
|
sizeof(addr.u.ip.hostName_ip) );
|
|
|
|
addr.u.ip.ipAddr_ip = stream_getU32( stream );
|
|
|
|
addr.u.ip.port_ip = stream_getU16( stream );
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_RELAY:
|
|
|
|
stringFromStreamHere( stream, addr.u.ip_relay.cookie,
|
|
|
|
sizeof(addr.u.ip_relay.cookie) );
|
|
|
|
stringFromStreamHere( stream, addr.u.ip_relay.hostName,
|
|
|
|
sizeof(addr.u.ip_relay.hostName) );
|
|
|
|
addr.u.ip_relay.ipAddr = stream_getU32( stream );
|
|
|
|
addr.u.ip_relay.port = stream_getU16( stream );
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* shut up, compiler */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_MEMCPY( addrP, &addr, sizeof(*addrP) );
|
|
|
|
} /* addrFromStream */
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
CommsCtxt*
|
|
|
|
comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
|
|
|
|
TransportSend sendproc, void* closure )
|
|
|
|
{
|
|
|
|
CommsCtxt* comms;
|
|
|
|
XP_Bool isServer;
|
2005-10-02 17:39:38 +02:00
|
|
|
XP_U16 nAddrRecs, nPlayersHere, nPlayersTotal;
|
2003-11-01 06:35:29 +01:00
|
|
|
AddressRecord** prevsAddrNext;
|
|
|
|
MsgQueueElem** prevsQueueNext;
|
2006-10-05 03:17:03 +02:00
|
|
|
XP_U16 version = stream_getVersion( stream );
|
|
|
|
CommsAddrRec addr;
|
2005-03-08 06:33:38 +01:00
|
|
|
short i;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
isServer = stream_getU8( stream );
|
2006-10-05 03:17:03 +02:00
|
|
|
if ( version < STREAM_VERS_RELAY ) {
|
|
|
|
XP_MEMSET( &addr, 0, sizeof(addr) );
|
|
|
|
addr.conType = COMMS_CONN_IR; /* all there was back then */
|
|
|
|
} else {
|
|
|
|
addrFromStream( &addr, stream );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
nPlayersHere = (XP_U16)stream_getBits( stream, 4 );
|
|
|
|
nPlayersTotal = (XP_U16)stream_getBits( stream, 4 );
|
|
|
|
} else {
|
|
|
|
nPlayersHere = 0;
|
|
|
|
nPlayersTotal = 0;
|
|
|
|
}
|
2005-10-02 17:39:38 +02:00
|
|
|
comms = comms_make( MPPARM(mpool) util, isServer,
|
|
|
|
nPlayersHere, nPlayersTotal,
|
|
|
|
sendproc, closure );
|
2006-10-05 03:17:03 +02:00
|
|
|
XP_MEMCPY( &comms->addr, &addr, sizeof(comms->addr) );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
comms->connID = stream_getU32( stream );
|
|
|
|
comms->nextChannelNo = stream_getU16( stream );
|
2006-10-05 03:17:03 +02:00
|
|
|
if ( addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
comms->r.myHostID = stream_getU8( stream );
|
|
|
|
stringFromStreamHere( stream, comms->r.connName,
|
|
|
|
sizeof(comms->r.connName) );
|
|
|
|
}
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
comms->nUniqueBytes = stream_getU16( stream );
|
|
|
|
#endif
|
|
|
|
comms->queueLen = stream_getU8( stream );
|
|
|
|
|
|
|
|
nAddrRecs = stream_getU8( stream );
|
|
|
|
prevsAddrNext = &comms->recs;
|
|
|
|
for ( i = 0; i < nAddrRecs; ++i ) {
|
|
|
|
AddressRecord* rec = (AddressRecord*)XP_MALLOC( mpool, sizeof(*rec));
|
|
|
|
XP_MEMSET( rec, 0, sizeof(*rec) );
|
2004-10-02 05:47:24 +02:00
|
|
|
|
2006-10-05 03:17:03 +02:00
|
|
|
addrFromStream( &rec->addr, stream );
|
2004-10-09 01:54:57 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
rec->nextMsgID = stream_getU16( stream );
|
|
|
|
rec->lastMsgReceived = stream_getU16( stream );
|
|
|
|
rec->channelNo = stream_getU16( stream );
|
2006-10-05 03:17:03 +02:00
|
|
|
if ( rec->addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
rec->r.hostID = stream_getU8( stream );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
rec->lastACK = stream_getU16( stream );
|
|
|
|
rec->nUniqueBytes = stream_getU16( stream );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
*prevsAddrNext = rec;
|
|
|
|
prevsAddrNext = &rec->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
prevsQueueNext = &comms->msgQueueHead;
|
|
|
|
for ( i = 0; i < comms->queueLen; ++i ) {
|
|
|
|
MsgQueueElem* msg = (MsgQueueElem*)XP_MALLOC( mpool, sizeof(*msg) );
|
|
|
|
|
|
|
|
msg->channelNo = stream_getU16( stream );
|
|
|
|
msg->msgID = stream_getU32( stream );
|
|
|
|
|
|
|
|
msg->len = stream_getU16( stream );
|
|
|
|
msg->msg = (XP_U8*)XP_MALLOC( mpool, msg->len );
|
|
|
|
stream_getBytes( stream, msg->msg, msg->len );
|
|
|
|
|
|
|
|
msg->next = (MsgQueueElem*)NULL;
|
|
|
|
*prevsQueueNext = comms->msgQueueTail = msg;
|
|
|
|
comms->msgQueueTail = msg;
|
|
|
|
prevsQueueNext = &msg->next;
|
|
|
|
}
|
|
|
|
|
2004-10-02 05:47:24 +02:00
|
|
|
#ifdef DEBUG
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_ASSERT( stream_getU32( stream ) == cEND );
|
2004-10-02 05:47:24 +02:00
|
|
|
#endif
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
return comms;
|
|
|
|
} /* comms_makeFromStream */
|
|
|
|
|
2005-04-03 19:00:59 +02:00
|
|
|
void
|
2005-07-06 02:58:20 +02:00
|
|
|
comms_start( CommsCtxt* comms )
|
2005-04-03 19:00:59 +02:00
|
|
|
{
|
2006-10-10 03:34:37 +02:00
|
|
|
if ( 0 ) {
|
|
|
|
#ifdef XWFEATURE_RELAY
|
|
|
|
} else if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
2005-06-23 06:16:53 +02:00
|
|
|
relayConnect( comms );
|
2006-10-10 03:34:37 +02:00
|
|
|
#endif
|
2006-08-26 23:12:10 +02:00
|
|
|
#ifdef XWFEATURE_BLUETOOTH
|
|
|
|
} else if ( comms->addr.conType == COMMS_CONN_BT ) {
|
|
|
|
btConnect( comms );
|
|
|
|
#endif
|
2005-04-03 19:00:59 +02:00
|
|
|
}
|
2006-10-10 03:34:37 +02:00
|
|
|
} /* comms_start */
|
2005-04-03 19:00:59 +02:00
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
static void
|
2006-10-15 15:53:17 +02:00
|
|
|
addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP )
|
2005-03-19 23:01:38 +01:00
|
|
|
{
|
|
|
|
CommsAddrRec addr;
|
|
|
|
XP_MEMCPY( &addr, addrP, sizeof(addr) );
|
|
|
|
|
2006-10-05 03:17:03 +02:00
|
|
|
stream_putU8( stream, addr.conType );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
|
|
|
switch( addr.conType ) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
case COMMS_CONN_UNUSED:
|
|
|
|
case LAST_____FOO:
|
2005-09-02 08:26:33 +02:00
|
|
|
/* XP_ASSERT( 0 ); */
|
2005-03-19 23:01:38 +01:00
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
case COMMS_CONN_BT:
|
2006-09-08 09:14:24 +02:00
|
|
|
stringToStream( stream, addr.u.bt.hostName );
|
2006-09-23 18:04:53 +02:00
|
|
|
/* sizeof(.bits) below defeats ARM's padding. */
|
|
|
|
stream_putBytes( stream, &addr.u.bt.btAddr.bits,
|
|
|
|
sizeof(addr.u.bt.btAddr.bits) );
|
2006-09-08 09:14:24 +02:00
|
|
|
break;
|
2005-03-19 23:01:38 +01:00
|
|
|
case COMMS_CONN_IR:
|
|
|
|
/* nothing to save */
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_IP_NOUSE:
|
|
|
|
stringToStream( stream, addr.u.ip.hostName_ip );
|
|
|
|
stream_putU32( stream, addr.u.ip.ipAddr_ip );
|
|
|
|
stream_putU16( stream, addr.u.ip.port_ip );
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_RELAY:
|
|
|
|
stringToStream( stream, addr.u.ip_relay.cookie );
|
|
|
|
stringToStream( stream, addr.u.ip_relay.hostName );
|
|
|
|
stream_putU32( stream, addr.u.ip_relay.ipAddr );
|
|
|
|
stream_putU16( stream, addr.u.ip_relay.port );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} /* addrToStream */
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
void
|
2006-10-15 15:53:17 +02:00
|
|
|
comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2005-03-08 06:33:38 +01:00
|
|
|
XP_U16 nAddrRecs;
|
2003-11-01 06:35:29 +01:00
|
|
|
AddressRecord* rec;
|
|
|
|
MsgQueueElem* msg;
|
|
|
|
|
|
|
|
stream_putU8( stream, (XP_U8)comms->isServer );
|
2006-10-05 03:17:03 +02:00
|
|
|
addrToStream( stream, &comms->addr );
|
|
|
|
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
stream_putBits( stream, 4, comms->r.nPlayersHere );
|
|
|
|
stream_putBits( stream, 4, comms->r.nPlayersTotal );
|
|
|
|
}
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
stream_putU32( stream, comms->connID );
|
|
|
|
stream_putU16( stream, comms->nextChannelNo );
|
2006-10-05 03:17:03 +02:00
|
|
|
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
stream_putU8( stream, comms->r.myHostID );
|
|
|
|
stringToStream( stream, comms->r.connName );
|
|
|
|
}
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
stream_putU16( stream, comms->nUniqueBytes );
|
|
|
|
#endif
|
|
|
|
|
|
|
|
XP_ASSERT( comms->queueLen <= 255 );
|
|
|
|
stream_putU8( stream, (XP_U8)comms->queueLen );
|
|
|
|
|
|
|
|
nAddrRecs = countAddrRecs(comms);
|
|
|
|
stream_putU8( stream, (XP_U8)nAddrRecs );
|
|
|
|
|
|
|
|
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2004-10-02 05:47:24 +02:00
|
|
|
CommsAddrRec* addr = &rec->addr;
|
2005-03-19 23:01:38 +01:00
|
|
|
addrToStream( stream, addr );
|
2004-10-02 05:47:24 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
stream_putU16( stream, (XP_U16)rec->nextMsgID );
|
|
|
|
stream_putU16( stream, (XP_U16)rec->lastMsgReceived );
|
|
|
|
stream_putU16( stream, rec->channelNo );
|
2006-10-05 03:17:03 +02:00
|
|
|
if ( rec->addr.conType == COMMS_CONN_RELAY ) {
|
|
|
|
stream_putU8( stream, rec->r.hostID ); /* unneeded unless RELAY */
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
stream_putU16( stream, rec->lastACK );
|
|
|
|
stream_putU16( stream, rec->nUniqueBytes );
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
for ( msg = comms->msgQueueHead; !!msg; msg = msg->next ) {
|
|
|
|
stream_putU16( stream, msg->channelNo );
|
|
|
|
stream_putU32( stream, msg->msgID );
|
|
|
|
|
|
|
|
stream_putU16( stream, msg->len );
|
|
|
|
stream_putBytes( stream, msg->msg, msg->len );
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
stream_putU32( stream, cEND );
|
|
|
|
#endif
|
|
|
|
} /* comms_writeToStream */
|
|
|
|
|
2005-06-27 07:45:28 +02:00
|
|
|
void
|
2006-10-15 15:53:17 +02:00
|
|
|
comms_getAddr( const CommsCtxt* comms, CommsAddrRec* addr )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2005-04-03 04:49:04 +02:00
|
|
|
XP_ASSERT( !!comms );
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_MEMCPY( addr, &comms->addr, sizeof(*addr) );
|
|
|
|
} /* comms_getAddr */
|
|
|
|
|
|
|
|
void
|
2005-07-23 17:28:15 +02:00
|
|
|
comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
2005-09-04 22:30:47 +02:00
|
|
|
XP_ASSERT( comms != NULL );
|
2006-10-10 03:34:37 +02:00
|
|
|
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH
|
2006-09-08 09:14:24 +02:00
|
|
|
util_addrChange( comms->util, &comms->addr, addr );
|
2003-11-01 06:35:29 +01:00
|
|
|
#endif
|
2005-04-03 19:00:59 +02:00
|
|
|
XP_MEMCPY( &comms->addr, addr, sizeof(comms->addr) );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-03-19 23:01:38 +01:00
|
|
|
/* We should now have a cookie so we can connect??? */
|
2006-08-23 06:44:55 +02:00
|
|
|
if ( addr->conType == COMMS_CONN_RELAY ) {
|
|
|
|
relayConnect( comms );
|
|
|
|
}
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* comms_setAddr */
|
|
|
|
|
2005-06-27 07:45:28 +02:00
|
|
|
void
|
|
|
|
comms_getInitialAddr( CommsAddrRec* addr )
|
|
|
|
{
|
2006-10-15 16:09:17 +02:00
|
|
|
#if defined XWFEATURE_RELAY
|
2006-09-15 09:33:59 +02:00
|
|
|
addr->conType = COMMS_CONN_RELAY; /* for temporary ease in debugging */
|
2006-08-26 23:12:10 +02:00
|
|
|
addr->u.ip_relay.ipAddr = 0L; /* force 'em to set it */
|
|
|
|
addr->u.ip_relay.port = 10999;
|
|
|
|
{
|
|
|
|
char* name = "eehouse.org";
|
|
|
|
XP_MEMCPY( addr->u.ip_relay.hostName, name, XP_STRLEN(name)+1 );
|
|
|
|
}
|
|
|
|
addr->u.ip_relay.cookie[0] = '\0';
|
2006-10-15 16:09:17 +02:00
|
|
|
#elif defined PLATFORM_PALM
|
|
|
|
/* default values; default is still IR where there's a choice, at least on
|
|
|
|
Palm... */
|
|
|
|
addr->conType = COMMS_CONN_IR;
|
|
|
|
#else
|
|
|
|
addr->conType = COMMS_CONN_BT;
|
2006-08-26 23:12:10 +02:00
|
|
|
#endif
|
2005-06-27 07:45:28 +02:00
|
|
|
} /* comms_getInitialAddr */
|
|
|
|
|
|
|
|
CommsConnType
|
2006-10-15 15:53:17 +02:00
|
|
|
comms_getConType( const CommsCtxt* comms )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
return comms->addr.conType;
|
|
|
|
} /* comms_getConType */
|
|
|
|
|
2006-09-08 09:14:24 +02:00
|
|
|
XP_Bool
|
2006-10-15 15:53:17 +02:00
|
|
|
comms_getIsServer( const CommsCtxt* comms )
|
2006-09-08 09:14:24 +02:00
|
|
|
{
|
|
|
|
return comms->isServer;
|
|
|
|
}
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
/* Send a message using the sequentially next MsgID. Save the message so
|
|
|
|
* resend can work. */
|
|
|
|
XP_S16
|
2005-03-19 23:01:38 +01:00
|
|
|
comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
XP_U16 streamSize = stream_getSize( stream );
|
|
|
|
XP_U16 headerLen;
|
|
|
|
XP_PlayerAddr channelNo = stream_getAddress( stream );
|
|
|
|
AddressRecord* rec = getRecordFor( comms, channelNo );
|
|
|
|
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
|
|
|
|
MsgID lastMsgRcd = (!!rec)? rec->lastMsgReceived : 0;
|
|
|
|
MsgQueueElem* newMsgElem;
|
|
|
|
XWStreamCtxt* msgStream;
|
|
|
|
|
2006-09-27 03:54:53 +02:00
|
|
|
XP_DEBUGF( "assigning msgID=" XP_LD " on chnl %d", msgID, channelNo );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
if ( !!rec ) {
|
|
|
|
rec->nUniqueBytes += streamSize;
|
|
|
|
} else {
|
|
|
|
comms->nUniqueBytes += streamSize;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
newMsgElem = (MsgQueueElem*)XP_MALLOC( comms->mpool,
|
|
|
|
sizeof( *newMsgElem ) );
|
|
|
|
newMsgElem->channelNo = channelNo;
|
|
|
|
newMsgElem->msgID = msgID;
|
|
|
|
|
|
|
|
msgStream = mem_stream_make( MPPARM(comms->mpool)
|
|
|
|
util_getVTManager(comms->util),
|
|
|
|
NULL, 0,
|
|
|
|
(MemStreamCloseCallback)NULL );
|
|
|
|
stream_open( msgStream );
|
2005-03-06 18:56:34 +01:00
|
|
|
stream_putU32( msgStream, comms->connID );
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
stream_putU16( msgStream, channelNo );
|
|
|
|
stream_putU32( msgStream, msgID );
|
|
|
|
stream_putU32( msgStream, lastMsgRcd );
|
|
|
|
|
|
|
|
headerLen = stream_getSize( msgStream );
|
|
|
|
newMsgElem->len = streamSize + headerLen;
|
|
|
|
newMsgElem->msg = (XP_U8*)XP_MALLOC( comms->mpool, newMsgElem->len );
|
|
|
|
|
|
|
|
stream_getBytes( msgStream, newMsgElem->msg, headerLen );
|
|
|
|
stream_destroy( msgStream );
|
|
|
|
|
|
|
|
stream_getBytes( stream, newMsgElem->msg + headerLen, streamSize );
|
|
|
|
|
|
|
|
addToQueue( comms, newMsgElem );
|
|
|
|
|
|
|
|
return sendMsg( comms, newMsgElem );
|
|
|
|
} /* comms_send */
|
|
|
|
|
|
|
|
/* Add new message to the end of the list. The list needs to be kept in order
|
|
|
|
* by ascending msgIDs within each channel since if there's a resend that's
|
|
|
|
* the order in which they need to be sent.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
addToQueue( CommsCtxt* comms, MsgQueueElem* newMsgElem )
|
|
|
|
{
|
|
|
|
newMsgElem->next = (MsgQueueElem*)NULL;
|
|
|
|
if ( !comms->msgQueueHead ) {
|
|
|
|
comms->msgQueueHead = comms->msgQueueTail = newMsgElem;
|
|
|
|
XP_ASSERT( comms->queueLen == 0 );
|
|
|
|
comms->queueLen = 1;
|
|
|
|
} else {
|
|
|
|
XP_ASSERT( !!comms->msgQueueTail );
|
|
|
|
comms->msgQueueTail->next = newMsgElem;
|
|
|
|
comms->msgQueueTail = newMsgElem;
|
|
|
|
|
|
|
|
XP_ASSERT( comms->queueLen > 0 );
|
|
|
|
++comms->queueLen;
|
|
|
|
}
|
|
|
|
XP_STATUSF( "addToQueue: queueLen now %d", comms->queueLen );
|
|
|
|
} /* addToQueue */
|
|
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
static void
|
|
|
|
printQueue( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
MsgQueueElem* elem;
|
|
|
|
short i;
|
|
|
|
|
|
|
|
for ( elem = comms->msgQueueHead, i = 0; i < comms->queueLen;
|
|
|
|
elem = elem->next, ++i ) {
|
2006-09-27 03:54:53 +02:00
|
|
|
XP_STATUSF( "\t%d: channel: %d; msgID=" XP_LD,
|
2003-11-01 06:35:29 +01:00
|
|
|
i+1, elem->channelNo, elem->msgID );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
2006-09-17 07:06:46 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
/* We've received on some channel a message with a certain ID. This means
|
|
|
|
* that all messages sent on that channel with lower IDs have been received
|
2007-02-06 06:49:45 +01:00
|
|
|
* and can be removed from our queue. BUT: if this ID is higher than any
|
|
|
|
* we've sent, don't remove. We may be starting a new game but have a server
|
|
|
|
* that's still on the old one.
|
2003-11-01 06:35:29 +01:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
removeFromQueue( CommsCtxt* comms, XP_PlayerAddr channelNo, MsgID msgID )
|
|
|
|
{
|
2007-02-06 06:49:45 +01:00
|
|
|
XP_STATUSF( "%s: remove msgs <= " XP_LD " for channel %d (queueLen: %d)",
|
|
|
|
__func__, msgID, channelNo, comms->queueLen );
|
|
|
|
|
|
|
|
if ( (channelNo == 0) || !!getRecordFor(comms, channelNo) ) {
|
2007-02-07 12:58:01 +01:00
|
|
|
MsgQueueElem dummy;
|
|
|
|
MsgQueueElem* keep = &dummy;
|
2007-02-06 06:49:45 +01:00
|
|
|
MsgQueueElem* elem;
|
|
|
|
MsgQueueElem* next;
|
|
|
|
|
|
|
|
for ( elem = comms->msgQueueHead; !!elem; elem = next ) {
|
2007-02-07 12:58:01 +01:00
|
|
|
XP_Bool knownGood = XP_FALSE;
|
2007-02-06 06:49:45 +01:00
|
|
|
next = elem->next;
|
|
|
|
|
|
|
|
/* remove the 0-channel message if we've established a channel
|
|
|
|
number. Only clients should have any 0-channel messages in the
|
|
|
|
queue, and receiving something from the server is an implicit
|
|
|
|
ACK -- IFF it isn't left over from the last game. */
|
|
|
|
|
|
|
|
if ( (elem->channelNo == 0) && (channelNo != 0) ) {
|
2007-02-07 12:58:01 +01:00
|
|
|
XP_ASSERT( !comms->isServer );
|
|
|
|
XP_ASSERT( elem->msgID == 0 );
|
2007-02-06 06:49:45 +01:00
|
|
|
} else if ( elem->channelNo != channelNo ) {
|
2007-02-07 12:58:01 +01:00
|
|
|
knownGood = XP_TRUE;
|
2007-02-06 06:49:45 +01:00
|
|
|
}
|
2006-09-15 09:33:59 +02:00
|
|
|
|
2007-02-07 12:58:01 +01:00
|
|
|
if ( !knownGood && (elem->msgID <= msgID) ) {
|
2007-02-06 06:49:45 +01:00
|
|
|
XP_FREE( comms->mpool, elem->msg );
|
|
|
|
XP_FREE( comms->mpool, elem );
|
|
|
|
--comms->queueLen;
|
2006-09-27 03:54:53 +02:00
|
|
|
} else {
|
2007-02-07 12:58:01 +01:00
|
|
|
keep->next = elem;
|
2007-02-06 06:49:45 +01:00
|
|
|
keep = elem;
|
2006-09-15 09:33:59 +02:00
|
|
|
}
|
|
|
|
}
|
2007-02-07 12:58:01 +01:00
|
|
|
|
|
|
|
keep->next = NULL;
|
|
|
|
comms->msgQueueHead = dummy.next;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2006-09-27 03:54:53 +02:00
|
|
|
|
2007-02-06 06:49:45 +01:00
|
|
|
XP_STATUSF( "%s: queueLen now %d", __func__, comms->queueLen );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_ASSERT( comms->queueLen > 0 || comms->msgQueueHead == NULL );
|
|
|
|
|
2006-09-17 07:06:46 +02:00
|
|
|
#ifdef DEBUG
|
2003-11-01 06:35:29 +01:00
|
|
|
printQueue( comms );
|
2006-09-17 07:06:46 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* removeFromQueue */
|
|
|
|
|
|
|
|
static XP_S16
|
|
|
|
sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
|
|
|
|
{
|
2005-03-19 23:01:38 +01:00
|
|
|
XP_S16 result = 0;
|
2003-11-01 06:35:29 +01:00
|
|
|
XP_PlayerAddr channelNo;
|
|
|
|
CommsAddrRec* addr;
|
|
|
|
|
|
|
|
channelNo = elem->channelNo;
|
|
|
|
|
2005-07-23 17:28:15 +02:00
|
|
|
if ( 0 ) {
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-07-23 17:28:15 +02:00
|
|
|
} else if ( comms_getConType( comms ) == COMMS_CONN_RELAY ) {
|
2006-10-02 16:26:56 +02:00
|
|
|
if ( comms->r.relayState == COMMS_RELAYSTATE_ALLCONNECTED ) {
|
2005-03-19 23:01:38 +01:00
|
|
|
XWHostID destID = getDestID( comms, channelNo );
|
2005-06-23 06:16:53 +02:00
|
|
|
result = send_via_relay( comms, XWRELAY_MSG_TORELAY, destID,
|
|
|
|
elem->msg, elem->len );
|
2005-03-19 23:01:38 +01:00
|
|
|
} else {
|
2007-02-06 06:49:45 +01:00
|
|
|
XP_LOGF( "%s: skipping message: not connected", __func__ );
|
2005-03-19 23:01:38 +01:00
|
|
|
}
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2005-03-19 23:01:38 +01:00
|
|
|
} else {
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
if ( !channelToAddress( comms, channelNo, &addr ) ) {
|
|
|
|
addr = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
XP_ASSERT( !!comms->sendproc );
|
|
|
|
result = (*comms->sendproc)( elem->msg, elem->len, addr,
|
|
|
|
comms->sendClosure );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
return result;
|
|
|
|
} /* sendMsg */
|
|
|
|
|
|
|
|
XP_S16
|
|
|
|
comms_resendAll( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
MsgQueueElem* msg;
|
|
|
|
XP_S16 result = 0;
|
2006-09-23 17:22:26 +02:00
|
|
|
|
2006-11-11 23:37:36 +01:00
|
|
|
XP_ASSERT( !!comms );
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
for ( msg = comms->msgQueueHead; !!msg; msg = msg->next ) {
|
|
|
|
XP_S16 oneResult = sendMsg( comms, msg );
|
|
|
|
if ( result == 0 && oneResult != 0 ) {
|
|
|
|
result = oneResult;
|
|
|
|
}
|
2006-09-27 03:54:53 +02:00
|
|
|
XP_STATUSF( "resend: msgID=" XP_LD "; rslt=%d",
|
2006-09-08 09:14:24 +02:00
|
|
|
msg->msgID, oneResult );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
} /* comms_resend */
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-03-19 23:01:38 +01:00
|
|
|
static XP_Bool
|
|
|
|
relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
|
|
|
|
{
|
|
|
|
XP_Bool consumed;
|
|
|
|
XWHostID destID, srcID;
|
2005-10-01 18:01:39 +02:00
|
|
|
CookieID cookieID;
|
2005-09-03 17:37:49 +02:00
|
|
|
XP_U8 relayErr;
|
2005-10-02 17:39:38 +02:00
|
|
|
XP_U8 hasName;
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2005-10-30 17:14:13 +01:00
|
|
|
/* nothing for us to do here if not using relay */
|
|
|
|
consumed = comms->addr.conType == COMMS_CONN_RELAY;
|
|
|
|
if ( consumed ) {
|
2005-03-19 23:01:38 +01:00
|
|
|
XWRELAY_Cmd cmd = stream_getU8( stream );
|
|
|
|
switch( cmd ) {
|
2005-10-01 18:01:39 +02:00
|
|
|
|
|
|
|
case XWRELAY_CONNECT_RESP:
|
|
|
|
case XWRELAY_RECONNECT_RESP:
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_CONNECTED;
|
|
|
|
comms->r.heartbeat = stream_getU16( stream );
|
|
|
|
comms->r.cookieID = stream_getU16( stream );
|
|
|
|
comms->r.myHostID = (XWHostID)stream_getU8( stream );
|
2005-10-01 18:01:39 +02:00
|
|
|
XP_LOGF( "got XWRELAY_CONNECTRESP; set cookieID = %d; "
|
|
|
|
"set hostid: %x",
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.cookieID, comms->r.myHostID );
|
2005-10-02 17:39:38 +02:00
|
|
|
setHeartbeatTimer( comms );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XWRELAY_ALLHERE:
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_ALLCONNECTED;
|
2005-10-02 17:39:38 +02:00
|
|
|
hasName = stream_getU8( stream );
|
|
|
|
if ( hasName ) {
|
2006-10-02 16:26:56 +02:00
|
|
|
stringFromStreamHere( stream, comms->r.connName,
|
|
|
|
sizeof(comms->r.connName) );
|
|
|
|
XP_LOGF( "read connName: %s", comms->r.connName );
|
2005-10-02 17:39:38 +02:00
|
|
|
} else {
|
2006-10-02 16:26:56 +02:00
|
|
|
XP_ASSERT( comms->r.connName[0] != '\0' );
|
2005-10-01 18:01:39 +02:00
|
|
|
}
|
2005-09-03 20:31:32 +02:00
|
|
|
|
|
|
|
/* 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. */
|
2005-03-19 23:01:38 +01:00
|
|
|
comms_resendAll( comms );
|
|
|
|
break;
|
|
|
|
case XWRELAY_MSG_FROMRELAY:
|
2005-10-01 18:01:39 +02:00
|
|
|
cookieID = stream_getU16( stream );
|
|
|
|
srcID = stream_getU8( stream );
|
|
|
|
destID = stream_getU8( stream );
|
|
|
|
XP_LOGF( "cookieID: %d; srcID: %x; destID: %x",
|
2005-03-19 23:01:38 +01:00
|
|
|
cookieID, srcID, destID );
|
|
|
|
/* If these values don't check out, drop it */
|
2006-10-02 16:26:56 +02:00
|
|
|
consumed = cookieID != comms->r.cookieID
|
|
|
|
|| destID != comms->r.myHostID;
|
2005-03-19 23:01:38 +01:00
|
|
|
if ( consumed ) {
|
|
|
|
XP_LOGF( "rejecting data message" );
|
|
|
|
} else {
|
|
|
|
*senderID = srcID;
|
|
|
|
}
|
|
|
|
break;
|
2005-09-03 08:57:01 +02:00
|
|
|
|
2005-09-03 17:37:49 +02:00
|
|
|
case XWRELAY_DISCONNECT_OTHER:
|
|
|
|
relayErr = stream_getU8( stream );
|
2005-10-01 18:01:39 +02:00
|
|
|
srcID = stream_getU8( stream );
|
|
|
|
XP_LOGF( "host id %x disconnected", srcID );
|
2005-09-03 17:37:49 +02:00
|
|
|
/* we will eventually want to tell the user which player's gone */
|
|
|
|
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case XWRELAY_DISCONNECT_YOU: /* Close socket for this? */
|
|
|
|
case XWRELAY_CONNECTDENIED: /* Close socket for this? */
|
2005-09-05 17:33:51 +02:00
|
|
|
XP_LOGF( "XWRELAY_DISCONNECT_YOU|XWRELAY_CONNECTDENIED" );
|
2005-09-03 17:37:49 +02:00
|
|
|
relayErr = stream_getU8( stream );
|
|
|
|
util_userError( comms->util, ERR_RELAY_BASE + relayErr );
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
2005-07-06 03:36:52 +02:00
|
|
|
/* fallthru */
|
2005-03-19 23:01:38 +01:00
|
|
|
default:
|
|
|
|
XP_LOGF( "dropping relay msg with cmd %d", (XP_U16)cmd );
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return consumed;
|
|
|
|
} /* checkForRelay */
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2006-11-11 23:37:36 +01:00
|
|
|
static XP_Bool
|
|
|
|
addressUnknown( CommsCtxt* comms, const CommsAddrRec* addr )
|
|
|
|
{
|
|
|
|
XP_Bool unknown = XP_TRUE;
|
2007-01-09 03:43:09 +01:00
|
|
|
if ( !!addr ) {
|
|
|
|
CommsConnType conType = addr->conType;
|
|
|
|
const AddressRecord* rec;
|
|
|
|
for ( rec = comms->recs; !!rec && unknown ; rec = rec->next ) {
|
|
|
|
XP_ASSERT( conType == rec->addr.conType );
|
|
|
|
switch( conType ) {
|
|
|
|
case COMMS_CONN_RELAY:
|
|
|
|
if ( (addr->u.ip_relay.ipAddr == rec->addr.u.ip_relay.ipAddr)
|
|
|
|
&& (addr->u.ip_relay.port == rec->addr.u.ip_relay.port ) ) {
|
|
|
|
unknown = XP_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_BT:
|
|
|
|
if ( 0 == XP_MEMCMP( &addr->u.bt.btAddr, &rec->addr.u.bt.btAddr,
|
|
|
|
sizeof(addr->u.bt.btAddr) ) ) {
|
|
|
|
unknown = XP_FALSE;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case COMMS_CONN_IR: /* no way to test */
|
|
|
|
default:
|
|
|
|
break;
|
2006-11-11 23:37:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return unknown;
|
|
|
|
} /* addressUnknown */
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
/* read a raw buffer into a stream, stripping off the headers and keeping
|
|
|
|
* any necessary stats.
|
|
|
|
*
|
|
|
|
* Keep track of return addresses by channel. If the message's channel number
|
|
|
|
* is 0, assign a new channel number and associate an address with it.
|
|
|
|
* Otherwise update the address, which may have changed since we last heard
|
|
|
|
* from this channel.
|
|
|
|
*
|
|
|
|
* There may be messages that are only about the comms 'protocol', that
|
|
|
|
* contain nothing to be passed to the server. In that case, return false
|
|
|
|
* indicating the caller that all processing is finished.
|
|
|
|
*
|
|
|
|
* conType tells both how to interpret the addr and whether to expect any
|
|
|
|
* special fields in the message itself. In the IP case, for example, the
|
|
|
|
* port component of a return address is in the message but the IP address
|
|
|
|
* component will be passed in.
|
|
|
|
*/
|
|
|
|
XP_Bool
|
2005-03-09 16:18:17 +01:00
|
|
|
comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
2006-09-14 03:25:40 +02:00
|
|
|
const CommsAddrRec* addr )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
XP_U16 channelNo;
|
|
|
|
XP_U32 connID;
|
|
|
|
MsgID msgID;
|
|
|
|
MsgID lastMsgRcd;
|
2006-08-29 15:18:12 +02:00
|
|
|
XP_Bool validMessage = XP_FALSE;
|
2003-11-01 06:35:29 +01:00
|
|
|
AddressRecord* recs = (AddressRecord*)NULL;
|
2006-09-14 03:25:40 +02:00
|
|
|
XWHostID senderID = 0; /* unset; default for non-relay cases */
|
2005-10-01 18:01:39 +02:00
|
|
|
XP_Bool usingRelay = XP_FALSE;
|
|
|
|
XP_Bool channelWas0 = XP_FALSE;
|
2006-10-10 03:34:37 +02:00
|
|
|
XP_Bool done = XP_FALSE;
|
2005-03-06 18:56:34 +01:00
|
|
|
|
2005-03-20 16:01:59 +01:00
|
|
|
XP_ASSERT( addr == NULL || comms->addr.conType == addr->conType );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2006-08-26 23:12:10 +02:00
|
|
|
/* relayPreProcess returns true if consumes the message. May just eat the
|
|
|
|
header and leave a regular message to be processed below. */
|
2006-10-10 03:34:37 +02:00
|
|
|
done = relayPreProcess( comms, stream, &senderID );
|
|
|
|
if ( !done ) {
|
2006-10-07 05:37:40 +02:00
|
|
|
usingRelay = comms->addr.conType == COMMS_CONN_RELAY;
|
2006-10-10 03:34:37 +02:00
|
|
|
}
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
if ( !done ) {
|
2006-10-07 05:37:40 +02:00
|
|
|
if ( stream_getSize( stream ) >= sizeof(connID) ) {
|
|
|
|
connID = stream_getU32( stream );
|
2007-02-06 06:49:45 +01:00
|
|
|
XP_STATUSF( "%s: read connID of %lx", __func__, connID );
|
2006-10-07 05:37:40 +02:00
|
|
|
|
|
|
|
if ( comms->connID == connID || comms->connID == CONN_ID_NONE ) {
|
|
|
|
if ( stream_getSize( stream ) >= sizeof(channelNo)
|
|
|
|
+ sizeof(msgID) + sizeof(lastMsgRcd) ) {
|
|
|
|
|
|
|
|
channelNo = stream_getU16( stream );
|
|
|
|
XP_STATUSF( "read channelNo %d", channelNo );
|
|
|
|
|
|
|
|
msgID = stream_getU32( stream );
|
|
|
|
lastMsgRcd = stream_getU32( stream );
|
|
|
|
|
|
|
|
XP_DEBUGF( "rcd: msgID=" XP_LD " on chnl %d", msgID,
|
|
|
|
channelNo );
|
|
|
|
|
|
|
|
removeFromQueue( comms, channelNo, lastMsgRcd );
|
|
|
|
|
|
|
|
/* Problem: need to detect duplicate messages even before
|
|
|
|
the server's had a chance to assign channels.
|
|
|
|
Solution, which is a hack: since hostID does the same
|
|
|
|
thing, use it in the relay case. But in the relay-less
|
|
|
|
case, which still needs to work, do assign channels.
|
|
|
|
The dup message problem is far less common there. */
|
|
|
|
|
2006-11-11 23:37:36 +01:00
|
|
|
if ( channelNo != 0 ) {
|
|
|
|
validMessage = XP_TRUE;
|
|
|
|
} else {
|
|
|
|
/* If we've seen a channel0 msg from same addr, drop
|
|
|
|
it. It's most likely a dupe, and server can't
|
|
|
|
handle e.g. duplicate client reg messages.. */
|
|
|
|
validMessage = addressUnknown( comms, addr );
|
|
|
|
|
|
|
|
if ( validMessage ) {
|
|
|
|
XP_ASSERT( comms->isServer );
|
|
|
|
if ( usingRelay ) {
|
|
|
|
XP_ASSERT( senderID != 0 );
|
|
|
|
channelNo = senderID;
|
|
|
|
} else {
|
|
|
|
XP_ASSERT( msgID == 0 );
|
|
|
|
/* check that address isn't already associated
|
|
|
|
with an existing channel. */
|
|
|
|
channelNo = ++comms->nextChannelNo;
|
|
|
|
XP_LOGF( "%s: incrementled nextChannelNo "
|
|
|
|
"to %d", __FUNCTION__,
|
|
|
|
comms->nextChannelNo );
|
|
|
|
channelWas0 = XP_TRUE;
|
|
|
|
}
|
|
|
|
XP_STATUSF( "assigning channelNo=%d", channelNo );
|
2006-10-07 05:37:40 +02:00
|
|
|
}
|
2006-11-11 23:37:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( validMessage && (usingRelay || !channelWas0) ) {
|
2006-10-07 05:37:40 +02:00
|
|
|
recs = getRecordFor( comms, channelNo );
|
|
|
|
/* messageID for an incoming message should be one
|
|
|
|
* greater than the id most recently used for that
|
|
|
|
* channel. */
|
|
|
|
if ( !!recs ) {
|
|
|
|
if ( msgID != recs->lastMsgReceived + 1 ) {
|
|
|
|
XP_DEBUGF( "on channel %d, msgID=" XP_LD
|
|
|
|
" (next should be " XP_LD ")",
|
|
|
|
channelNo, msgID,
|
|
|
|
recs->lastMsgReceived+1 );
|
|
|
|
validMessage = XP_FALSE;
|
|
|
|
}
|
|
|
|
} else if ( msgID > 1 ) {
|
2006-09-15 09:33:59 +02:00
|
|
|
validMessage = XP_FALSE;
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
2006-10-07 05:37:40 +02:00
|
|
|
if ( !!recs ) {
|
|
|
|
XP_ASSERT( lastMsgRcd <= recs->nextMsgID );
|
|
|
|
XP_ASSERT( lastMsgRcd < 0x0000FFFF );
|
|
|
|
recs->lastACK = (XP_U16)lastMsgRcd;
|
|
|
|
}
|
2006-09-17 07:06:46 +02:00
|
|
|
#endif
|
2006-10-07 05:37:40 +02:00
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2006-10-07 05:37:40 +02:00
|
|
|
if ( validMessage ) {
|
|
|
|
XP_LOGF( "remembering senderID %x for channel %d",
|
|
|
|
senderID, channelNo );
|
2006-08-29 15:18:12 +02:00
|
|
|
|
2006-10-07 05:37:40 +02:00
|
|
|
recs = rememberChannelAddress( comms, channelNo,
|
|
|
|
senderID, addr );
|
|
|
|
stream_setAddress( stream, channelNo );
|
2006-08-29 15:18:12 +02:00
|
|
|
|
2006-10-07 05:37:40 +02:00
|
|
|
if ( !!recs ) {
|
|
|
|
recs->lastMsgReceived = msgID;
|
|
|
|
}
|
|
|
|
XP_STATUSF( "set channel %d's lastMsgReceived to "
|
|
|
|
XP_LD, channelNo, msgID );
|
2006-08-29 15:18:12 +02:00
|
|
|
}
|
2006-10-07 05:37:40 +02:00
|
|
|
} else {
|
|
|
|
XP_LOGF( "%s: message too small", __FUNCTION__ );
|
2006-08-29 15:18:12 +02:00
|
|
|
}
|
|
|
|
} else {
|
2006-10-07 05:37:40 +02:00
|
|
|
XP_STATUSF( "refusing non-matching connID; got %lx, "
|
|
|
|
"wanted %lx", connID, comms->connID );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2006-08-29 15:18:12 +02:00
|
|
|
} else {
|
2006-10-07 05:37:40 +02:00
|
|
|
XP_LOGF( "%s: message too small", __FUNCTION__ );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
}
|
2006-09-15 09:33:59 +02:00
|
|
|
LOG_RETURNF( "%d", (XP_U16)validMessage );
|
2003-11-01 06:35:29 +01:00
|
|
|
return validMessage;
|
2005-03-09 16:18:17 +01:00
|
|
|
} /* comms_checkIncomingStream */
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-06-23 06:16:53 +02:00
|
|
|
static void
|
2006-08-16 15:44:44 +02:00
|
|
|
p_comms_timerFired( void* closure, XWTimerReason XP_UNUSED_DBG(why) )
|
2005-06-23 06:16:53 +02:00
|
|
|
{
|
|
|
|
CommsCtxt* comms = (CommsCtxt*)closure;
|
|
|
|
XP_ASSERT( why == TIMER_HEARTBEAT );
|
|
|
|
XP_LOGF( "comms_timerFired" );
|
2006-10-02 16:26:56 +02:00
|
|
|
if ( comms->r.heartbeat != HEARTBEAT_NONE ) {
|
2005-06-23 06:16:53 +02:00
|
|
|
send_via_relay( comms, XWRELAY_HEARTBEAT, HOST_ID_NONE, NULL, 0 );
|
2005-07-05 22:57:37 +02:00
|
|
|
/* No need to reset timer. send_via_relay does that. */
|
2005-06-23 06:16:53 +02:00
|
|
|
}
|
|
|
|
} /* comms_timerFired */
|
|
|
|
|
|
|
|
static void
|
|
|
|
setHeartbeatTimer( CommsCtxt* comms )
|
|
|
|
{
|
2006-10-02 16:26:56 +02:00
|
|
|
util_setTimer( comms->util, TIMER_HEARTBEAT, comms->r.heartbeat,
|
2005-06-23 06:16:53 +02:00
|
|
|
p_comms_timerFired, comms );
|
|
|
|
}
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2005-06-23 06:16:53 +02:00
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
|
|
|
void
|
|
|
|
comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|
|
|
{
|
|
|
|
XP_UCHAR buf[100];
|
|
|
|
AddressRecord* rec;
|
2006-09-27 03:54:53 +02:00
|
|
|
MsgQueueElem* elem;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2006-09-27 03:54:53 +02:00
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
|
|
|
(XP_UCHAR*)"msg queue len: %d\n", comms->queueLen );
|
|
|
|
stream_putString( stream, buf );
|
|
|
|
|
|
|
|
for ( elem = comms->msgQueueHead; !!elem; elem = elem->next ) {
|
|
|
|
XP_SNPRINTF( buf, sizeof(buf),
|
|
|
|
" - channelNo=%d; msgID=" XP_LD "; len=%d\n",
|
|
|
|
elem->channelNo, elem->msgID, elem->len );
|
|
|
|
stream_putString( stream, buf );
|
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
|
|
|
(XP_UCHAR*)"channel-less bytes sent: %d\n",
|
|
|
|
comms->nUniqueBytes );
|
2006-09-27 03:54:53 +02:00
|
|
|
stream_putString( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
|
|
|
(XP_UCHAR*)" Stats for channel: %d\n",
|
|
|
|
rec->channelNo );
|
2006-09-27 03:54:53 +02:00
|
|
|
stream_putString( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
2005-03-20 20:41:30 +01:00
|
|
|
(XP_UCHAR*)"Last msg sent: " XP_LD "\n",
|
2003-11-01 06:35:29 +01:00
|
|
|
rec->nextMsgID );
|
2006-09-27 03:54:53 +02:00
|
|
|
stream_putString( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
|
|
|
(XP_UCHAR*)"Unique bytes sent: %d\n",
|
|
|
|
rec->nUniqueBytes );
|
2006-09-27 03:54:53 +02:00
|
|
|
stream_putString( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
|
|
|
|
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
|
|
|
(XP_UCHAR*)"Last message acknowledged: %d\n",
|
|
|
|
rec->lastACK);
|
2006-09-27 03:54:53 +02:00
|
|
|
stream_putString( stream, buf );
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
} /* comms_getStats */
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static AddressRecord*
|
|
|
|
rememberChannelAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
2006-09-14 03:25:40 +02:00
|
|
|
XWHostID hostID, const CommsAddrRec* addr )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
AddressRecord* recs = NULL;
|
2005-03-06 18:56:34 +01:00
|
|
|
recs = getRecordFor( comms, channelNo );
|
|
|
|
if ( !recs ) {
|
|
|
|
/* not found; add a new entry */
|
|
|
|
recs = (AddressRecord*)XP_MALLOC( comms->mpool, sizeof(*recs) );
|
|
|
|
|
|
|
|
recs->nextMsgID = 0;
|
|
|
|
recs->channelNo = channelNo;
|
2006-10-02 16:26:56 +02:00
|
|
|
recs->r.hostID = hostID;
|
2003-11-01 06:35:29 +01:00
|
|
|
#ifdef DEBUG
|
2005-03-06 18:56:34 +01:00
|
|
|
recs->nUniqueBytes = 0;
|
2003-11-01 06:35:29 +01:00
|
|
|
#endif
|
2005-03-06 18:56:34 +01:00
|
|
|
recs->next = comms->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) );
|
2006-10-02 16:26:56 +02:00
|
|
|
XP_ASSERT( recs->r.hostID == hostID );
|
2005-03-06 18:56:34 +01:00
|
|
|
} else {
|
|
|
|
XP_MEMSET( &recs->addr, 0, sizeof(recs->addr) );
|
2006-08-26 23:12:10 +02:00
|
|
|
recs->addr.conType = comms->addr.conType;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return recs;
|
|
|
|
} /* rememberChannelAddress */
|
|
|
|
|
|
|
|
static XP_Bool
|
|
|
|
channelToAddress( CommsCtxt* comms, XP_PlayerAddr channelNo,
|
|
|
|
CommsAddrRec** addr )
|
|
|
|
{
|
|
|
|
AddressRecord* recs = getRecordFor( comms, channelNo );
|
|
|
|
|
|
|
|
if ( !!recs ) {
|
|
|
|
*addr = &recs->addr;
|
|
|
|
return XP_TRUE;
|
|
|
|
} else {
|
|
|
|
return XP_FALSE;
|
|
|
|
}
|
|
|
|
} /* channelToAddress */
|
|
|
|
|
|
|
|
static AddressRecord*
|
|
|
|
getRecordFor( CommsCtxt* comms, XP_PlayerAddr channelNo )
|
|
|
|
{
|
2007-02-06 06:49:45 +01:00
|
|
|
AddressRecord* recs = NULL;
|
2003-11-01 06:35:29 +01:00
|
|
|
|
2007-02-06 06:49:45 +01:00
|
|
|
if ( channelNo != CHANNEL_NONE ) {
|
|
|
|
for ( recs = comms->recs; !!recs; recs = recs->next ) {
|
|
|
|
if ( recs->channelNo == channelNo ) {
|
|
|
|
break;
|
|
|
|
}
|
2005-03-06 18:56:34 +01:00
|
|
|
}
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
2007-02-06 06:49:45 +01:00
|
|
|
return recs;
|
2003-11-01 06:35:29 +01:00
|
|
|
} /* getRecordFor */
|
|
|
|
|
|
|
|
static XP_U16
|
2006-10-15 15:53:17 +02:00
|
|
|
countAddrRecs( const CommsCtxt* comms )
|
2003-11-01 06:35:29 +01:00
|
|
|
{
|
|
|
|
short count = 0;
|
|
|
|
AddressRecord* recs;
|
|
|
|
for ( recs = comms->recs; !!recs; recs = recs->next ) {
|
2005-03-19 23:01:38 +01:00
|
|
|
++count;
|
2003-11-01 06:35:29 +01:00
|
|
|
}
|
|
|
|
return count;
|
|
|
|
} /* countAddrRecs */
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2006-06-16 03:46:47 +02:00
|
|
|
static XWHostID
|
|
|
|
getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo )
|
|
|
|
{
|
|
|
|
XWHostID id = HOST_ID_NONE;
|
|
|
|
if ( channelNo == CHANNEL_NONE ) {
|
|
|
|
id = HOST_ID_SERVER;
|
|
|
|
} else {
|
|
|
|
AddressRecord* recs;
|
|
|
|
for ( recs = comms->recs; !!recs; recs = recs->next ) {
|
|
|
|
if ( recs->channelNo == channelNo ) {
|
2006-10-02 16:26:56 +02:00
|
|
|
id = recs->r.hostID;
|
2006-06-16 03:46:47 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
XP_LOGF( "getDestID(%d) => %x", channelNo, id );
|
|
|
|
return id;
|
|
|
|
} /* getDestID */
|
|
|
|
|
2005-03-19 23:01:38 +01:00
|
|
|
static XP_Bool
|
2005-06-23 06:16:53 +02:00
|
|
|
send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
|
|
|
void* data, int dlen )
|
2005-03-19 23:01:38 +01:00
|
|
|
{
|
2005-06-23 06:16:53 +02:00
|
|
|
XP_Bool success = XP_FALSE;
|
2005-04-03 04:49:04 +02:00
|
|
|
XP_U16 len = 0;
|
2005-03-19 23:01:38 +01:00
|
|
|
CommsAddrRec addr;
|
|
|
|
XWStreamCtxt* tmpStream;
|
|
|
|
XP_U8* buf;
|
|
|
|
|
|
|
|
comms_getAddr( comms, &addr );
|
|
|
|
tmpStream = mem_stream_make( MPPARM(comms->mpool)
|
|
|
|
util_getVTManager(comms->util),
|
|
|
|
NULL, 0,
|
|
|
|
(MemStreamCloseCallback)NULL );
|
|
|
|
if ( tmpStream != NULL ) {
|
|
|
|
stream_open( tmpStream );
|
|
|
|
stream_putU8( tmpStream, cmd );
|
|
|
|
|
2005-07-06 02:58:20 +02:00
|
|
|
switch ( cmd ) {
|
|
|
|
case XWRELAY_MSG_TORELAY:
|
2006-10-02 16:26:56 +02:00
|
|
|
stream_putU16( tmpStream, comms->r.cookieID );
|
|
|
|
stream_putU8( tmpStream, comms->r.myHostID );
|
2005-10-01 18:01:39 +02:00
|
|
|
stream_putU8( tmpStream, destID );
|
2005-03-19 23:01:38 +01:00
|
|
|
if ( data != NULL && dlen > 0 ) {
|
|
|
|
stream_putBytes( tmpStream, data, dlen );
|
|
|
|
}
|
2005-07-06 02:58:20 +02:00
|
|
|
break;
|
2005-09-05 17:33:51 +02:00
|
|
|
case XWRELAY_GAME_CONNECT:
|
2005-07-06 03:36:52 +02:00
|
|
|
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
2005-07-06 02:58:20 +02:00
|
|
|
stringToStream( tmpStream, addr.u.ip_relay.cookie );
|
2006-10-02 16:26:56 +02:00
|
|
|
stream_putU8( tmpStream, comms->r.myHostID );
|
|
|
|
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
|
|
|
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_CONNECT_PENDING;
|
2005-07-06 02:58:20 +02:00
|
|
|
break;
|
|
|
|
|
2005-09-05 17:33:51 +02:00
|
|
|
case XWRELAY_GAME_RECONNECT:
|
2005-09-02 08:26:33 +02:00
|
|
|
stream_putU8( tmpStream, XWRELAY_PROTO_VERSION );
|
2006-10-02 16:26:56 +02:00
|
|
|
stream_putU8( tmpStream, comms->r.myHostID );
|
|
|
|
stream_putU8( tmpStream, comms->r.nPlayersHere );
|
|
|
|
stream_putU8( tmpStream, comms->r.nPlayersTotal );
|
|
|
|
stringToStream( tmpStream, comms->r.connName );
|
2005-09-02 08:26:33 +02:00
|
|
|
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_CONNECT_PENDING;
|
2005-09-02 08:26:33 +02:00
|
|
|
break;
|
|
|
|
|
2005-09-05 17:33:51 +02:00
|
|
|
case XWRELAY_GAME_DISCONNECT:
|
2006-10-02 16:26:56 +02:00
|
|
|
stream_putU16( tmpStream, comms->r.cookieID );
|
|
|
|
stream_putU8( tmpStream, comms->r.myHostID );
|
2005-09-05 17:33:51 +02:00
|
|
|
break;
|
|
|
|
|
2005-07-06 02:58:20 +02:00
|
|
|
case XWRELAY_HEARTBEAT:
|
2005-06-23 06:16:53 +02:00
|
|
|
/* Add these for grins. Server can assert they match the IP
|
|
|
|
address it expects 'em on. */
|
2006-10-02 16:26:56 +02:00
|
|
|
stream_putU16( tmpStream, comms->r.cookieID );
|
|
|
|
stream_putU8( tmpStream, comms->r.myHostID );
|
2005-07-06 02:58:20 +02:00
|
|
|
break;
|
2005-09-02 08:26:33 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
XP_ASSERT(0);
|
2005-03-19 23:01:38 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
len = stream_getSize( tmpStream );
|
|
|
|
buf = XP_MALLOC( comms->mpool, len );
|
|
|
|
if ( buf != NULL ) {
|
|
|
|
stream_getBytes( tmpStream, buf, len );
|
|
|
|
}
|
|
|
|
stream_destroy( tmpStream );
|
|
|
|
if ( buf != NULL ) {
|
2005-06-23 06:16:53 +02:00
|
|
|
XP_U16 result;
|
2005-03-19 23:01:38 +01:00
|
|
|
XP_LOGF( "passing %d bytes to sendproc", len );
|
|
|
|
result = (*comms->sendproc)( buf, len, &addr, comms->sendClosure );
|
2005-06-23 06:16:53 +02:00
|
|
|
success = result == len;
|
|
|
|
if ( success ) {
|
|
|
|
setHeartbeatTimer( comms );
|
|
|
|
}
|
2005-03-19 23:01:38 +01:00
|
|
|
}
|
|
|
|
XP_FREE( comms->mpool, buf );
|
|
|
|
}
|
2005-06-23 06:16:53 +02:00
|
|
|
return success;
|
|
|
|
} /* send_via_relay */
|
2005-03-19 23:01:38 +01:00
|
|
|
|
|
|
|
/* Send a CONNECT message to the relay. This opens up a connection to the
|
|
|
|
* relay, and tells it our hostID and cookie so that it can associatate it
|
|
|
|
* with a socket. In the CONNECT_RESP we should get back what?
|
|
|
|
*/
|
|
|
|
static void
|
2005-06-23 06:16:53 +02:00
|
|
|
relayConnect( CommsCtxt* comms )
|
2005-03-19 23:01:38 +01:00
|
|
|
{
|
2007-02-06 06:49:45 +01:00
|
|
|
LOG_FUNC();
|
2006-10-02 16:26:56 +02:00
|
|
|
if ( comms->addr.conType == COMMS_CONN_RELAY && !comms->r.connecting ) {
|
|
|
|
comms->r.connecting = XP_TRUE;
|
2005-09-02 08:26:33 +02:00
|
|
|
send_via_relay( comms,
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.connName[0] == '\0' ?
|
2005-09-05 17:33:51 +02:00
|
|
|
XWRELAY_GAME_CONNECT:XWRELAY_GAME_RECONNECT,
|
2006-10-02 16:26:56 +02:00
|
|
|
comms->r.myHostID, NULL, 0 );
|
|
|
|
comms->r.connecting = XP_FALSE;
|
2005-04-03 04:49:04 +02:00
|
|
|
}
|
2005-06-23 06:16:53 +02:00
|
|
|
} /* relayConnect */
|
2006-10-10 03:34:37 +02:00
|
|
|
#endif
|
2005-09-05 17:33:51 +02:00
|
|
|
|
2006-08-26 23:12:10 +02:00
|
|
|
#ifdef XWFEATURE_BLUETOOTH
|
|
|
|
static void
|
|
|
|
btConnect( CommsCtxt* comms )
|
|
|
|
{
|
2007-02-04 18:13:01 +01:00
|
|
|
XP_ASSERT( !!comms );
|
2006-08-26 23:12:10 +02:00
|
|
|
/* Ping the bt layer so it'll get sockets set up. PENDING: if I'm server
|
2006-09-23 17:18:01 +02:00
|
|
|
need to do this once per guest record with non-null address. Might as
|
|
|
|
well use real messages if we have 'em. Otherwise a fake size-0 msg. */
|
|
|
|
if ( comms_resendAll( comms ) <= 0 ) {
|
2006-11-11 23:37:36 +01:00
|
|
|
/* any valid ptr will do */
|
|
|
|
(void)(*comms->sendproc)( (const void*)comms, 0, NULL,
|
|
|
|
comms->sendClosure );
|
2006-09-23 17:18:01 +02:00
|
|
|
}
|
2006-08-26 23:12:10 +02:00
|
|
|
} /* btConnect */
|
|
|
|
#endif
|
|
|
|
|
2006-10-10 03:34:37 +02:00
|
|
|
#ifdef XWFEATURE_RELAY
|
2005-09-05 17:33:51 +02:00
|
|
|
static void
|
|
|
|
relayDisconnect( CommsCtxt* comms )
|
|
|
|
{
|
|
|
|
XP_LOGF( "relayDisconnect called" );
|
2006-08-23 06:44:55 +02:00
|
|
|
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
2006-10-02 16:26:56 +02:00
|
|
|
if ( comms->r.relayState != COMMS_RELAYSTATE_UNCONNECTED ) {
|
|
|
|
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
|
2006-08-26 23:12:10 +02:00
|
|
|
send_via_relay( comms, XWRELAY_GAME_DISCONNECT, HOST_ID_NONE,
|
|
|
|
NULL, 0 );
|
2006-08-23 06:44:55 +02:00
|
|
|
}
|
2005-09-05 17:33:51 +02:00
|
|
|
}
|
|
|
|
} /* relayDisconnect */
|
2005-07-23 17:28:15 +02:00
|
|
|
#endif
|
2005-03-19 23:01:38 +01:00
|
|
|
|
2005-01-31 04:31:50 +01:00
|
|
|
EXTERN_C_END
|
|
|
|
|
2003-11-01 06:35:29 +01:00
|
|
|
#endif /* #ifndef XWFEATURE_STANDALONE_ONLY */
|