Re-add direct-via-ip transport, and implement for linux in order to

better test heartbeats.  Fix so can play against Palm over BT.
Assertions failing on Linux when reset, but it's otherwise done.
This commit is contained in:
ehouse 2007-11-26 02:58:25 +00:00
parent 044a889d6d
commit 42615345c9
8 changed files with 373 additions and 264 deletions

View file

@ -53,14 +53,15 @@ typedef struct MsgQueueElem {
XP_U8* msg; XP_U8* msg;
XP_U16 len; XP_U16 len;
XP_U16 channelNo; XP_U16 channelNo;
XP_U16 sendCount; /* how many times sent? */
MsgID msgID; /* saved for ease of deletion */ MsgID msgID; /* saved for ease of deletion */
} MsgQueueElem; } MsgQueueElem;
typedef struct AddressRecord { typedef struct AddressRecord {
struct AddressRecord* next; struct AddressRecord* next;
CommsAddrRec addr; CommsAddrRec addr;
#ifdef DEBUG
XP_U16 lastACK; XP_U16 lastACK;
#ifdef DEBUG
XP_U16 nUniqueBytes; XP_U16 nUniqueBytes;
#endif #endif
MsgID nextMsgID; /* on a per-channel basis */ MsgID nextMsgID; /* on a per-channel basis */
@ -136,11 +137,12 @@ struct CommsCtxt {
MPSLOT MPSLOT
}; };
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
typedef enum { typedef enum {
BTMSG_DATA = 0 BTIPMSG_NONE = 0
,BTMSG_RESET ,BTIPMSG_DATA
} BTMsgType; ,BTIPMSG_RESET
} BTIPMsgType;
#endif #endif
/**************************************************************************** /****************************************************************************
@ -157,6 +159,8 @@ static AddressRecord* getRecordFor( CommsCtxt* comms,
static XP_S16 sendMsg( CommsCtxt* comms, MsgQueueElem* elem ); static XP_S16 sendMsg( CommsCtxt* comms, MsgQueueElem* elem );
static void addToQueue( CommsCtxt* comms, MsgQueueElem* newMsgElem ); static void addToQueue( CommsCtxt* comms, MsgQueueElem* newMsgElem );
static XP_U16 countAddrRecs( const CommsCtxt* comms ); static XP_U16 countAddrRecs( const CommsCtxt* comms );
static void sendConnect( CommsCtxt* comms );
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
static void relayConnect( CommsCtxt* comms ); static void relayConnect( CommsCtxt* comms );
static void relayDisconnect( CommsCtxt* comms ); static void relayDisconnect( CommsCtxt* comms );
@ -166,12 +170,13 @@ static XWHostID getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo );
#endif #endif
#if defined XWFEATURE_RELAY || defined COMMS_HEARTBEAT #if defined XWFEATURE_RELAY || defined COMMS_HEARTBEAT
static void setHeartbeatTimer( CommsCtxt* comms ); static void setHeartbeatTimer( CommsCtxt* comms );
#else
# define setHeartbeatTimer( comms )
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
static XP_S16 send_via_bt( CommsCtxt* comms, BTMsgType typ, static XP_S16 send_via_bt_or_ip( CommsCtxt* comms, BTIPMsgType typ,
XP_PlayerAddr channelNo, XP_PlayerAddr channelNo,
void* data, int dlen ); void* data, int dlen );
static void btConnect( CommsCtxt* comms );
#endif #endif
/**************************************************************************** /****************************************************************************
@ -299,7 +304,7 @@ addrFromStream( CommsAddrRec* addrP, XWStreamCtxt* stream )
case COMMS_CONN_IR: case COMMS_CONN_IR:
/* nothing to save */ /* nothing to save */
break; break;
case COMMS_CONN_IP_NOUSE: case COMMS_CONN_IP_DIRECT:
stringFromStreamHere( stream, addr.u.ip.hostName_ip, stringFromStreamHere( stream, addr.u.ip.hostName_ip,
sizeof(addr.u.ip.hostName_ip) ); sizeof(addr.u.ip.hostName_ip) );
addr.u.ip.ipAddr_ip = stream_getU32( stream ); addr.u.ip.ipAddr_ip = stream_getU32( stream );
@ -398,7 +403,9 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
msg->channelNo = stream_getU16( stream ); msg->channelNo = stream_getU16( stream );
msg->msgID = stream_getU32( stream ); msg->msgID = stream_getU32( stream );
#ifdef COMMS_HEARTBEAT
msg->sendCount = 0;
#endif
msg->len = stream_getU16( stream ); msg->len = stream_getU16( stream );
msg->msg = (XP_U8*)XP_MALLOC( mpool, msg->len ); msg->msg = (XP_U8*)XP_MALLOC( mpool, msg->len );
stream_getBytes( stream, msg->msg, msg->len ); stream_getBytes( stream, msg->msg, msg->len );
@ -419,21 +426,36 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
void void
comms_start( CommsCtxt* comms ) comms_start( CommsCtxt* comms )
{ {
if ( 0 ) {
#ifdef XWFEATURE_RELAY
} else if ( comms->addr.conType == COMMS_CONN_RELAY ) {
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
relayConnect( comms );
#endif
#ifdef XWFEATURE_BLUETOOTH
} else if ( comms->addr.conType == COMMS_CONN_BT ) {
btConnect( comms );
#endif
}
#ifdef COMMS_HEARTBEAT #ifdef COMMS_HEARTBEAT
comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR; comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR;
#endif #endif
sendConnect( comms );
} /* comms_start */
static void
sendConnect( CommsCtxt* comms )
{
switch( comms->addr.conType ) {
#ifdef XWFEATURE_RELAY
case COMMS_CONN_RELAY:
comms->r.relayState = COMMS_RELAYSTATE_UNCONNECTED;
relayConnect( comms );
break;
#endif
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
case COMMS_CONN_BT:
case COMMS_CONN_IP_DIRECT:
send_via_bt_or_ip( comms, BTIPMSG_RESET,
CHANNEL_NONE, NULL, 0 );
(void)comms_resendAll( comms );
break;
#endif
default:
break;
}
setHeartbeatTimer( comms );
} /* comms_start */ } /* comms_start */
static void static void
@ -460,7 +482,7 @@ addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP )
case COMMS_CONN_IR: case COMMS_CONN_IR:
/* nothing to save */ /* nothing to save */
break; break;
case COMMS_CONN_IP_NOUSE: case COMMS_CONN_IP_DIRECT:
stringToStream( stream, addr.u.ip.hostName_ip ); stringToStream( stream, addr.u.ip.hostName_ip );
stream_putU32( stream, addr.u.ip.ipAddr_ip ); stream_putU32( stream, addr.u.ip.ipAddr_ip );
stream_putU16( stream, addr.u.ip.port_ip ); stream_putU16( stream, addr.u.ip.port_ip );
@ -546,22 +568,16 @@ void
comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr ) comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr )
{ {
XP_ASSERT( comms != NULL ); XP_ASSERT( comms != NULL );
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH #if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
util_addrChange( comms->util, &comms->addr, addr ); util_addrChange( comms->util, &comms->addr, addr );
#endif #endif
XP_MEMCPY( &comms->addr, addr, sizeof(comms->addr) ); XP_MEMCPY( &comms->addr, addr, sizeof(comms->addr) );
if ( 0 ) { #ifdef COMMS_HEARTBEAT
#ifdef XWFEATURE_RELAY comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR;
/* We should now have a cookie so we can connect??? */
} else if ( addr->conType == COMMS_CONN_RELAY ) {
relayConnect( comms );
#endif #endif
#ifdef XWFEATURE_BLUETOOTH sendConnect( comms );
} else if ( addr->conType == COMMS_CONN_BT ) {
btConnect( comms );
#endif
}
#ifdef COMMS_HEARTBEAT #ifdef COMMS_HEARTBEAT
comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR; comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR;
#endif #endif
@ -601,9 +617,9 @@ comms_getIsServer( const CommsCtxt* comms )
return comms->isServer; return comms->isServer;
} }
static XP_S16 static MsgQueueElem*
sendWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec, makeElemWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
XP_PlayerAddr channelNo, XWStreamCtxt* stream ) XP_PlayerAddr channelNo, XWStreamCtxt* stream )
{ {
XP_U16 headerLen; XP_U16 headerLen;
XP_U16 streamSize = NULL == stream? 0 : stream_getSize( stream ); XP_U16 streamSize = NULL == stream? 0 : stream_getSize( stream );
@ -623,6 +639,9 @@ sendWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
sizeof( *newMsgElem ) ); sizeof( *newMsgElem ) );
newMsgElem->channelNo = channelNo; newMsgElem->channelNo = channelNo;
newMsgElem->msgID = msgID; newMsgElem->msgID = msgID;
#ifdef COMMS_HEARTBEAT
newMsgElem->sendCount = 0;
#endif
msgStream = mem_stream_make( MPPARM(comms->mpool) msgStream = mem_stream_make( MPPARM(comms->mpool)
util_getVTManager(comms->util), util_getVTManager(comms->util),
@ -646,10 +665,8 @@ sendWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
stream_getBytes( stream, newMsgElem->msg + headerLen, streamSize ); stream_getBytes( stream, newMsgElem->msg + headerLen, streamSize );
} }
addToQueue( comms, newMsgElem ); return newMsgElem;
} /* makeElemWithID */
return sendMsg( comms, newMsgElem );
} /* sendWithID */
/* Send a message using the sequentially next MsgID. Save the message so /* Send a message using the sequentially next MsgID. Save the message so
* resend can work. */ * resend can work. */
@ -659,9 +676,17 @@ comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
XP_PlayerAddr channelNo = stream_getAddress( stream ); XP_PlayerAddr channelNo = stream_getAddress( stream );
AddressRecord* rec = getRecordFor( comms, channelNo ); AddressRecord* rec = getRecordFor( comms, channelNo );
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0; MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
MsgQueueElem* elem;
XP_S16 result = -1;
XP_DEBUGF( "assigning msgID=" XP_LD " on chnl %d", msgID, channelNo ); XP_DEBUGF( "assigning msgID=" XP_LD " on chnl %d", msgID, channelNo );
return sendWithID( comms, msgID, rec, channelNo, stream );
elem = makeElemWithID( comms, msgID, rec, channelNo, stream );
if ( NULL != elem ) {
addToQueue( comms, elem );
result = sendMsg( comms, elem );
}
return result;
} /* comms_send */ } /* comms_send */
/* Add new message to the end of the list. The list needs to be kept in order /* Add new message to the end of the list. The list needs to be kept in order
@ -702,6 +727,13 @@ printQueue( CommsCtxt* comms )
} }
#endif #endif
static void
freeElem( const CommsCtxt* comms, MsgQueueElem* elem )
{
XP_FREE( comms->mpool, elem->msg );
XP_FREE( comms->mpool, elem );
}
/* We've received on some channel a message with a certain ID. This means /* 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 * that all messages sent on that channel with lower IDs have been received
* and can be removed from our queue. BUT: if this ID is higher than any * and can be removed from our queue. BUT: if this ID is higher than any
@ -737,8 +769,7 @@ removeFromQueue( CommsCtxt* comms, XP_PlayerAddr channelNo, MsgID msgID )
} }
if ( !knownGood && (elem->msgID <= msgID) ) { if ( !knownGood && (elem->msgID <= msgID) ) {
XP_FREE( comms->mpool, elem->msg ); freeElem( comms, elem );
XP_FREE( comms->mpool, elem );
--comms->queueLen; --comms->queueLen;
} else { } else {
keep->next = elem; keep->next = elem;
@ -762,7 +793,7 @@ removeFromQueue( CommsCtxt* comms, XP_PlayerAddr channelNo, MsgID msgID )
static XP_S16 static XP_S16
sendMsg( CommsCtxt* comms, MsgQueueElem* elem ) sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
{ {
XP_S16 result = 0; XP_S16 result = -1;
XP_PlayerAddr channelNo; XP_PlayerAddr channelNo;
#if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH #if defined XWFEATURE_RELAY || defined XWFEATURE_BLUETOOTH
CommsConnType conType = comms_getConType( comms ); CommsConnType conType = comms_getConType( comms );
@ -781,10 +812,13 @@ sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
XP_LOGF( "%s: skipping message: not connected", __func__ ); XP_LOGF( "%s: skipping message: not connected", __func__ );
} }
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
} else if ( conType == COMMS_CONN_BT ) { } else if ( conType == COMMS_CONN_BT || conType == COMMS_CONN_IP_DIRECT ) {
result = send_via_bt( comms, BTMSG_DATA, channelNo, result = send_via_bt_or_ip( comms, BTIPMSG_DATA, channelNo,
elem->msg, elem->len ); elem->msg, elem->len );
#ifdef COMMS_HEARTBEAT
setHeartbeatTimer( comms );
#endif
#endif #endif
} else { } else {
const CommsAddrRec* addr; const CommsAddrRec* addr;
@ -794,6 +828,12 @@ sendMsg( CommsCtxt* comms, MsgQueueElem* elem )
result = (*comms->sendproc)( elem->msg, elem->len, addr, result = (*comms->sendproc)( elem->msg, elem->len, addr,
comms->sendClosure ); comms->sendClosure );
} }
if ( result == elem->len ) {
++elem->sendCount;
XP_LOGF( "sendCount now %d", elem->sendCount );
}
return result; return result;
} /* sendMsg */ } /* sendMsg */
@ -898,22 +938,51 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
} /* relayPreProcess */ } /* relayPreProcess */
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
static XP_Bool static XP_Bool
btPreProcess( CommsCtxt* comms, XWStreamCtxt* stream ) btIpPreProcess( CommsCtxt* comms, XWStreamCtxt* stream )
{ {
BTMsgType typ = (BTMsgType)stream_getU8( stream ); BTIPMsgType typ = (BTIPMsgType)stream_getU8( stream );
XP_Bool consumed = typ != BTMSG_DATA; XP_Bool consumed = typ != BTIPMSG_DATA;
if ( consumed ) { if ( consumed ) {
XP_ASSERT( typ == BTMSG_RESET ); /* This is all there is so far */
XP_ASSERT( typ == BTIPMSG_RESET );
(void)comms_resendAll( comms ); (void)comms_resendAll( comms );
} }
return consumed; return consumed;
} /* btPreProcess */ } /* btIpPreProcess */
#endif #endif
static XP_Bool
preProcess( CommsCtxt* comms, XWStreamCtxt* stream,
XP_Bool* usingRelay, XWHostID* senderID )
{
XP_Bool consumed = XP_FALSE;
switch ( comms->addr.conType ) {
#ifdef XWFEATURE_RELAY
/* relayPreProcess returns true if consumes the message. May just eat the
header and leave a regular message to be processed below. */
case COMMS_CONN_RELAY:
consumed = relayPreProcess( comms, stream, senderID );
if ( !consumed ) {
*usingRelay = comms->addr.conType == COMMS_CONN_RELAY;
}
break;
#endif
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
case COMMS_CONN_BT:
case COMMS_CONN_IP_DIRECT:
consumed = btIpPreProcess( comms, stream );
break;
#endif
default:
break;
}
return consumed;
} /* preProcess */
static XP_Bool static XP_Bool
addressUnknown( CommsCtxt* comms, const CommsAddrRec* addr ) addressUnknown( CommsCtxt* comms, const CommsAddrRec* addr )
{ {
@ -976,27 +1045,10 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
XWHostID senderID = 0; /* unset; default for non-relay cases */ XWHostID senderID = 0; /* unset; default for non-relay cases */
XP_Bool usingRelay = XP_FALSE; XP_Bool usingRelay = XP_FALSE;
XP_Bool channelWas0 = XP_FALSE; XP_Bool channelWas0 = XP_FALSE;
XP_Bool done = XP_FALSE;
XP_ASSERT( addr == NULL || comms->addr.conType == addr->conType ); XP_ASSERT( addr == NULL || comms->addr.conType == addr->conType );
if ( 0 ) { if ( !preProcess( comms, stream, &usingRelay, &senderID ) ) {
#ifdef XWFEATURE_RELAY
/* relayPreProcess returns true if consumes the message. May just eat the
header and leave a regular message to be processed below. */
} else if ( comms->addr.conType == COMMS_CONN_RELAY ) {
done = relayPreProcess( comms, stream, &senderID );
if ( !done ) {
usingRelay = comms->addr.conType == COMMS_CONN_RELAY;
}
#endif
#ifdef XWFEATURE_BLUETOOTH
} else if ( comms->addr.conType == COMMS_CONN_BT ) {
done = btPreProcess( comms, stream );
#endif
}
if ( !done ) {
if ( stream_getSize( stream ) >= sizeof(connID) ) { if ( stream_getSize( stream ) >= sizeof(connID) ) {
connID = stream_getU32( stream ); connID = stream_getU32( stream );
XP_STATUSF( "%s: read connID of %lx", __func__, connID ); XP_STATUSF( "%s: read connID of %lx", __func__, connID );
@ -1073,14 +1125,16 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
} }
#ifdef DEBUG #ifdef DEBUG
if ( !!recs ) { if ( !!recs ) {
XP_ASSERT( lastMsgRcd <= recs->nextMsgID ); /* XP_ASSERT( lastMsgRcd <= recs->nextMsgID ); */
if ( lastMsgRcd > recs->nextMsgID ) { if ( lastMsgRcd > recs->nextMsgID ) {
XP_LOGF( "bad: got lastMsgRcd of %ld, " XP_LOGF( "bad: got lastMsgRcd of %ld, "
"nextMsgID is %ld", "nextMsgID is %ld",
lastMsgRcd, recs->nextMsgID ); lastMsgRcd, recs->nextMsgID );
validMessage = XP_FALSE;
} else {
XP_ASSERT( lastMsgRcd < 0x0000FFFF );
recs->lastACK = (XP_U16)lastMsgRcd;
} }
XP_ASSERT( lastMsgRcd < 0x0000FFFF );
recs->lastACK = (XP_U16)lastMsgRcd;
} }
#endif #endif
} }
@ -1146,7 +1200,9 @@ heartbeat_checks( CommsCtxt* comms )
for ( elem = comms->msgQueueHead; !!elem; elem = elem->next ) { for ( elem = comms->msgQueueHead; !!elem; elem = elem->next ) {
XP_ASSERT( elem->channelNo < MAX_NUM_PLAYERS ); XP_ASSERT( elem->channelNo < MAX_NUM_PLAYERS );
++pendingPacks[elem->channelNo]; if ( elem->sendCount == 0 ) { /* still waiting being sent? */
++pendingPacks[elem->channelNo];
}
} }
now = util_getCurSeconds( comms->util ); now = util_getCurSeconds( comms->util );
@ -1154,17 +1210,27 @@ heartbeat_checks( CommsCtxt* comms )
for ( rec = comms->recs; !!rec; rec = rec->next ) { for ( rec = comms->recs; !!rec; rec = rec->next ) {
XP_U32 lastMsgRcvdTime = rec->lastMsgRcvdTime; XP_U32 lastMsgRcvdTime = rec->lastMsgRcvdTime;
if ( lastMsgRcvdTime == 0 ) { /* nothing received yet */ if ( lastMsgRcvdTime == 0 ) { /* nothing received yet */
XP_LOGF( "no last message" );
/* do nothing; or should we send? */ /* do nothing; or should we send? */
} else if ( (lastMsgRcvdTime > 0) && (lastMsgRcvdTime < tooLongAgo) ) { } else if ( (lastMsgRcvdTime > 0) && (lastMsgRcvdTime < tooLongAgo) ) {
XP_LOGF( "calling reset proc" ); XP_LOGF( "calling reset proc; last was %ld secs too long ago",
tooLongAgo-lastMsgRcvdTime );
(*comms->resetproc)(comms->sendClosure); (*comms->resetproc)(comms->sendClosure);
resetTimer = XP_FALSE; resetTimer = XP_FALSE;
break; break;
} else if ( 0 == pendingPacks[rec->channelNo] ) { } else if ( 0 == pendingPacks[rec->channelNo] ) {
XP_LOGF( "sending heartbeat on channel %d", rec->channelNo ); MsgQueueElem* hb;
sendWithID( comms, rec->lastMsgReceived, rec, rec->channelNo, NULL ); XP_LOGF( "sending heartbeat on channel %d with msgID %d",
rec->channelNo, rec->lastMsgReceived );
hb = makeElemWithID( comms, rec->lastACK, rec, rec->channelNo, NULL );
if ( NULL != hb ) {
sendMsg( comms, hb );
freeElem( comms, hb );
} else {
XP_ASSERT( XP_FALSE );
}
} else { } else {
XP_LOGF( "All's well" ); XP_LOGF( "All's well (%d pending)", pendingPacks[rec->channelNo] );
resetTimer = XP_TRUE; resetTimer = XP_TRUE;
} }
} }
@ -1199,6 +1265,7 @@ p_comms_timerFired( void* closure, XWTimerReason XP_UNUSED_DBG(why) )
static void static void
setHeartbeatTimer( CommsCtxt* comms ) setHeartbeatTimer( CommsCtxt* comms )
{ {
LOG_FUNC();
#ifdef RELAY_HEARTBEAT #ifdef RELAY_HEARTBEAT
if ( comms->addr.conType == COMMS_CONN_RELAY ) { if ( comms->addr.conType == COMMS_CONN_RELAY ) {
util_setTimer( comms->util, TIMER_HEARTBEAT, comms->r.heartbeat, util_setTimer( comms->util, TIMER_HEARTBEAT, comms->r.heartbeat,
@ -1463,22 +1530,10 @@ relayConnect( CommsCtxt* comms )
} /* relayConnect */ } /* relayConnect */
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_IP_DIRECT
static void
btConnect( CommsCtxt* comms )
{
XP_ASSERT( !!comms );
/* Ping the bt layer so it'll get sockets set up. PENDING: if I'm server
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. */
send_via_bt( comms, BTMSG_RESET, CHANNEL_NONE, NULL, 0 );
(void)( comms_resendAll( comms ) );
} /* btConnect */
static XP_S16 static XP_S16
send_via_bt( CommsCtxt* comms, BTMsgType typ, XP_PlayerAddr channelNo, send_via_bt_or_ip( CommsCtxt* comms, BTIPMsgType typ, XP_PlayerAddr channelNo,
void* data, int dlen ) void* data, int dlen )
{ {
XP_U8* buf; XP_U8* buf;
XP_S16 nSent = -1; XP_S16 nSent = -1;
@ -1499,7 +1554,7 @@ send_via_bt( CommsCtxt* comms, BTMsgType typ, XP_PlayerAddr channelNo,
setHeartbeatTimer( comms ); setHeartbeatTimer( comms );
} }
return nSent; return nSent;
} /* send_via_bt */ } /* send_via_bt_or_ip */
#endif #endif

View file

@ -35,7 +35,7 @@ typedef XP_U8 XWHostID;
typedef enum { typedef enum {
COMMS_CONN_UNUSED, /* I want errors on uninited case */ COMMS_CONN_UNUSED, /* I want errors on uninited case */
COMMS_CONN_IR, COMMS_CONN_IR,
COMMS_CONN_IP_NOUSE, COMMS_CONN_IP_DIRECT,
COMMS_CONN_RELAY, COMMS_CONN_RELAY,
COMMS_CONN_BT, COMMS_CONN_BT,

View file

@ -70,6 +70,10 @@ BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_L2CAP
DEFINES += ${BLUETOOTH} DEFINES += ${BLUETOOTH}
DEFINES += -DXWFEATURE_RELAY DEFINES += -DXWFEATURE_RELAY
# Support device-to-device connection via UDP, e.g. using wifi on a
# LAN or where the host/server isn't behind a firewall.
DEFINES += -DXWFEATURE_IP_DIRECT
# Choose one of these. RELAY_HEARTBEAT means relay (must be compiled # Choose one of these. RELAY_HEARTBEAT means relay (must be compiled
# with same -D) works with comms on heartbeat. Works only with relay. # with same -D) works with comms on heartbeat. Works only with relay.
# COMMS_HEARTBEAT should work on any comms transport (even IR, but # COMMS_HEARTBEAT should work on any comms transport (even IR, but
@ -106,6 +110,7 @@ OBJ = $(PLATFORM)/linuxmain.o \
$(PLATFORM)/cursesletterask.o \ $(PLATFORM)/cursesletterask.o \
$(PLATFORM)/filestream.o \ $(PLATFORM)/filestream.o \
$(PLATFORM)/linuxbt.o \ $(PLATFORM)/linuxbt.o \
$(PLATFORM)/linuxudp.o \
# $(PLATFORM)/linuxcommpipe.o \ # $(PLATFORM)/linuxcommpipe.o \

View file

@ -665,11 +665,12 @@ static void
curses_stop_listening( CursesAppGlobals* globals, int sock ) curses_stop_listening( CursesAppGlobals* globals, int sock )
{ {
int count = globals->fdCount; int count = globals->fdCount;
int i, found = 0; int i;
bool found = false;
for ( i = 0; i < count; ++i ) { for ( i = 0; i < count; ++i ) {
if ( globals->fdArray[i].fd == sock ) { if ( globals->fdArray[i].fd == sock ) {
found = 1; found = true;
} else if ( found ) { } else if ( found ) {
globals->fdArray[i-1].fd = globals->fdArray[i].fd; globals->fdArray[i-1].fd = globals->fdArray[i].fd;
} }
@ -680,7 +681,8 @@ curses_stop_listening( CursesAppGlobals* globals, int sock )
} /* curses_stop_listening */ } /* curses_stop_listening */
static void static void
curses_socket_changed( void* closure, int oldSock, int newSock ) curses_socket_changed( void* closure, int oldSock, int newSock,
void** XP_UNUSED(storage) )
{ {
CursesAppGlobals* globals = (CursesAppGlobals*)closure; CursesAppGlobals* globals = (CursesAppGlobals*)closure;
if ( oldSock != -1 ) { if ( oldSock != -1 ) {
@ -1014,7 +1016,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
globals.amServer = isServer; globals.amServer = isServer;
globals.cGlobals.params = params; globals.cGlobals.params = params;
#ifdef XWFEATURE_RELAY
globals.cGlobals.socket = -1; globals.cGlobals.socket = -1;
#endif
globals.cGlobals.socketChanged = curses_socket_changed; globals.cGlobals.socketChanged = curses_socket_changed;
globals.cGlobals.socketChangedClosure = &globals; globals.cGlobals.socketChangedClosure = &globals;

View file

@ -42,6 +42,7 @@
#include "main.h" #include "main.h"
#include "linuxmain.h" #include "linuxmain.h"
#include "linuxbt.h" #include "linuxbt.h"
#include "linuxudp.h"
/* #include "gtkmain.h" */ /* #include "gtkmain.h" */
#include "draw.h" #include "draw.h"
@ -59,7 +60,6 @@
/* static guint gtkSetupClientSocket( GtkAppGlobals* globals, int sock ); */ /* static guint gtkSetupClientSocket( GtkAppGlobals* globals, int sock ); */
static void sendOnClose( XWStreamCtxt* stream, void* closure ); static void sendOnClose( XWStreamCtxt* stream, void* closure );
static XP_Bool file_exists( const char* fileName ); static XP_Bool file_exists( const char* fileName );
static void gtkListenOnSocket( GtkAppGlobals* globals, int newSock );
static void setCtrlsForTray( GtkAppGlobals* globals ); static void setCtrlsForTray( GtkAppGlobals* globals );
static void printFinalScores( GtkAppGlobals* globals ); static void printFinalScores( GtkAppGlobals* globals );
@ -317,6 +317,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
XP_U16 gameID; XP_U16 gameID;
CommsAddrRec addr; CommsAddrRec addr;
XP_MEMSET( &addr, 0, sizeof(addr) );
addr.conType = params->conType; addr.conType = params->conType;
gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util ); gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util );
@ -354,6 +355,12 @@ createOrLoadObjects( GtkAppGlobals* globals )
>= sizeof(params->connInfo.bt.hostAddr)); >= sizeof(params->connInfo.bt.hostAddr));
XP_MEMCPY( &addr.u.bt.btAddr, &params->connInfo.bt.hostAddr, XP_MEMCPY( &addr.u.bt.btAddr, &params->connInfo.bt.hostAddr,
sizeof(params->connInfo.bt.hostAddr) ); sizeof(params->connInfo.bt.hostAddr) );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( addr.conType == COMMS_CONN_IP_DIRECT ) {
XP_STRNCPY( addr.u.ip.hostName_ip, params->connInfo.ip.hostName,
sizeof(addr.u.ip.hostName_ip) - 1 );
addr.u.ip.port_ip = params->connInfo.ip.port;
#endif #endif
} }
@ -378,6 +385,10 @@ createOrLoadObjects( GtkAppGlobals* globals )
} }
} }
if ( !!globals->cGlobals.game.comms ) {
comms_start( globals->cGlobals.game.comms );
}
server_do( globals->cGlobals.game.server ); server_do( globals->cGlobals.game.server );
} /* createOrLoadObjects */ } /* createOrLoadObjects */
@ -548,6 +559,9 @@ quit( void* XP_UNUSED(dunno), GtkAppGlobals* globals )
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
linux_bt_close( &globals->cGlobals ); linux_bt_close( &globals->cGlobals );
#endif
#ifdef XWFEATURE_IP_DIRECT
linux_udp_close( &globals->cGlobals );
#endif #endif
vtmgr_destroy( MEMPOOL globals->cGlobals.params->vtMgr ); vtmgr_destroy( MEMPOOL globals->cGlobals.params->vtMgr );
@ -1201,7 +1215,7 @@ score_timer_func( gpointer data )
return XP_FALSE; return XP_FALSE;
} /* score_timer_func */ } /* score_timer_func */
#ifdef XWFEATURE_RELAY #if defined RELAY_HEARTBEAT || defined COMMS_HEARTBEAT
static gint static gint
heartbeat_timer_func( gpointer data ) heartbeat_timer_func( gpointer data )
{ {
@ -1217,7 +1231,7 @@ heartbeat_timer_func( gpointer data )
static void static void
gtk_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why, gtk_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
XP_U16 XP_UNUSED_RELAY(when), XP_U16 when,
XWTimerProc proc, void* closure ) XWTimerProc proc, void* closure )
{ {
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure; GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
@ -1236,7 +1250,7 @@ gtk_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
(void)gettimeofday( &globals->scoreTv, NULL ); (void)gettimeofday( &globals->scoreTv, NULL );
newSrc = g_timeout_add( 1000, score_timer_func, globals ); newSrc = g_timeout_add( 1000, score_timer_func, globals );
#ifdef XWFEATURE_RELAY #if defined RELAY_HEARTBEAT || defined COMMS_HEARTBEAT
} else if ( why == TIMER_HEARTBEAT ) { } else if ( why == TIMER_HEARTBEAT ) {
newSrc = g_timeout_add( 1000 * when, heartbeat_timer_func, globals ); newSrc = g_timeout_add( 1000 * when, heartbeat_timer_func, globals );
#endif #endif
@ -1570,17 +1584,26 @@ newConnectionInput( GIOChannel *source,
if ( (condition & (G_IO_HUP | G_IO_ERR)) != 0 ) { if ( (condition & (G_IO_HUP | G_IO_ERR)) != 0 ) {
XP_LOGF( "dropping socket %d", sock ); XP_LOGF( "dropping socket %d", sock );
close( sock ); close( sock );
#ifdef XWFEATURE_RELAY
globals->cGlobals.socket = -1; globals->cGlobals.socket = -1;
#ifdef XWFEATURE_BLUETOOTH
if ( COMMS_CONN_BT == globals->cGlobals.params->conType ) {
linux_bt_socketclosed( &globals->cGlobals, sock );
}
#endif #endif
if ( 0 ) {
#ifdef XWFEATURE_BLUETOOTH
} else if ( COMMS_CONN_BT == globals->cGlobals.params->conType ) {
linux_bt_socketclosed( &globals->cGlobals, sock );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( COMMS_CONN_IP_DIRECT == globals->cGlobals.params->conType ) {
linux_udp_socketclosed( &globals->cGlobals, sock );
#endif
}
keepSource = FALSE; /* remove the event source */ keepSource = FALSE; /* remove the event source */
} else if ( (condition & G_IO_IN) != 0 ) { } else if ( (condition & G_IO_IN) != 0 ) {
ssize_t nRead; ssize_t nRead;
unsigned char buf[512]; unsigned char buf[512];
CommsAddrRec addr;
CommsAddrRec* addrp = NULL;
if ( 0 ) { if ( 0 ) {
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
@ -1591,6 +1614,11 @@ newConnectionInput( GIOChannel *source,
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
} else if ( globals->cGlobals.params->conType == COMMS_CONN_BT ) { } else if ( globals->cGlobals.params->conType == COMMS_CONN_BT ) {
nRead = linux_bt_receive( sock, buf, sizeof(buf) ); nRead = linux_bt_receive( sock, buf, sizeof(buf) );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( globals->cGlobals.params->conType == COMMS_CONN_IP_DIRECT ) {
addrp = &addr;
nRead = linux_udp_receive( sock, buf, sizeof(buf), addrp, &globals->cGlobals );
#endif #endif
} else { } else {
XP_ASSERT( 0 ); XP_ASSERT( 0 );
@ -1603,7 +1631,7 @@ newConnectionInput( GIOChannel *source,
inboundS = stream_from_msgbuf( &globals->cGlobals, buf, nRead ); inboundS = stream_from_msgbuf( &globals->cGlobals, buf, nRead );
if ( !!inboundS ) { if ( !!inboundS ) {
if ( comms_checkIncomingStream( globals->cGlobals.game.comms, if ( comms_checkIncomingStream( globals->cGlobals.game.comms,
inboundS, NULL ) ) { inboundS, addrp ) ) {
redraw = redraw =
server_receiveMessage(globals->cGlobals.game.server, server_receiveMessage(globals->cGlobals.game.server,
inboundS ); inboundS );
@ -1631,40 +1659,50 @@ newConnectionInput( GIOChannel *source,
return keepSource; /* FALSE means to remove event source */ return keepSource; /* FALSE means to remove event source */
} /* newConnectionInput */ } /* newConnectionInput */
/* Make gtk listen for events on the socket that clients will use to typedef struct SockInfo {
* connect to us. GIOChannel* channel;
*/ guint watch;
static void int socket;
gtkListenOnSocket( GtkAppGlobals* globals, int newSock ) } SockInfo;
{
GIOChannel* channel = g_io_channel_unix_new( newSock );
guint result = g_io_add_watch( channel,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
newConnectionInput,
globals );
XP_LOGF( "g_io_add_watch(%d) => %d", newSock, result );
} /* gtkListenOnSocket */
static void static void
gtk_socket_changed( void* closure, int oldSock, int newSock ) gtk_socket_changed( void* closure, int oldSock, int newSock, void** storage )
{ {
GtkAppGlobals* globals = (GtkAppGlobals*)closure; GtkAppGlobals* globals = (GtkAppGlobals*)closure;
SockInfo* info = (SockInfo*)*storage;
XP_LOGF( "%s(old:%d; new:%d)", __func__, oldSock, newSock );
if ( oldSock != -1 ) { if ( oldSock != -1 ) {
g_source_remove( oldSock ); XP_ASSERT( info != NULL );
XP_LOGF( "Removed %d from gtk's list of listened-to sockets" ); g_source_remove( info->watch );
g_io_channel_unref( info->channel );
XP_FREE( globals->cGlobals.params->util->mpool, info );
*storage = NULL;
XP_LOGF( "Removed socket %d from gtk's list of listened-to sockets", oldSock );
} }
if ( newSock != -1 ) { if ( newSock != -1 ) {
gtkListenOnSocket( globals, newSock ); info = (SockInfo*)XP_MALLOC( globals->cGlobals.params->util->mpool,
sizeof(*info) );
GIOChannel* channel = g_io_channel_unix_new( newSock );
g_io_channel_set_close_on_unref( channel, TRUE );
guint result = g_io_add_watch( channel,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
newConnectionInput,
globals );
info->channel = channel;
info->watch = result;
*storage = info;
XP_LOGF( "g_io_add_watch(%d) => %d", newSock, result );
} }
#ifdef XWFEATURE_RELAY
globals->cGlobals.socket = newSock; globals->cGlobals.socket = newSock;
#endif
/* A hack for the bluetooth case. */ /* A hack for the bluetooth case. */
CommsCtxt* comms = globals->cGlobals.game.comms; CommsCtxt* comms = globals->cGlobals.game.comms;
if ( comms != NULL ) { if ( (comms != NULL) && (comms_getConType(comms) == COMMS_CONN_BT) ) {
comms_resendAll( comms ); comms_resendAll( comms );
} }
LOG_RETURN_VOID();
} }
static gboolean static gboolean
@ -1739,7 +1777,9 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
globals.cGlobals.params = params; globals.cGlobals.params = params;
globals.cGlobals.lastNTilesToUse = MAX_TRAY_TILES; globals.cGlobals.lastNTilesToUse = MAX_TRAY_TILES;
#ifdef XWFEATURE_RELAY
globals.cGlobals.socket = -1; globals.cGlobals.socket = -1;
#endif
globals.cGlobals.socketChanged = gtk_socket_changed; globals.cGlobals.socketChanged = gtk_socket_changed;
globals.cGlobals.socketChangedClosure = &globals; globals.cGlobals.socketChangedClosure = &globals;

View file

@ -42,7 +42,7 @@
#include "comms.h" #include "comms.h"
#include "strutils.h" #include "strutils.h"
#define MAX_CLIENTS 3 #define MAX_CLIENTS 1
#if defined BT_USE_L2CAP #if defined BT_USE_L2CAP
# define L2_RF_ADDR struct sockaddr_l2 # define L2_RF_ADDR struct sockaddr_l2
@ -50,81 +50,22 @@
# define L2_RF_ADDR struct sockaddr_rc # define L2_RF_ADDR struct sockaddr_rc
#endif #endif
typedef struct BtaddrSockMap {
bdaddr_t btaddr;
int sock;
} BtaddrSockMap;
typedef struct LinBtStuff { typedef struct LinBtStuff {
CommonGlobals* globals; CommonGlobals* globals;
void* sockStorage;
union { union {
struct { struct {
BtaddrSockMap socks[MAX_CLIENTS];
int listener; /* socket */ int listener; /* socket */
XP_U16 nSocks;
XP_Bool threadDie; XP_Bool threadDie;
sdp_session_t* session; sdp_session_t* session;
} master; } master;
} u; } u;
/* A single socket's fine as long as there's only one client allowed. */
int socket;
XP_Bool amMaster; XP_Bool amMaster;
} LinBtStuff; } LinBtStuff;
static void
lbt_addSock( LinBtStuff* btStuff, const bdaddr_t* btaddr, int sock )
{
XP_U16 i;
XP_Bool done = XP_FALSE;
XP_ASSERT( btStuff->amMaster );
XP_ASSERT( btStuff->u.master.nSocks < MAX_CLIENTS - 1 );
/* first look for an older entry for the same device. If found, close the
socket and replace. No change in nSocks. */
for ( i = 0; i < MAX_CLIENTS; ++i ) {
BtaddrSockMap* mp = &btStuff->u.master.socks[i];
if ( (mp->sock != -1) && (0 == memcmp( btaddr, &mp->btaddr, sizeof(*btaddr) )) ) {
(void)close( mp->sock );
mp->sock = sock;
done = XP_TRUE;
break;
}
}
if ( !done ) {
for ( i = 0; i < MAX_CLIENTS; ++i ) {
BtaddrSockMap* mp = &btStuff->u.master.socks[i];
if ( mp->sock == -1 ) {
XP_MEMCPY( &mp->btaddr, btaddr, sizeof(mp->btaddr) );
mp->sock = sock;
++btStuff->u.master.nSocks;
break;
}
}
}
XP_ASSERT( i < MAX_CLIENTS );
} /* lbt_addSock */
static void
lbt_removeSock( LinBtStuff* btStuff, int sock )
{
XP_U16 i;
XP_ASSERT( btStuff->amMaster );
for ( i = 0; i < MAX_CLIENTS; ++i ) {
BtaddrSockMap* mp = &btStuff->u.master.socks[i];
if ( mp->sock == sock ) {
mp->sock = -1;
XP_ASSERT( btStuff->u.master.nSocks > 0 );
--btStuff->u.master.nSocks;
break;
}
}
} /* lbt_removeSock */
static LinBtStuff* static LinBtStuff*
lbt_make( MPFORMAL XP_Bool amMaster ) lbt_make( MPFORMAL XP_Bool amMaster )
{ {
@ -132,13 +73,7 @@ lbt_make( MPFORMAL XP_Bool amMaster )
XP_MEMSET( btStuff, 0, sizeof(*btStuff) ); XP_MEMSET( btStuff, 0, sizeof(*btStuff) );
btStuff->amMaster = amMaster; btStuff->amMaster = amMaster;
btStuff->socket = -1;
if ( amMaster ) {
XP_U16 i;
for ( i = 0; i < MAX_CLIENTS; ++i ) {
btStuff->u.master.socks[i].sock = -1;
}
}
return btStuff; return btStuff;
} /* lbt_make */ } /* lbt_make */
@ -217,6 +152,7 @@ getL2Addr( const CommsAddrRec const* addrP, L2_RF_ADDR* const saddr )
sdp_close( session ); sdp_close( session );
} }
LOG_RETURNF( "%p", result );
return result; return result;
} /* getL2Addr */ } /* getL2Addr */
@ -224,6 +160,7 @@ static void
lbt_connectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP ) lbt_connectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
{ {
int sock; int sock;
LOG_FUNC();
// allocate a socket // allocate a socket
sock = socket( AF_BLUETOOTH, sock = socket( AF_BLUETOOTH,
@ -244,7 +181,8 @@ lbt_connectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
&& (0 == connect( sock, (struct sockaddr *)&saddr, sizeof(saddr) )) ) { && (0 == connect( sock, (struct sockaddr *)&saddr, sizeof(saddr) )) ) {
CommonGlobals* globals = btStuff->globals; CommonGlobals* globals = btStuff->globals;
(*globals->socketChanged)( globals->socketChangedClosure, (*globals->socketChanged)( globals->socketChangedClosure,
-1, sock ); -1, sock, &btStuff->sockStorage );
btStuff->socket = sock;
} else { } else {
XP_LOGF( "%s: connect->%s; closing socket %d", __FUNCTION__, strerror(errno), sock ); XP_LOGF( "%s: connect->%s; closing socket %d", __FUNCTION__, strerror(errno), sock );
close( sock ); close( sock );
@ -272,13 +210,10 @@ lbt_accept( int listener, void* ctxt )
success = sock >= 0; success = sock >= 0;
if ( success ) { if ( success ) {
#if defined BT_USE_L2CAP
lbt_addSock( btStuff, &inaddr.l2_bdaddr, sock );
#elif defined BT_USE_RFCOMM
lbt_addSock( btStuff, &inaddr.rc_bdaddr, sock );
#endif
(*globals->socketChanged)( globals->socketChangedClosure, (*globals->socketChanged)( globals->socketChangedClosure,
-1, sock ); -1, sock, &btStuff->sockStorage );
XP_ASSERT( btStuff->socket == -1 );
btStuff->socket = sock;
} else { } else {
XP_LOGF( "%s: accept->%s", __FUNCTION__, strerror(errno) ); XP_LOGF( "%s: accept->%s", __FUNCTION__, strerror(errno) );
} }
@ -423,12 +358,14 @@ linux_bt_open( CommonGlobals* globals, XP_Bool amMaster )
btStuff = globals->btStuff btStuff = globals->btStuff
= lbt_make( MPPARM(globals->params->util->mpool) amMaster ); = lbt_make( MPPARM(globals->params->util->mpool) amMaster );
btStuff->globals = globals; btStuff->globals = globals;
btStuff->socket = -1;
globals->btStuff = btStuff; globals->btStuff = btStuff;
if ( amMaster ) { if ( amMaster ) {
lbt_listenerSetup( globals ); lbt_listenerSetup( globals );
} else { } else {
if ( globals->socket < 0 ) { if ( btStuff->socket < 0 ) {
CommsAddrRec addr; CommsAddrRec addr;
comms_getAddr( globals->game.comms, &addr ); comms_getAddr( globals->game.comms, &addr );
lbt_connectSocket( btStuff, &addr ); lbt_connectSocket( btStuff, &addr );
@ -451,7 +388,6 @@ void
linux_bt_close( CommonGlobals* globals ) linux_bt_close( CommonGlobals* globals )
{ {
LinBtStuff* btStuff = globals->btStuff; LinBtStuff* btStuff = globals->btStuff;
XP_U16 i;
if ( !!btStuff ) { if ( !!btStuff ) {
if ( btStuff->amMaster ) { if ( btStuff->amMaster ) {
@ -459,18 +395,17 @@ linux_bt_close( CommonGlobals* globals )
close( btStuff->u.master.listener ); close( btStuff->u.master.listener );
btStuff->u.master.listener = -1; btStuff->u.master.listener = -1;
for ( i = 0; i < MAX_CLIENTS; ++i ) {
BtaddrSockMap* mp = &btStuff->u.master.socks[i];
if ( mp->sock != -1 ) {
XP_LOGF( "%s: closing data socket %d", __func__, mp->sock );
(void)close( mp->sock );
}
}
sdp_close( btStuff->u.master.session ); sdp_close( btStuff->u.master.session );
XP_LOGF( "sleeping for Palm's sake..." ); XP_LOGF( "sleeping for Palm's sake..." );
sleep( 2 ); /* see if this gives palm a chance to not hang */ sleep( 2 ); /* see if this gives palm a chance to not hang */
} }
if ( btStuff->socket != -1 ) {
(*globals->socketChanged)( globals->socketChangedClosure,
btStuff->socket, -1, &btStuff->sockStorage );
(void)close( btStuff->socket );
}
XP_FREE( globals->params->util->mpool, btStuff ); XP_FREE( globals->params->util->mpool, btStuff );
globals->btStuff = NULL; globals->btStuff = NULL;
} }
@ -495,17 +430,17 @@ linux_bt_send( const XP_U8* buf, XP_U16 buflen,
addrP = &addr; addrP = &addr;
} }
if ( globals->socket < 0 && !btStuff->amMaster ) { if ( btStuff->socket < 0 && !btStuff->amMaster ) {
lbt_connectSocket( btStuff, addrP ); lbt_connectSocket( btStuff, addrP );
} }
if ( globals->socket >= 0 ) { if ( btStuff->socket >= 0 ) {
#if defined BT_USE_RFCOMM #if defined BT_USE_RFCOMM
unsigned short len = htons(buflen); unsigned short len = htons(buflen);
nSent = write( globals->socket, &len, sizeof(len) ); nSent = write( btStuff->socket, &len, sizeof(len) );
assert( nSent == sizeof(len) ); assert( nSent == sizeof(len) );
#endif #endif
nSent = write( globals->socket, buf, buflen ); nSent = write( btStuff->socket, buf, buflen );
if ( nSent < 0 ) { if ( nSent < 0 ) {
XP_LOGF( "%s: send->%s", __FUNCTION__, strerror(errno) ); XP_LOGF( "%s: send->%s", __FUNCTION__, strerror(errno) );
} else if ( nSent < buflen ) { } else if ( nSent < buflen ) {
@ -569,10 +504,9 @@ void
linux_bt_socketclosed( CommonGlobals* globals, int sock ) linux_bt_socketclosed( CommonGlobals* globals, int sock )
{ {
LinBtStuff* btStuff = globals->btStuff; LinBtStuff* btStuff = globals->btStuff;
if ( btStuff->amMaster ) { LOG_FUNC();
lbt_removeSock( btStuff, sock ); XP_ASSERT( sock == btStuff->socket );
} btStuff->socket = -1;
} }
#endif /* XWFEATURE_BLUETOOTH */ #endif /* XWFEATURE_BLUETOOTH */

View file

@ -42,6 +42,7 @@
#include "linuxmain.h" #include "linuxmain.h"
#include "linuxbt.h" #include "linuxbt.h"
#include "linuxudp.h"
#include "main.h" #include "main.h"
#ifdef PLATFORM_NCURSES #ifdef PLATFORM_NCURSES
# include "cursesmain.h" # include "cursesmain.h"
@ -57,7 +58,7 @@
#include "memstream.h" #include "memstream.h"
#include "LocalizedStrIncludes.h" #include "LocalizedStrIncludes.h"
#define DEFAULT_SEND_PORT 10999 #define DEFAULT_PORT 10999
#define DEFAULT_LISTEN_PORT 4998 #define DEFAULT_LISTEN_PORT 4998
#ifdef DEBUG #ifdef DEBUG
@ -266,24 +267,30 @@ usage( char* appName, char* msg )
"\t [-B n:name|a:00:11:22:33:44:55]\n" "\t [-B n:name|a:00:11:22:33:44:55]\n"
"\t\t\t# connect via bluetooth [param ignored if -s]\n" "\t\t\t# connect via bluetooth [param ignored if -s]\n"
#endif #endif
#ifdef XWFEATURE_IP_DIRECT
"\t [-D host_addr]\t\t\tConnect directly to host [param ignored if -s]\n"
"\t [-p host_port] # put/look for host on this port\n"
#endif
/* "# --------------- OR client-only ----------\n" */ /* "# --------------- OR client-only ----------\n" */
/* "\t [-p client_port] # must != server's port if on same device" */ /* "\t [-p client_port] # must != server's port if on same device" */
"\nexample: \n"
"\tserver: ./xwords -d dict.xwd -s -r Eric -N"
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
" -a localhost -p 10999" "\nrelay example: \n"
"\t host: ./xwords -d dict.xwd -r Eric -s -N -a localhost -p 10999 -C COOKIE\n"
"\tguest: ./xwords -d dict.xwd -r Kati -a localhost -p 10999 -C COOKIE"
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
" -B ignored " "\nBluetooth example: \n"
"\t host: ./xwords -d dict.xwd -r Eric -s -N -B ignored\n"
"\tguest: ./xwords -d dict.xwd -r Kati -B n:treo_bt_name (OR b:11:22:33:44:55:66)"
#endif #endif
"\n" #ifdef XWFEATURE_IP_DIRECT
"\tclient: ./xwords -d dict.xwd -r Kati" "\nDirect example: \n"
#ifdef XWFEATURE_RELAY "\t host: ./xwords -d dict.xwd -r Eric -s -N -N -D localhost -p 10999\n"
" -a localhost -p 10999" "\tguest: ./xwords -d dict.xwd -r Kati -D localhost -p 10999\n"
#endif "\tguest: ./xwords -d dict.xwd -r Ariynn -D localhost -p 10999"
#ifdef XWFEATURE_BLUETOOTH
" -B a:11:22:33:44:55:66 | n:my_treo "
#endif #endif
"\n" "\n"
, appName ); , appName );
fprintf( stderr, "\n(revision: %s)\n", SVN_REV); fprintf( stderr, "\n(revision: %s)\n", SVN_REV);
@ -394,7 +401,8 @@ linux_tcp_send( const XP_U8* buf, XP_U16 buflen,
if ( socket != -1 ) { if ( socket != -1 ) {
assert( globals->socket == socket ); assert( globals->socket == socket );
(*globals->socketChanged)( globals->socketChangedClosure, (*globals->socketChanged)( globals->socketChangedClosure,
-1, socket ); -1, socket,
&globals->storage );
} }
} }
@ -410,7 +418,7 @@ linux_tcp_send( const XP_U8* buf, XP_U16 buflen,
XP_STATUSF( "closing non-functional socket" ); XP_STATUSF( "closing non-functional socket" );
close( socket ); close( socket );
(*globals->socketChanged)( globals->socketChangedClosure, (*globals->socketChanged)( globals->socketChangedClosure,
socket, -1 ); socket, -1, &globals->storage );
globals->socket = -1; globals->socket = -1;
} }
@ -420,7 +428,17 @@ linux_tcp_send( const XP_U8* buf, XP_U16 buflen,
return result; return result;
} /* linux_tcp_send */ } /* linux_tcp_send */
#endif
static void
linux_tcp_reset( CommonGlobals* globals )
{
LOG_FUNC();
if ( globals->socket != -1 ) {
(void)close( globals->socket );
globals->socket = -1;
}
}
#endif /* XWFEATURE_RELAY */
#ifdef COMMS_HEARTBEAT #ifdef COMMS_HEARTBEAT
void void
@ -432,6 +450,14 @@ linux_reset( void* closure )
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
} else if ( conType == COMMS_CONN_BT ) { } else if ( conType == COMMS_CONN_BT ) {
linux_bt_reset( globals ); linux_bt_reset( globals );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( conType == COMMS_CONN_IP_DIRECT ) {
linux_udp_reset( globals );
#endif
#ifdef XWFEATURE_RELAY
} else if ( conType == COMMS_CONN_RELAY ) {
linux_tcp_reset( globals );
#endif #endif
} }
@ -458,11 +484,18 @@ linux_send( const XP_U8* buf, XP_U16 buflen,
} else if ( conType == COMMS_CONN_RELAY ) { } else if ( conType == COMMS_CONN_RELAY ) {
nSent = linux_tcp_send( buf, buflen, addrRec, globals ); nSent = linux_tcp_send( buf, buflen, addrRec, globals );
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #if defined XWFEATURE_BLUETOOTH
} else if ( conType == COMMS_CONN_BT ) { } else if ( conType == COMMS_CONN_BT ) {
XP_Bool isServer = comms_getIsServer( globals->game.comms ); XP_Bool isServer = comms_getIsServer( globals->game.comms );
linux_bt_open( globals, isServer ); linux_bt_open( globals, isServer );
nSent = linux_bt_send( buf, buflen, addrRec, globals ); nSent = linux_bt_send( buf, buflen, addrRec, globals );
#endif
#if defined XWFEATURE_IP_DIRECT
} else if ( conType == COMMS_CONN_IP_DIRECT ) {
CommsAddrRec addr;
comms_getAddr( globals->game.comms, &addr );
linux_udp_open( globals, &addr );
nSent = linux_udp_send( buf, buflen, addrRec, globals );
#endif #endif
} else { } else {
XP_ASSERT(0); XP_ASSERT(0);
@ -470,6 +503,7 @@ linux_send( const XP_U8* buf, XP_U16 buflen,
return nSent; return nSent;
} /* linux_send */ } /* linux_send */
#ifdef XWFEATURE_RELAY
static void static void
linux_close_socket( CommonGlobals* cGlobals ) linux_close_socket( CommonGlobals* cGlobals )
{ {
@ -502,6 +536,7 @@ linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize )
} }
return nRead; return nRead;
} /* linuxReceive */ } /* linuxReceive */
#endif
/* Create a stream for the incoming message buffer, and read in any /* Create a stream for the incoming message buffer, and read in any
information specific to our platform's comms layer (return address, say) information specific to our platform's comms layer (return address, say)
@ -684,9 +719,9 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code )
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_RELAY #if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_RELAY
static void static void
linux_util_addrChange( XW_UtilCtxt* XP_UNUSED_BT(uc), linux_util_addrChange( XW_UtilCtxt* uc,
const CommsAddrRec* XP_UNUSED(oldAddr), const CommsAddrRec* XP_UNUSED(oldAddr),
const CommsAddrRec* XP_UNUSED_BT(newAddr) ) const CommsAddrRec* newAddr )
{ {
if ( 0 ) { if ( 0 ) {
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
@ -694,6 +729,11 @@ linux_util_addrChange( XW_UtilCtxt* XP_UNUSED_BT(uc),
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
XP_Bool isServer = comms_getIsServer( cGlobals->game.comms ); XP_Bool isServer = comms_getIsServer( cGlobals->game.comms );
linux_bt_open( cGlobals, isServer ); linux_bt_open( cGlobals, isServer );
#endif
#if defined XWFEATURE_IP_DIRECT
} else if ( newAddr->conType == COMMS_CONN_IP_DIRECT ) {
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
linux_udp_open( cGlobals, newAddr );
#endif #endif
} }
} }
@ -757,8 +797,8 @@ main( int argc, char** argv )
int opt; int opt;
int totalPlayerCount = 0; int totalPlayerCount = 0;
XP_Bool isServer = XP_FALSE; XP_Bool isServer = XP_FALSE;
char* sendPortNumString = NULL; char* portNum = "10999";
char* relayName = "localhost"; char* hostName = "localhost";
unsigned int seed = defaultRandomSeed(); unsigned int seed = defaultRandomSeed();
LaunchParams mainParams; LaunchParams mainParams;
XP_U16 robotCount = 0; XP_U16 robotCount = 0;
@ -798,9 +838,12 @@ main( int argc, char** argv )
/* defaults */ /* defaults */
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
mainParams.connInfo.relay.defaultListenPort = DEFAULT_LISTEN_PORT; mainParams.connInfo.relay.defaultSendPort = DEFAULT_PORT;
mainParams.connInfo.relay.defaultSendPort = DEFAULT_SEND_PORT;
mainParams.connInfo.relay.cookie = "COOKIE"; mainParams.connInfo.relay.cookie = "COOKIE";
#endif
#ifdef XWFEATURE_IP_DIRECT
mainParams.connInfo.ip.port = DEFAULT_PORT;
mainParams.connInfo.ip.hostName = "localhost";
#endif #endif
mainParams.gi.boardSize = 15; mainParams.gi.boardSize = 15;
mainParams.quitAfter = XP_FALSE; mainParams.quitAfter = XP_FALSE;
@ -837,8 +880,14 @@ main( int argc, char** argv )
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
"a:p:C:H" "a:p:C:H"
#endif #endif
#if defined XWFEATURE_RELAY || defined XWFEATURE_IP_DIRECT
"p:"
#endif
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
"B:" "B:"
#endif
#ifdef XWFEATURE_IP_DIRECT
"D:"
#endif #endif
); );
switch( opt ) { switch( opt ) {
@ -856,6 +905,12 @@ main( int argc, char** argv )
conType = COMMS_CONN_RELAY; conType = COMMS_CONN_RELAY;
break; break;
#endif #endif
case 'D':
XP_ASSERT( conType == COMMS_CONN_UNUSED ||
conType == COMMS_CONN_IP_DIRECT );
hostName = optarg;
conType = COMMS_CONN_IP_DIRECT;
break;
case 'd': case 'd':
mainParams.gi.dictName = copyString( mainParams.util->mpool, mainParams.gi.dictName = copyString( mainParams.util->mpool,
(XP_UCHAR*)optarg ); (XP_UCHAR*)optarg );
@ -893,10 +948,8 @@ main( int argc, char** argv )
++mainParams.info.serverInfo.nRemotePlayers; ++mainParams.info.serverInfo.nRemotePlayers;
break; break;
case 'p': case 'p':
sendPortNumString = optarg; /* could be RELAY or IP_DIRECT */
XP_ASSERT( conType == COMMS_CONN_UNUSED || portNum = optarg;
conType == COMMS_CONN_RELAY );
conType = COMMS_CONN_RELAY;
break; break;
case 'r': case 'r':
++robotCount; ++robotCount;
@ -928,7 +981,7 @@ main( int argc, char** argv )
XP_ASSERT( conType == COMMS_CONN_UNUSED || XP_ASSERT( conType == COMMS_CONN_UNUSED ||
conType == COMMS_CONN_RELAY ); conType == COMMS_CONN_RELAY );
conType = COMMS_CONN_RELAY; conType = COMMS_CONN_RELAY;
relayName = optarg; hostName = optarg;
break; break;
case 'q': case 'q':
mainParams.quitAfter = XP_TRUE; mainParams.quitAfter = XP_TRUE;
@ -1015,12 +1068,19 @@ main( int argc, char** argv )
if ( 0 ) { if ( 0 ) {
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
} else if ( conType == COMMS_CONN_RELAY ) { } else if ( conType == COMMS_CONN_RELAY ) {
mainParams.connInfo.relay.relayName = relayName; mainParams.connInfo.relay.relayName = hostName;
/* convert strings to whatever */ /* convert strings to whatever */
if ( sendPortNumString != NULL ) { if ( portNum != NULL ) {
mainParams.connInfo.relay.defaultSendPort = mainParams.connInfo.relay.defaultSendPort =
atoi( sendPortNumString ); atoi( portNum );
}
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( conType == COMMS_CONN_IP_DIRECT ) {
mainParams.connInfo.ip.hostName = hostName;
if ( portNum != NULL ) {
mainParams.connInfo.ip.port = atoi( portNum );
} }
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH

View file

@ -65,19 +65,24 @@ typedef struct LaunchParams {
DeviceRole serverRole; DeviceRole serverRole;
CommsConnType conType; CommsConnType conType;
union { struct {
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
struct { struct {
char* relayName; char* relayName;
char* cookie; char* cookie;
short defaultSendPort; short defaultSendPort;
short defaultListenPort;
} relay; } relay;
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
struct { struct {
bdaddr_t hostAddr; /* unused if a host */ bdaddr_t hostAddr; /* unused if a host */
} bt; } bt;
#endif
#ifdef XWFEATURE_IP_DIRECT
struct {
const char* hostName;
int port;
} ip;
#endif #endif
} connInfo; } connInfo;
@ -90,7 +95,8 @@ typedef struct LaunchParams {
typedef struct CommonGlobals CommonGlobals; typedef struct CommonGlobals CommonGlobals;
typedef void (*SocketChangedFunc)(void* closure, int oldsock, int newsock ); typedef void (*SocketChangedFunc)(void* closure, int oldsock, int newsock,
void** storage );
typedef XP_Bool (*Acceptor)( int sock, void* ctxt ); typedef XP_Bool (*Acceptor)( int sock, void* ctxt );
typedef void (*AddAcceptorFunc)(int listener, Acceptor func, typedef void (*AddAcceptorFunc)(int listener, Acceptor func,
CommonGlobals* globals ); CommonGlobals* globals );
@ -109,13 +115,18 @@ struct CommonGlobals {
AddAcceptorFunc addAcceptor; AddAcceptorFunc addAcceptor;
Acceptor acceptor; Acceptor acceptor;
int socket; /* either relay or bt */ #ifdef XWFEATURE_RELAY
int socket; /* relay */
/* Used only for relay case */ void* storage;
char* defaultServerName; char* defaultServerName;
#endif
/* Used only for bluetooth case */ #if defined XWFEATURE_BLUETOOTH
struct LinBtStuff* btStuff; struct LinBtStuff* btStuff;
#endif
#if defined XWFEATURE_IP_DIRECT
struct LinUDPStuff* udpStuff;
#endif
XWTimerProc timerProcs[NUM_TIMERS_PLUS_ONE]; XWTimerProc timerProcs[NUM_TIMERS_PLUS_ONE];
void* timerClosures[NUM_TIMERS_PLUS_ONE]; void* timerClosures[NUM_TIMERS_PLUS_ONE];