mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-14 08:01:38 +01:00
Add and set a compile-time option so comms will set a periodic timer
and use it to send and check for heartbeats over any transport. Caller must supply a reset proc which is called when heartbeat hasn't been received in too long. No changes required to comms protocol, but that means the heartbeat interval is fixed at compile time: can't be negotiated, and the two ends had better agree. Currently tested with linux host and PalmOS guest, where only the first heartbeat failure is recovered from. So there's some debugging to be done still.
This commit is contained in:
parent
a91056bed2
commit
321acd1d42
17 changed files with 356 additions and 72 deletions
184
common/comms.c
184
common/comms.c
|
@ -35,6 +35,17 @@
|
|||
|
||||
#ifndef XWFEATURE_STANDALONE_ONLY
|
||||
|
||||
#if defined RELAY_HEARTBEAT && defined COMMS_HEARTBEAT
|
||||
compilation_error_here( "Choose one or the other or none." );
|
||||
#endif
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
/* It might make sense for this to be a parameter or somehow tied to the
|
||||
platform and transport. But in that case it'd have to be passed across
|
||||
since all devices must agree. */
|
||||
# define HB_INTERVAL 5
|
||||
#endif
|
||||
|
||||
EXTERN_C_START
|
||||
|
||||
typedef struct MsgQueueElem {
|
||||
|
@ -54,6 +65,8 @@ typedef struct AddressRecord {
|
|||
#endif
|
||||
MsgID nextMsgID; /* on a per-channel basis */
|
||||
MsgID lastMsgReceived; /* on a per-channel basis */
|
||||
/* only used if COMMS_HEARTBEAT set except for serialization (to_stream) */
|
||||
XP_U32 lastMsgRcvdTime; /* when did we set lastMsgReceived? */
|
||||
XP_PlayerAddr channelNo;
|
||||
struct {
|
||||
XWHostID hostID; /* used for relay case */
|
||||
|
@ -78,12 +91,19 @@ struct CommsCtxt {
|
|||
AddressRecord* recs; /* return addresses */
|
||||
|
||||
TransportSend sendproc;
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
TransportReset resetproc;
|
||||
#endif
|
||||
void* sendClosure;
|
||||
|
||||
MsgQueueElem* msgQueueHead;
|
||||
MsgQueueElem* msgQueueTail;
|
||||
XP_U16 queueLen;
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
XP_Bool doHeartbeat;
|
||||
#endif
|
||||
|
||||
/* 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.*/
|
||||
|
@ -143,6 +163,8 @@ static void relayDisconnect( CommsCtxt* comms );
|
|||
static XP_Bool send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd,
|
||||
XWHostID destID, void* data, int dlen );
|
||||
static XWHostID getDestID( CommsCtxt* comms, XP_PlayerAddr channelNo );
|
||||
#endif
|
||||
#if defined XWFEATURE_RELAY || defined COMMS_HEARTBEAT
|
||||
static void setHeartbeatTimer( CommsCtxt* comms );
|
||||
#endif
|
||||
#ifdef XWFEATURE_BLUETOOTH
|
||||
|
@ -159,7 +181,8 @@ CommsCtxt*
|
|||
comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
|
||||
XP_U16 XP_UNUSED_RELAY(nPlayersHere),
|
||||
XP_U16 XP_UNUSED_RELAY(nPlayersTotal),
|
||||
TransportSend sendproc, void* closure )
|
||||
TransportSend sendproc, IF_CH(TransportReset resetproc)
|
||||
void* closure )
|
||||
{
|
||||
CommsCtxt* result = (CommsCtxt*)XP_MALLOC( mpool, sizeof(*result) );
|
||||
XP_MEMSET( result, 0, sizeof(*result) );
|
||||
|
@ -168,6 +191,9 @@ comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
|
|||
|
||||
result->isServer = isServer;
|
||||
result->sendproc = sendproc;
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
result->resetproc = resetproc;
|
||||
#endif
|
||||
result->sendClosure = closure;
|
||||
result->util = util;
|
||||
|
||||
|
@ -297,7 +323,8 @@ addrFromStream( CommsAddrRec* addrP, XWStreamCtxt* stream )
|
|||
|
||||
CommsCtxt*
|
||||
comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
|
||||
TransportSend sendproc, void* closure )
|
||||
TransportSend sendproc,
|
||||
IF_CH(TransportReset resetproc ) void* closure )
|
||||
{
|
||||
CommsCtxt* comms;
|
||||
XP_Bool isServer;
|
||||
|
@ -325,7 +352,7 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
|
|||
}
|
||||
comms = comms_make( MPPARM(mpool) util, isServer,
|
||||
nPlayersHere, nPlayersTotal,
|
||||
sendproc, closure );
|
||||
sendproc, IF_CH(resetproc) closure );
|
||||
XP_MEMCPY( &comms->addr, &addr, sizeof(comms->addr) );
|
||||
|
||||
comms->connID = stream_getU32( stream );
|
||||
|
@ -403,6 +430,10 @@ comms_start( CommsCtxt* comms )
|
|||
btConnect( comms );
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR;
|
||||
#endif
|
||||
} /* comms_start */
|
||||
|
||||
static void
|
||||
|
@ -531,6 +562,9 @@ comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr )
|
|||
btConnect( comms );
|
||||
#endif
|
||||
}
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
comms->doHeartbeat = comms->addr.conType != COMMS_CONN_IR;
|
||||
#endif
|
||||
} /* comms_setAddr */
|
||||
|
||||
void
|
||||
|
@ -567,22 +601,16 @@ comms_getIsServer( const CommsCtxt* comms )
|
|||
return comms->isServer;
|
||||
}
|
||||
|
||||
/* Send a message using the sequentially next MsgID. Save the message so
|
||||
* resend can work. */
|
||||
XP_S16
|
||||
comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
|
||||
static XP_S16
|
||||
sendWithID( CommsCtxt* comms, MsgID msgID, AddressRecord* rec,
|
||||
XP_PlayerAddr channelNo, XWStreamCtxt* stream )
|
||||
{
|
||||
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;
|
||||
XP_U16 streamSize = NULL == stream? 0 : stream_getSize( stream );
|
||||
MsgID lastMsgRcd = (!!rec)? rec->lastMsgReceived : 0;
|
||||
MsgQueueElem* newMsgElem;
|
||||
XWStreamCtxt* msgStream;
|
||||
|
||||
XP_DEBUGF( "assigning msgID=" XP_LD " on chnl %d", msgID, channelNo );
|
||||
|
||||
#ifdef DEBUG
|
||||
if ( !!rec ) {
|
||||
rec->nUniqueBytes += streamSize;
|
||||
|
@ -614,11 +642,26 @@ comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
stream_getBytes( msgStream, newMsgElem->msg, headerLen );
|
||||
stream_destroy( msgStream );
|
||||
|
||||
stream_getBytes( stream, newMsgElem->msg + headerLen, streamSize );
|
||||
if ( 0 < streamSize ) {
|
||||
stream_getBytes( stream, newMsgElem->msg + headerLen, streamSize );
|
||||
}
|
||||
|
||||
addToQueue( comms, newMsgElem );
|
||||
|
||||
return sendMsg( comms, newMsgElem );
|
||||
} /* sendWithID */
|
||||
|
||||
/* Send a message using the sequentially next MsgID. Save the message so
|
||||
* resend can work. */
|
||||
XP_S16
|
||||
comms_send( CommsCtxt* comms, XWStreamCtxt* stream )
|
||||
{
|
||||
XP_PlayerAddr channelNo = stream_getAddress( stream );
|
||||
AddressRecord* rec = getRecordFor( comms, channelNo );
|
||||
MsgID msgID = (!!rec)? ++rec->nextMsgID : 0;
|
||||
|
||||
XP_DEBUGF( "assigning msgID=" XP_LD " on chnl %d", msgID, channelNo );
|
||||
return sendWithID( comms, msgID, rec, channelNo, stream );
|
||||
} /* comms_send */
|
||||
|
||||
/* Add new message to the end of the list. The list needs to be kept in order
|
||||
|
@ -1013,6 +1056,11 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
* greater than the id most recently used for that
|
||||
* channel. */
|
||||
if ( !!recs ) {
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
/* Good for heartbeat even if not "valid." In
|
||||
fact, all HB messages are invalid by design. */
|
||||
recs->lastMsgRcvdTime = util_getCurSeconds( comms->util );
|
||||
#endif
|
||||
if ( msgID != recs->lastMsgReceived + 1 ) {
|
||||
XP_DEBUGF( "on channel %d, msgID=" XP_LD
|
||||
" (next should be " XP_LD ")",
|
||||
|
@ -1047,9 +1095,9 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
|
||||
if ( !!recs ) {
|
||||
recs->lastMsgReceived = msgID;
|
||||
XP_STATUSF( "set channel %d's lastMsgReceived to "
|
||||
XP_LD, channelNo, msgID );
|
||||
}
|
||||
XP_STATUSF( "set channel %d's lastMsgReceived to "
|
||||
XP_LD, channelNo, msgID );
|
||||
}
|
||||
} else {
|
||||
XP_LOGF( "%s: message too small", __FUNCTION__ );
|
||||
|
@ -1066,25 +1114,103 @@ comms_checkIncomingStream( CommsCtxt* comms, XWStreamCtxt* stream,
|
|||
return validMessage;
|
||||
} /* comms_checkIncomingStream */
|
||||
|
||||
#ifdef XWFEATURE_RELAY
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
/* Heartbeat.
|
||||
*
|
||||
* Goal is to allow all participants to detect when another is gone quickly.
|
||||
* Assumption is that transport is cheap: sending extra packets doesn't cost
|
||||
* much money or bother (meaning: don't do this over IR! :-).
|
||||
*
|
||||
* Keep track of last time we heard from each channel and of when we last sent
|
||||
* a packet. Run a timer, and when it fires: 1) check if we haven't heard
|
||||
* since 2x the timer interval. If so, call alert function and reset the
|
||||
* underlying (ip, bt) channel. If not, check how long since we last sent a
|
||||
* packet on each channel. If it's been longer than since the last timer, and
|
||||
* if there are not already packets in the queue on that channel, fire a HB
|
||||
* packet.
|
||||
*
|
||||
* A HB packet is one whose msg ID is lower than the most recent ACK'd so that
|
||||
* it's sure to be dropped on the other end and not to interfere with packets
|
||||
* that might be resent.
|
||||
*/
|
||||
static void
|
||||
heartbeat_checks( CommsCtxt* comms )
|
||||
{
|
||||
XP_U32 now, tooLongAgo;
|
||||
XP_U16 pendingPacks[MAX_NUM_PLAYERS] = { 0 };
|
||||
AddressRecord* rec;
|
||||
const MsgQueueElem* elem;
|
||||
XP_Bool resetTimer = XP_FALSE;
|
||||
|
||||
LOG_FUNC();
|
||||
|
||||
for ( elem = comms->msgQueueHead; !!elem; elem = elem->next ) {
|
||||
XP_ASSERT( elem->channelNo < MAX_NUM_PLAYERS );
|
||||
++pendingPacks[elem->channelNo];
|
||||
}
|
||||
|
||||
now = util_getCurSeconds( comms->util );
|
||||
tooLongAgo = now - (HB_INTERVAL * 2);
|
||||
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
||||
XP_U32 lastMsgRcvdTime = rec->lastMsgRcvdTime;
|
||||
if ( lastMsgRcvdTime == 0 ) { /* nothing received yet */
|
||||
/* do nothing; or should we send? */
|
||||
} else if ( (lastMsgRcvdTime > 0) && (lastMsgRcvdTime < tooLongAgo) ) {
|
||||
XP_LOGF( "calling reset proc" );
|
||||
(*comms->resetproc)(comms->sendClosure);
|
||||
resetTimer = XP_FALSE;
|
||||
break;
|
||||
} else if ( 0 == pendingPacks[rec->channelNo] ) {
|
||||
XP_LOGF( "sending heartbeat on channel %d", rec->channelNo );
|
||||
sendWithID( comms, rec->lastMsgReceived, rec, rec->channelNo, NULL );
|
||||
} else {
|
||||
XP_LOGF( "All's well" );
|
||||
resetTimer = XP_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if ( resetTimer ) {
|
||||
setHeartbeatTimer( comms );
|
||||
}
|
||||
} /* heartbeat_checks */
|
||||
#endif
|
||||
|
||||
#if defined RELAY_HEARTBEAT || defined COMMS_HEARTBEAT
|
||||
static void
|
||||
p_comms_timerFired( void* closure, XWTimerReason XP_UNUSED_DBG(why) )
|
||||
{
|
||||
CommsCtxt* comms = (CommsCtxt*)closure;
|
||||
XP_ASSERT( why == TIMER_HEARTBEAT );
|
||||
XP_LOGF( "comms_timerFired" );
|
||||
if ( comms->r.heartbeat != HEARTBEAT_NONE ) {
|
||||
if (0 ) {
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
} else if ( (comms->addr.conType == COMMS_CONN_RELAY )
|
||||
&& (comms->r.heartbeat != HEARTBEAT_NONE) ) {
|
||||
send_via_relay( comms, XWRELAY_HEARTBEAT, HOST_ID_NONE, NULL, 0 );
|
||||
/* No need to reset timer. send_via_relay does that. */
|
||||
#elif defined COMMS_HEARTBEAT
|
||||
} else {
|
||||
XP_ASSERT( comms->doHeartbeat );
|
||||
heartbeat_checks( comms );
|
||||
#endif
|
||||
}
|
||||
} /* comms_timerFired */
|
||||
} /* p_comms_timerFired */
|
||||
|
||||
static void
|
||||
setHeartbeatTimer( CommsCtxt* comms )
|
||||
{
|
||||
util_setTimer( comms->util, TIMER_HEARTBEAT, comms->r.heartbeat,
|
||||
p_comms_timerFired, comms );
|
||||
}
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
if ( comms->addr.conType == COMMS_CONN_RELAY ) {
|
||||
util_setTimer( comms->util, TIMER_HEARTBEAT, comms->r.heartbeat,
|
||||
p_comms_timerFired, comms );
|
||||
}
|
||||
#elif defined COMMS_HEARTBEAT
|
||||
if ( comms->doHeartbeat ) {
|
||||
util_setTimer( comms->util, TIMER_HEARTBEAT, HB_INTERVAL,
|
||||
p_comms_timerFired, comms );
|
||||
}
|
||||
#endif
|
||||
} /* setHeartbeatTimer */
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
|
@ -1094,6 +1220,7 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
XP_UCHAR buf[100];
|
||||
AddressRecord* rec;
|
||||
MsgQueueElem* elem;
|
||||
XP_U32 now;
|
||||
|
||||
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
||||
(XP_UCHAR*)"msg queue len: %d\n", comms->queueLen );
|
||||
|
@ -1111,6 +1238,7 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
comms->nUniqueBytes );
|
||||
stream_putString( stream, buf );
|
||||
|
||||
now = util_getCurSeconds( comms->util );
|
||||
for ( rec = comms->recs; !!rec; rec = rec->next ) {
|
||||
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
||||
(XP_UCHAR*)" Stats for channel: %d\n",
|
||||
|
@ -1131,6 +1259,13 @@ comms_getStats( CommsCtxt* comms, XWStreamCtxt* stream )
|
|||
(XP_UCHAR*)"Last message acknowledged: %d\n",
|
||||
rec->lastACK);
|
||||
stream_putString( stream, buf );
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
XP_SNPRINTF( (XP_UCHAR*)buf, sizeof(buf),
|
||||
(XP_UCHAR*)"Last ack'd %ld secs ago\n",
|
||||
now - rec->lastMsgRcvdTime );
|
||||
stream_putString( stream, buf );
|
||||
#endif
|
||||
}
|
||||
} /* comms_getStats */
|
||||
#endif
|
||||
|
@ -1277,13 +1412,14 @@ send_via_relay( CommsCtxt* comms, XWRELAY_Cmd cmd, XWHostID destID,
|
|||
stream_putU8( tmpStream, comms->r.myHostID );
|
||||
break;
|
||||
|
||||
#ifdef RELAY_HEARTBEAT
|
||||
case XWRELAY_HEARTBEAT:
|
||||
/* Add these for grins. Server can assert they match the IP
|
||||
address it expects 'em on. */
|
||||
stream_putU16( tmpStream, comms->r.cookieID );
|
||||
stream_putU8( tmpStream, comms->r.myHostID );
|
||||
break;
|
||||
|
||||
#endif
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
}
|
||||
|
@ -1359,6 +1495,8 @@ send_via_bt( CommsCtxt* comms, BTMsgType typ, XP_PlayerAddr channelNo,
|
|||
|
||||
nSent = (*comms->sendproc)( buf, dlen+1, addr, comms->sendClosure );
|
||||
XP_FREE( comms->mpool, buf );
|
||||
|
||||
setHeartbeatTimer( comms );
|
||||
}
|
||||
return nSent;
|
||||
} /* send_via_bt */
|
||||
|
|
|
@ -54,6 +54,12 @@ typedef enum {
|
|||
typedef struct XP_BtAddr { XP_U8 bits[6]; } XP_BtAddr;
|
||||
typedef struct XP_BtAddrStr { XP_UCHAR chars[18]; } XP_BtAddrStr;
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
# define IF_CH(a) a,
|
||||
#else
|
||||
# define IF_CH(a)
|
||||
#endif
|
||||
|
||||
#define MAX_HOSTNAME_LEN 63
|
||||
typedef struct CommsAddrRec {
|
||||
CommsConnType conType;
|
||||
|
@ -85,11 +91,13 @@ typedef struct CommsAddrRec {
|
|||
typedef XP_S16 (*TransportSend)( const XP_U8* buf, XP_U16 len,
|
||||
const CommsAddrRec* addr,
|
||||
void* closure );
|
||||
typedef void (*TransportReset)( void* closure );
|
||||
|
||||
CommsCtxt* comms_make( MPFORMAL XW_UtilCtxt* util,
|
||||
XP_Bool isServer,
|
||||
XP_U16 nPlayersHere, XP_U16 nPlayersTotal,
|
||||
TransportSend sendproc, void* closure );
|
||||
TransportSend sendproc, IF_CH(TransportReset resetproc)
|
||||
void* closure );
|
||||
|
||||
void comms_reset( CommsCtxt* comms, XP_Bool isServer,
|
||||
XP_U16 nPlayersHere, XP_U16 nPlayersTotal );
|
||||
|
@ -107,6 +115,7 @@ XP_Bool comms_getIsServer( const CommsCtxt* comms );
|
|||
|
||||
CommsCtxt* comms_makeFromStream( MPFORMAL XWStreamCtxt* stream,
|
||||
XW_UtilCtxt* util, TransportSend sendproc,
|
||||
IF_CH(TransportReset resetproc)
|
||||
void* closure );
|
||||
void comms_start( CommsCtxt* comms );
|
||||
void comms_writeToStream( const CommsCtxt* comms, XWStreamCtxt* stream );
|
||||
|
|
|
@ -103,7 +103,7 @@ typedef XP_U16 XP_PlayerAddr;
|
|||
typedef enum {
|
||||
TIMER_PENDOWN = 1, /* ARM doesn't like ids of 0... */
|
||||
TIMER_TIMERTICK,
|
||||
#ifdef XWFEATURE_RELAY
|
||||
#if defined RELAY_HEARTBEAT || defined COMMS_HEARTBEAT
|
||||
TIMER_HEARTBEAT,
|
||||
#endif
|
||||
|
||||
|
|
|
@ -73,7 +73,8 @@ void
|
|||
game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||
XW_UtilCtxt* util, DrawCtx* draw,
|
||||
XP_U16 gameID, CommonPrefs* cp,
|
||||
TransportSend sendproc, void* closure )
|
||||
TransportSend sendproc, IF_CH( TransportReset resetproc )
|
||||
void* closure )
|
||||
{
|
||||
XP_U16 nPlayersHere, nPlayersTotal;
|
||||
|
||||
|
@ -90,7 +91,7 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
|||
game->comms = comms_make( MPPARM(mpool) util,
|
||||
gi->serverRole != SERVER_ISCLIENT,
|
||||
nPlayersHere, nPlayersTotal,
|
||||
sendproc, closure );
|
||||
sendproc, IF_CH(resetproc) closure );
|
||||
} else {
|
||||
game->comms = (CommsCtxt*)NULL;
|
||||
}
|
||||
|
@ -112,7 +113,7 @@ game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
|||
void
|
||||
game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
|
||||
XP_U16 gameID, CommonPrefs* cp, TransportSend sendproc,
|
||||
void* closure )
|
||||
IF_CH(TransportReset resetproc) void* closure )
|
||||
{
|
||||
XP_U16 i;
|
||||
XP_U16 nPlayersHere, nPlayersTotal;
|
||||
|
@ -136,7 +137,7 @@ game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
|
|||
game->comms = comms_make( MPPARM(mpool) util,
|
||||
gi->serverRole != SERVER_ISCLIENT,
|
||||
nPlayersHere, nPlayersTotal,
|
||||
sendproc, closure );
|
||||
sendproc, IF_CH(resetproc) closure );
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -162,7 +163,8 @@ XP_Bool
|
|||
game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
|
||||
CurGameInfo* gi, DictionaryCtxt* dict,
|
||||
XW_UtilCtxt* util, DrawCtx* draw, CommonPrefs* cp,
|
||||
TransportSend sendProc, void* closure )
|
||||
TransportSend sendProc, IF_CH(TransportReset resetProc)
|
||||
void* closure )
|
||||
{
|
||||
XP_Bool success = XP_FALSE;
|
||||
XP_U8 strVersion;
|
||||
|
@ -181,7 +183,7 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
|
|||
hasComms = stream_getU8( stream );
|
||||
if ( hasComms ) {
|
||||
game->comms = comms_makeFromStream( MPPARM(mpool) stream, util,
|
||||
sendProc, closure );
|
||||
sendProc, IF_CH(resetProc) closure );
|
||||
} else {
|
||||
game->comms = NULL;
|
||||
}
|
||||
|
|
|
@ -81,16 +81,18 @@ typedef struct XWGame {
|
|||
|
||||
void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
|
||||
XW_UtilCtxt* util, DrawCtx* draw, XP_U16 gameID,
|
||||
CommonPrefs* cp, TransportSend sendproc, void* closure);
|
||||
CommonPrefs* cp, TransportSend sendproc,
|
||||
IF_CH(TransportReset resetproc) void* closure);
|
||||
void game_reset( MPFORMAL XWGame* game, CurGameInfo* gi, XW_UtilCtxt* util,
|
||||
XP_U16 gameID, CommonPrefs* cp, TransportSend sendproc,
|
||||
void* closure );
|
||||
IF_CH(TransportReset resetproc) void* closure );
|
||||
|
||||
XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
|
||||
CurGameInfo* gi,
|
||||
DictionaryCtxt* dict, XW_UtilCtxt* util,
|
||||
DrawCtx* draw, CommonPrefs* cp,
|
||||
TransportSend sendProc, void* closure );
|
||||
TransportSend sendProc, IF_CH(TransportReset rp)
|
||||
void* closure );
|
||||
|
||||
void game_saveToStream( const XWGame* game, const CurGameInfo* gi,
|
||||
XWStreamCtxt* stream );
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#define LETTER_NONE '\0'
|
||||
|
||||
typedef enum {
|
||||
ERR_NONE, /* 0 is special case */
|
||||
ERR_TILES_NOT_IN_LINE, /* scoring a move where tiles aren't in line */
|
||||
ERR_NO_EMPTIES_IN_TURN,
|
||||
ERR_TWO_TILES_FIRST_MOVE,
|
||||
|
|
|
@ -64,12 +64,19 @@ DEFINES += -DFEATURE_TRAY_EDIT
|
|||
#DEFINES += -DDRAW_WITH_PRIMITIVES
|
||||
|
||||
# Bluetooth support
|
||||
#BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_L2CAP
|
||||
BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_RFCOMM
|
||||
BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_L2CAP
|
||||
#BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_RFCOMM
|
||||
# DEFINES += -DXWFEATURE_IR
|
||||
DEFINES += ${BLUETOOTH}
|
||||
DEFINES += -DXWFEATURE_RELAY
|
||||
|
||||
# Choose one of these. RELAY_HEARTBEAT means relay (must be compiled
|
||||
# with same -D) works with comms on heartbeat. Works only with relay.
|
||||
# COMMS_HEARTBEAT should work on any comms transport (even IR, but
|
||||
# user experience will be very bad!). Is particularly useful with BT.
|
||||
# DEFINES += -DRELAY_HEARTBEAT
|
||||
DEFINES += -DCOMMS_HEARTBEAT
|
||||
|
||||
# Let users pick the tiles going into their trays
|
||||
#DEFINES += -DFEATURE_TRAY_EDIT
|
||||
DEFINES += -DDONT_ABORT_ENGINE
|
||||
|
|
|
@ -1048,7 +1048,8 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
|
|||
gameID = (XP_U16)util_getCurSeconds( globals.cGlobals.params->util );
|
||||
game_makeNewGame( MEMPOOL &globals.cGlobals.game, ¶ms->gi,
|
||||
params->util, (DrawCtx*)globals.draw,
|
||||
gameID, &globals.cp, linux_send, &globals );
|
||||
gameID, &globals.cp, linux_send,
|
||||
IF_CH(linux_reset) &globals );
|
||||
|
||||
if ( globals.cGlobals.game.comms ) {
|
||||
CommsAddrRec addr;
|
||||
|
|
|
@ -308,7 +308,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
|
|||
params->dict, params->util,
|
||||
(DrawCtx*)globals->draw,
|
||||
&globals->cp,
|
||||
linux_send, globals );
|
||||
linux_send, IF_CH(linux_reset) globals );
|
||||
|
||||
stream_destroy( stream );
|
||||
}
|
||||
|
@ -334,7 +334,8 @@ createOrLoadObjects( GtkAppGlobals* globals )
|
|||
|
||||
game_makeNewGame( MEMPOOL &globals->cGlobals.game, ¶ms->gi,
|
||||
params->util, (DrawCtx*)globals->draw,
|
||||
gameID, &globals->cp, linux_send, globals );
|
||||
gameID, &globals->cp, linux_send,
|
||||
IF_CH(linux_reset) globals );
|
||||
|
||||
addr.conType = params->conType;
|
||||
if ( 0 ) {
|
||||
|
@ -631,7 +632,8 @@ new_game( GtkWidget* XP_UNUSED(widget), GtkAppGlobals* globals )
|
|||
XP_STATUSF( "grabbed gameID: %ld\n", gameID );
|
||||
game_reset( MEMPOOL &globals->cGlobals.game, gi,
|
||||
globals->cGlobals.params->util,
|
||||
gameID, &globals->cp, linux_send, globals );
|
||||
gameID, &globals->cp, linux_send,
|
||||
IF_CH(linux_reset) globals );
|
||||
|
||||
if ( isClient ) {
|
||||
XWStreamCtxt* stream =
|
||||
|
@ -1674,6 +1676,7 @@ acceptorInput( GIOChannel* source, GIOCondition condition, gpointer data )
|
|||
|
||||
if ( (condition & G_IO_IN) != 0 ) {
|
||||
int listener = g_io_channel_unix_get_fd( source );
|
||||
XP_LOGF( "%s: input on socket %d", __func__, listener );
|
||||
keepSource = (*globals->acceptor)( listener, data );
|
||||
} else {
|
||||
keepSource = FALSE;
|
||||
|
@ -1694,9 +1697,11 @@ gtk_socket_acceptor( int listener, Acceptor func, CommonGlobals* globals )
|
|||
globals->acceptor = func;
|
||||
|
||||
channel = g_io_channel_unix_new( listener );
|
||||
g_io_channel_set_close_on_unref( channel, TRUE );
|
||||
result = g_io_add_watch( channel,
|
||||
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
|
||||
acceptorInput, globals );
|
||||
g_io_channel_unref( channel ); /* only main loop holds it now */
|
||||
XP_LOGF( "%s: g_io_add_watch(%d) => %d", __FUNCTION__, listener, result );
|
||||
}
|
||||
|
||||
|
|
|
@ -76,19 +76,34 @@ 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 ) {
|
||||
XP_MEMCPY( &mp->btaddr, btaddr, sizeof(mp->btaddr) );
|
||||
if ( (mp->sock != -1) && (0 == memcmp( btaddr, &mp->btaddr, sizeof(*btaddr) )) ) {
|
||||
(void)close( mp->sock );
|
||||
mp->sock = sock;
|
||||
++btStuff->u.master.nSocks;
|
||||
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 */
|
||||
|
||||
|
@ -98,17 +113,16 @@ lbt_removeSock( LinBtStuff* btStuff, int sock )
|
|||
XP_U16 i;
|
||||
|
||||
XP_ASSERT( btStuff->amMaster );
|
||||
XP_ASSERT( btStuff->u.master.nSocks > 0 );
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
XP_ASSERT( i < MAX_CLIENTS );
|
||||
} /* lbt_removeSock */
|
||||
|
||||
static LinBtStuff*
|
||||
|
@ -232,7 +246,7 @@ lbt_connectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
|
|||
(*globals->socketChanged)( globals->socketChangedClosure,
|
||||
-1, sock );
|
||||
} else {
|
||||
XP_LOGF( "%s: connect->%s", __FUNCTION__, strerror(errno) );
|
||||
XP_LOGF( "%s: connect->%s; closing socket %d", __FUNCTION__, strerror(errno), sock );
|
||||
close( sock );
|
||||
}
|
||||
}
|
||||
|
@ -250,11 +264,11 @@ lbt_accept( int listener, void* ctxt )
|
|||
|
||||
LOG_FUNC();
|
||||
|
||||
XP_LOGF( "%s: calling accept", __FUNCTION__ );
|
||||
XP_LOGF( "%s: calling accept", __func__ );
|
||||
slen = sizeof( inaddr );
|
||||
XP_ASSERT( listener == btStuff->u.master.listener );
|
||||
sock = accept( listener, (struct sockaddr *)&inaddr, &slen );
|
||||
XP_LOGF( "%s: accept returned; sock = %d", __FUNCTION__, sock );
|
||||
XP_LOGF( "%s: accept returned; socket = %d", __func__, sock );
|
||||
|
||||
success = sock >= 0;
|
||||
if ( success ) {
|
||||
|
@ -393,6 +407,7 @@ lbt_listenerSetup( CommonGlobals* globals )
|
|||
}
|
||||
#endif
|
||||
|
||||
XP_LOGF( "%s: calling listen on socket %d", __func__, listener );
|
||||
listen( listener, MAX_CLIENTS );
|
||||
|
||||
lbt_register( btStuff, htobs( XW_PSM ), rc_channel );
|
||||
|
@ -422,14 +437,36 @@ linux_bt_open( CommonGlobals* globals, XP_Bool amMaster )
|
|||
}
|
||||
} /* linux_bt_open */
|
||||
|
||||
void
|
||||
linux_bt_reset( CommonGlobals* globals )
|
||||
{
|
||||
XP_Bool amMaster = globals->btStuff->amMaster;
|
||||
LOG_FUNC();
|
||||
linux_bt_close( globals );
|
||||
linux_bt_open( globals, amMaster );
|
||||
LOG_RETURN_VOID();
|
||||
}
|
||||
|
||||
void
|
||||
linux_bt_close( CommonGlobals* globals )
|
||||
{
|
||||
LinBtStuff* btStuff = globals->btStuff;
|
||||
XP_U16 i;
|
||||
|
||||
if ( !!btStuff ) {
|
||||
if ( btStuff->amMaster ) {
|
||||
XP_LOGF( "%s: closing listener socket %d", __func__, btStuff->u.master.listener );
|
||||
close( btStuff->u.master.listener );
|
||||
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 );
|
||||
XP_LOGF( "sleeping for Palm's sake..." );
|
||||
sleep( 2 ); /* see if this gives palm a chance to not hang */
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "main.h"
|
||||
|
||||
void linux_bt_open( CommonGlobals* globals, XP_Bool amMaster );
|
||||
void linux_bt_reset( CommonGlobals* globals );
|
||||
void linux_bt_close( CommonGlobals* globals );
|
||||
|
||||
XP_S16 linux_bt_send( const XP_U8* buf, XP_U16 buflen,
|
||||
|
|
|
@ -422,6 +422,22 @@ linux_tcp_send( const XP_U8* buf, XP_U16 buflen,
|
|||
} /* linux_tcp_send */
|
||||
#endif
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
void
|
||||
linux_reset( void* closure )
|
||||
{
|
||||
CommonGlobals* globals = (CommonGlobals*)closure;
|
||||
CommsConnType conType = globals->params->conType;
|
||||
if ( 0 ) {
|
||||
#ifdef XWFEATURE_BLUETOOTH
|
||||
} else if ( conType == COMMS_CONN_BT ) {
|
||||
linux_bt_reset( globals );
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
||||
XP_S16
|
||||
linux_send( const XP_U8* buf, XP_U16 buflen,
|
||||
const CommsAddrRec* addrRec,
|
||||
|
|
|
@ -39,6 +39,9 @@ DictionaryCtxt* linux_dictionary_make( MPFORMAL const char* dictFileName );
|
|||
int initListenerSocket( int port );
|
||||
XP_S16 linux_send( const XP_U8* buf, XP_U16 buflen,
|
||||
const CommsAddrRec* addrRec, void* closure );
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
void linux_reset( void* closure );
|
||||
#endif
|
||||
int linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf,
|
||||
int bufSize );
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ MYDEFS_COMMON += -DXWFEATURE_SEARCHLIMIT
|
|||
# MYDEFS_COMMON += -DXWFEATURE_RELAY
|
||||
|
||||
# turn on bluetooth comms option for 68K and ARM
|
||||
BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_L2CAP
|
||||
BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_L2CAP -DCOMMS_HEARTBEAT
|
||||
#BLUETOOTH = -DXWFEATURE_BLUETOOTH -DBT_USE_RFCOMM
|
||||
MYDEFS_COMMON += $(BLUETOOTH)
|
||||
|
||||
|
|
|
@ -158,8 +158,8 @@ static XP_S16 pbt_enqueue( PBT_queue* queue, const XP_U8* data, XP_S16 len,
|
|||
static void pbt_handoffIncoming( PalmBTStuff* btStuff, BtCbEvtProc proc );
|
||||
|
||||
static void waitACL( PalmBTStuff* btStuff );
|
||||
static void pbt_reset( PalmBTStuff* btStuff );
|
||||
static void pbt_killL2C( PalmBTStuff* btStuff, BtLibSocketRef sock );
|
||||
static void pbt_reset_buffers( PalmBTStuff* btStuff );
|
||||
static void pbt_killLinks( PalmBTStuff* btStuff, BtLibSocketRef sock );
|
||||
static XP_Bool pbt_checkAddress( PalmBTStuff* btStuff, const CommsAddrRec* addr );
|
||||
static void pbt_setstate( PalmBTStuff* btStuff, PBT_STATE newState,
|
||||
const char* whence );
|
||||
|
@ -202,7 +202,7 @@ palm_bt_init( PalmAppGlobals* globals, XP_Bool* userCancelled )
|
|||
btStuff = pbt_checkInit( globals, userCancelled );
|
||||
/* Should I start master/slave setup here? If not, how? */
|
||||
} else {
|
||||
pbt_reset( btStuff );
|
||||
pbt_reset_buffers( btStuff );
|
||||
}
|
||||
|
||||
/* If we're the master, and a new game is starting without shutting down,
|
||||
|
@ -222,6 +222,28 @@ palm_bt_init( PalmAppGlobals* globals, XP_Bool* userCancelled )
|
|||
return inited;
|
||||
} /* palm_bt_init */
|
||||
|
||||
void
|
||||
palm_bt_reset( PalmAppGlobals* globals )
|
||||
{
|
||||
PalmBTStuff* btStuff = globals->btStuff;
|
||||
if ( !!btStuff ) {
|
||||
if ( btStuff->dataSocket != SOCK_INVAL ) {
|
||||
pbt_killLinks( btStuff, btStuff->dataSocket );
|
||||
}
|
||||
/* nuke all pending messages */
|
||||
pbt_reset_buffers( btStuff );
|
||||
btStuff->queueLen = 0;
|
||||
|
||||
if ( btStuff->picoRole == PBT_MASTER ) {
|
||||
pbt_setup_master( btStuff );
|
||||
} else if ( btStuff->picoRole == PBT_SLAVE ) {
|
||||
CommsAddrRec remoteAddr;
|
||||
comms_getAddr( globals->game.comms, &remoteAddr );
|
||||
pbt_setup_slave( btStuff, &remoteAddr );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
palm_bt_close( PalmAppGlobals* globals )
|
||||
{
|
||||
|
@ -431,6 +453,7 @@ pbt_send_pending( PalmBTStuff* btStuff )
|
|||
#ifdef LOG_BTIO
|
||||
LOG_HEX( buf, len, "to BtLibSocketSend" );
|
||||
#endif
|
||||
XP_LOGF( "sending on socket %d", btStuff->dataSocket );
|
||||
CALL_ERR( err, BtLibSocketSend, btStuff->btLibRefNum,
|
||||
btStuff->dataSocket, (char*)buf, len );
|
||||
if ( btLibErrPending == err ) {
|
||||
|
@ -578,6 +601,17 @@ pbt_close_datasocket( PalmBTStuff* btStuff )
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pbt_close_sdpsocket( PalmBTStuff* btStuff )
|
||||
{
|
||||
XP_ASSERT( PBT_SLAVE == btStuff->picoRole );
|
||||
if ( SOCK_INVAL != btStuff->u.slave.sdpSocket ) {
|
||||
Err err;
|
||||
CALL_ERR( err, BtLibSocketClose, btStuff->btLibRefNum, btStuff->u.slave.sdpSocket );
|
||||
btStuff->u.slave.sdpSocket = SOCK_INVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
pbt_takedown_master( PalmBTStuff* btStuff )
|
||||
{
|
||||
|
@ -669,11 +703,13 @@ pbt_do_work( PalmBTStuff* btStuff, BtCbEvtProc proc )
|
|||
|
||||
case PBT_ACT_GETSDP:
|
||||
if ( PBTST_ACL_CONNECTED == GET_STATE(btStuff) ) {
|
||||
XP_ASSERT( SOCK_INVAL == btStuff->u.slave.sdpSocket );
|
||||
CALL_ERR( err, BtLibSocketCreate, btStuff->btLibRefNum,
|
||||
&btStuff->u.slave.sdpSocket, socketCallback, (UInt32)btStuff,
|
||||
btLibSdpProtocol );
|
||||
if ( err == errNone ) {
|
||||
#if defined BT_USE_L2CAP
|
||||
XP_LOGF( "sending on sdpSocket socket %d", btStuff->u.slave.sdpSocket );
|
||||
CALL_ERR( err, BtLibSdpGetPsmByUuid, btStuff->btLibRefNum,
|
||||
btStuff->u.slave.sdpSocket, &btStuff->otherAddr,
|
||||
(BtLibSdpUuidType*)&XWORDS_UUID, 1 );
|
||||
|
@ -699,6 +735,7 @@ pbt_do_work( PalmBTStuff* btStuff, BtCbEvtProc proc )
|
|||
}
|
||||
/* Presumably state's been reset since PBT_ACT_GETSDP issued */
|
||||
XP_LOGF( "aborting b/c state wrong" );
|
||||
pbt_close_sdpsocket( btStuff );
|
||||
SET_STATE( btStuff, PBTST_NONE );
|
||||
waitACL( btStuff );
|
||||
break;
|
||||
|
@ -745,7 +782,9 @@ pbt_do_work( PalmBTStuff* btStuff, BtCbEvtProc proc )
|
|||
break;
|
||||
|
||||
case PBT_ACT_GOTDATA:
|
||||
CALL_ERR( err, BtLibSocketAdvanceCredit, btLibRefNum, btStuff->dataSocket, 1 );
|
||||
#ifdef BT_USE_RFCOMM
|
||||
CALL_ERR( err, BtLibSocketAdvanceCredit, btLibRefNum, btStuff->dataSocket, 5 );
|
||||
#endif
|
||||
pbt_handoffIncoming( btStuff, proc );
|
||||
break;
|
||||
|
||||
|
@ -892,7 +931,7 @@ pbt_handoffIncoming( PalmBTStuff* btStuff, BtCbEvtProc proc )
|
|||
} /* pbt_handoffIncoming */
|
||||
|
||||
static void
|
||||
pbt_reset( PalmBTStuff* btStuff )
|
||||
pbt_reset_buffers( PalmBTStuff* btStuff )
|
||||
{
|
||||
LOG_FUNC();
|
||||
XP_MEMSET( &btStuff->vol, 0, sizeof(btStuff->vol) );
|
||||
|
@ -940,6 +979,7 @@ pbt_setup_slave( PalmBTStuff* btStuff, const CommsAddrRec* addr )
|
|||
pbt_takedown_master( btStuff );
|
||||
}
|
||||
btStuff->picoRole = PBT_SLAVE;
|
||||
btStuff->u.slave.sdpSocket = SOCK_INVAL;
|
||||
|
||||
if ( !!addr ) {
|
||||
char buf[64];
|
||||
|
@ -964,7 +1004,7 @@ pbt_setup_slave( PalmBTStuff* btStuff, const CommsAddrRec* addr )
|
|||
static void
|
||||
pbt_takedown_slave( PalmBTStuff* btStuff )
|
||||
{
|
||||
pbt_killL2C( btStuff, btStuff->dataSocket );
|
||||
pbt_killLinks( btStuff, btStuff->dataSocket );
|
||||
btStuff->picoRole = PBT_UNINIT;
|
||||
}
|
||||
|
||||
|
@ -995,6 +1035,7 @@ pbt_checkInit( PalmAppGlobals* globals, XP_Bool* userCancelledP )
|
|||
|
||||
btStuff->dataSocket = SOCK_INVAL;
|
||||
btStuff->u.master.listenSocket = SOCK_INVAL;
|
||||
btStuff->u.slave.sdpSocket = SOCK_INVAL;
|
||||
|
||||
CALL_ERR( err, BtLibRegisterManagementNotification,
|
||||
btLibRefNum, libMgmtCallback, (UInt32)btStuff );
|
||||
|
@ -1010,13 +1051,17 @@ pbt_checkInit( PalmAppGlobals* globals, XP_Bool* userCancelledP )
|
|||
} /* pbt_checkInit */
|
||||
|
||||
static void
|
||||
pbt_killL2C( PalmBTStuff* btStuff, BtLibSocketRef sock )
|
||||
pbt_killLinks( PalmBTStuff* btStuff, BtLibSocketRef sock )
|
||||
{
|
||||
Err err;
|
||||
|
||||
XP_ASSERT( sock == btStuff->dataSocket );
|
||||
pbt_close_datasocket( btStuff );
|
||||
|
||||
if ( PBT_SLAVE == btStuff->picoRole ) {
|
||||
pbt_close_sdpsocket( btStuff );
|
||||
}
|
||||
|
||||
/* Harm in calling this when not connected? */
|
||||
if ( GET_STATE(btStuff) != PBTST_NONE ) {
|
||||
SET_STATE( btStuff, PBTST_NONE ); /* set first */
|
||||
|
@ -1024,7 +1069,7 @@ pbt_killL2C( PalmBTStuff* btStuff, BtLibSocketRef sock )
|
|||
CALL_ERR( err, BtLibLinkDisconnect, btStuff->btLibRefNum,
|
||||
&btStuff->otherAddr );
|
||||
}
|
||||
} /* pbt_killL2C */
|
||||
} /* pbt_killLinks */
|
||||
|
||||
static XP_Bool
|
||||
pbt_checkAddress( PalmBTStuff* btStuff, const CommsAddrRec* addr )
|
||||
|
@ -1041,7 +1086,7 @@ pbt_checkAddress( PalmBTStuff* btStuff, const CommsAddrRec* addr )
|
|||
LOG_HEX( &addr->u.bt.btAddr.bits, sizeof(addr->u.bt.btAddr.bits),
|
||||
"new" );
|
||||
|
||||
pbt_killL2C( btStuff, btStuff->dataSocket );
|
||||
pbt_killLinks( btStuff, btStuff->dataSocket );
|
||||
|
||||
XP_MEMCPY( &btStuff->otherAddr, &addr->u.bt.btAddr,
|
||||
sizeof(btStuff->otherAddr) );
|
||||
|
@ -1204,7 +1249,7 @@ socketCallback( BtLibSocketEventType* sEvent, UInt32 refCon )
|
|||
}
|
||||
|
||||
if ( PBT_SLAVE == btStuff->picoRole ) {
|
||||
pbt_killL2C( btStuff, sEvent->socket );
|
||||
pbt_killLinks( btStuff, sEvent->socket );
|
||||
waitACL( btStuff );
|
||||
} else if ( PBT_MASTER == btStuff->picoRole ) {
|
||||
pbt_close_datasocket( btStuff );
|
||||
|
@ -1215,9 +1260,7 @@ socketCallback( BtLibSocketEventType* sEvent, UInt32 refCon )
|
|||
case btLibSocketEventSdpGetPsmByUuid:
|
||||
case btLibSocketEventSdpGetServerChannelByUuid:
|
||||
XP_ASSERT( sEvent->socket == btStuff->u.slave.sdpSocket );
|
||||
CALL_ERR( err, BtLibSocketClose, btStuff->btLibRefNum, sEvent->socket );
|
||||
XP_ASSERT( err == errNone );
|
||||
btStuff->u.slave.sdpSocket = SOCK_INVAL;
|
||||
pbt_close_sdpsocket( btStuff );
|
||||
if ( sEvent->status == errNone ) {
|
||||
#if defined BT_USE_L2CAP
|
||||
btStuff->u.slave.remotePsm = sEvent->eventData.sdpByUuid.param.psm;
|
||||
|
@ -1269,7 +1312,6 @@ socketCallback( BtLibSocketEventType* sEvent, UInt32 refCon )
|
|||
static void
|
||||
libMgmtCallback( BtLibManagementEventType* mEvent, UInt32 refCon )
|
||||
{
|
||||
Err err;
|
||||
PalmBTStuff* btStuff = (PalmBTStuff*)refCon;
|
||||
BtLibManagementEventEnum event = mEvent->event;
|
||||
XP_LOGF( "%s(%s); status=%s", __FUNCTION__, mgmtEvtToStr(event),
|
||||
|
@ -1312,11 +1354,7 @@ libMgmtCallback( BtLibManagementEventType* mEvent, UInt32 refCon )
|
|||
call!!!! */
|
||||
XP_ASSERT( 0 == XP_MEMCMP( &mEvent->eventData.bdAddr,
|
||||
&btStuff->otherAddr, 6 ) );
|
||||
if ( SOCK_INVAL != btStuff->dataSocket ) {
|
||||
CALL_ERR( err, BtLibSocketClose, btStuff->btLibRefNum,
|
||||
btStuff->dataSocket );
|
||||
btStuff->dataSocket = SOCK_INVAL;
|
||||
}
|
||||
pbt_close_datasocket( btStuff );
|
||||
SET_STATE( btStuff, PBTST_NONE );
|
||||
/* See comment at btLibSocketEventDisconnected */
|
||||
if ( PBT_SLAVE == btStuff->picoRole ) {
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
void palm_bt_amendWaitTicks( PalmAppGlobals* globals, Int32* result );
|
||||
|
||||
XP_Bool palm_bt_init( PalmAppGlobals* globals, XP_Bool* userCancelled );
|
||||
void palm_bt_reset( PalmAppGlobals* globals );
|
||||
void palm_bt_close( PalmAppGlobals* globals );
|
||||
|
||||
typedef enum { BTCBEVT_CONN, BTCBEVT_DATA, BTCBEVT_HOSTFAIL } BtCbEvt;
|
||||
|
|
|
@ -91,6 +91,9 @@ static XP_Bool timeForTimer( PalmAppGlobals* globals, XWTimerReason* why,
|
|||
XP_U32* when );
|
||||
static XP_S16 palm_send( const XP_U8* buf, XP_U16 len,
|
||||
const CommsAddrRec* addr, void* closure );
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
static void palm_reset( void* closure );
|
||||
#endif
|
||||
static void palm_send_on_close( XWStreamCtxt* stream, void* closure );
|
||||
|
||||
/* callbacks */
|
||||
|
@ -597,7 +600,7 @@ loadCurrentGame( PalmAppGlobals* globals, XP_U16 gIndex,
|
|||
success = game_makeFromStream( MEMPOOL recStream, game, ginfo,
|
||||
dict, &globals->util,
|
||||
globals->draw, &globals->gState.cp,
|
||||
palm_send, globals );
|
||||
palm_send, IF_CH(palm_reset) globals );
|
||||
}
|
||||
|
||||
stream_destroy( recStream );
|
||||
|
@ -1190,7 +1193,7 @@ startApplication( PalmAppGlobals** globalsP )
|
|||
game_makeNewGame( MEMPOOL &globals->game, &globals->gameInfo,
|
||||
&globals->util, globals->draw, gameID,
|
||||
&globals->gState.cp,
|
||||
palm_send, globals );
|
||||
palm_send, IF_CH(palm_reset) globals );
|
||||
FrmPopupForm( XW_NEWGAMES_FORM );
|
||||
}
|
||||
|
||||
|
@ -1989,7 +1992,7 @@ initAndStartBoard( PalmAppGlobals* globals, XP_Bool newGame )
|
|||
XP_U32 newGameID = TimGetSeconds();
|
||||
game_reset( MEMPOOL &globals->game, &globals->gameInfo,
|
||||
&globals->util, newGameID, &globals->gState.cp,
|
||||
palm_send, globals );
|
||||
palm_send, IF_CH(palm_reset) globals );
|
||||
#if defined XWFEATURE_BLUETOOTH || defined XWFEATURE_RELAY || defined XWFEATURE_IR
|
||||
if ( !!globals->game.comms ) {
|
||||
comms_setAddr( globals->game.comms,
|
||||
|
@ -3812,7 +3815,7 @@ palm_util_setTimer( XW_UtilCtxt* uc, XWTimerReason why,
|
|||
now += PALM_TIMER_DELAY;
|
||||
} else if ( why == TIMER_TIMERTICK ) {
|
||||
now += SysTicksPerSecond();
|
||||
#ifdef XWFEATURE_RELAY
|
||||
#if defined XWFEATURE_RELAY || defined COMMS_HEARTBEAT
|
||||
} else if ( why == TIMER_HEARTBEAT ) {
|
||||
now += (secsFromNow * SysTicksPerSecond());
|
||||
#endif
|
||||
|
@ -3927,6 +3930,26 @@ palm_send( const XP_U8* buf, XP_U16 len,
|
|||
return result;
|
||||
} /* palm_send */
|
||||
|
||||
#ifdef COMMS_HEARTBEAT
|
||||
static void
|
||||
palm_reset( void* closure )
|
||||
{
|
||||
PalmAppGlobals* globals = (PalmAppGlobals*)closure;
|
||||
XP_ASSERT( !!globals->game.comms );
|
||||
|
||||
switch( comms_getConType( globals->game.comms ) ) {
|
||||
#ifdef XWFEATURE_BLUETOOTH
|
||||
case COMMS_CONN_BT:
|
||||
palm_bt_reset( globals );
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
XP_ASSERT(0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
checkAndDeliver( PalmAppGlobals* globals, const CommsAddrRec* addr,
|
||||
XWStreamCtxt* instream )
|
||||
|
|
Loading…
Reference in a new issue