mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-11-18 10:08:29 +01:00
1049 lines
30 KiB
C
1049 lines
30 KiB
C
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
|
|
/*
|
|
* Copyright 2001 by Eric House (fixin@peak.org). All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#ifdef IR_SUPPORT
|
|
|
|
#include <TimeMgr.h>
|
|
|
|
#include "palmir.h"
|
|
|
|
#include "callback.h"
|
|
#include "xwords4defines.h"
|
|
#include "comms.h"
|
|
#include "memstream.h"
|
|
#include "palmutil.h"
|
|
#include "LocalizedStrIncludes.h"
|
|
#ifdef BEYOND_IR
|
|
# include <NetMgr.h>
|
|
#endif
|
|
|
|
# ifndef IR_EXCHMGR
|
|
|
|
#define IR_NO_TIMEOUT 0xFFFFFFFF
|
|
#if 1
|
|
# define IR_TIMEOUT (15*60) /* 10 seconds during debugging */
|
|
#else
|
|
# define IR_TIMEOUT (150*60) /* 100 seconds during debugging */
|
|
#endif
|
|
|
|
#define RESET_TIMER(g) (g)->ir_timeout = TimGetTicks() + IR_TIMEOUT
|
|
|
|
struct MyIrPacket {
|
|
IrPacket packet;
|
|
struct MyIrPacket* next;
|
|
Boolean in_use;
|
|
};
|
|
|
|
/***************************************************************************/
|
|
static void receiveData( PalmAppGlobals* globals, UInt8* buf, UInt16 len );
|
|
#define addFreeQueue( g,p ) (--(g)->irSendQueueLen)
|
|
static void addToSendQueue( PalmAppGlobals* globals, MyIrPacket* packet );
|
|
static void clearSendQueue( PalmAppGlobals* globals );
|
|
static MyIrPacket* getFreeSendPacket( PalmAppGlobals* globals );
|
|
#ifdef DEBUG
|
|
static void printStateTransition( PalmAppGlobals* globals );
|
|
static void assert_state1( PalmAppGlobals* globals, short line,
|
|
IR_STATE assertState );
|
|
static void assert_state2( PalmAppGlobals* globals, short line,
|
|
IR_STATE assertState1,IR_STATE assertState2 );
|
|
#else
|
|
#define printStateTransition( globals )
|
|
#define assert_state1( globals, line, assertState )
|
|
#define assert_state2( globals, line, assertState1, assertState2 )
|
|
#endif
|
|
/***************************************************************************/
|
|
|
|
static Boolean
|
|
storeDiscovery( PalmAppGlobals* globals, IrDeviceList* deviceList,
|
|
IrConnect* con )
|
|
{
|
|
short i;
|
|
|
|
XP_ASSERT( deviceList->nItems <= 1 );
|
|
|
|
for ( i = 0; i < deviceList->nItems; ++i ) {
|
|
globals->irDev = deviceList->dev[i].hDevice;
|
|
XP_ASSERT( &globals->irC_out.irCon == con );
|
|
con->rLsap = deviceList->dev[i].xid[0];
|
|
#ifdef DEBUG
|
|
globals->save_rLsap = con->rLsap;
|
|
#endif
|
|
}
|
|
return deviceList->nItems > 0;
|
|
} /* storeDiscovery */
|
|
|
|
void
|
|
ir_callback_out( IrConnect* con, IrCallBackParms* parms )
|
|
{
|
|
PalmAppGlobals* globals;
|
|
IrStatus status;
|
|
|
|
CALLBACK_PROLOGUE();
|
|
|
|
globals = ((MyIrConnect*)con)->globals;
|
|
|
|
switch ( parms->event ) {
|
|
|
|
case LEVENT_LAP_DISCON_IND: /* IrLAP connection has gone down, or
|
|
IrConnectIrLap failed */
|
|
|
|
XP_STATUSF( "LAP_DISCON_IND received" );
|
|
if ( !!globals->rcvBuffSize ) {
|
|
/* we've received a buffer and now need to do something with it */
|
|
assert_state1( globals, __LINE__, IR_STATE_NONE );
|
|
/* globals->ir_state = IR_STATE_MESSAGE_RECD; */
|
|
} else {
|
|
globals->ir_state = IR_STATE_NONE; /* was IR_STATE_DOLAP */
|
|
}
|
|
break;
|
|
|
|
case LEVENT_LM_CON_IND:
|
|
XP_ASSERT( !globals->conPacketInUse );
|
|
XP_STATUSF( "responding to incomming connection" );
|
|
assert_state2( globals, __LINE__, IR_STATE_CONN_RECD,
|
|
IR_STATE_LAP_RCV );
|
|
|
|
globals->conPacket.buff = globals->conBuff;
|
|
globals->conPacket.len = sizeof(globals->conBuff);
|
|
XP_ASSERT( globals->conPacket.len <= IR_MAX_CON_PACKET );
|
|
status = IrConnectRsp( globals->irLibRefNum, con,
|
|
&globals->conPacket, 0 /* credit: ignored */);
|
|
|
|
XP_ASSERT( status == IR_STATUS_PENDING );
|
|
if ( status == IR_STATUS_PENDING ) {
|
|
globals->conPacketInUse = true;
|
|
globals->ir_state = IR_STATE_CONN_INCOMMING;
|
|
} else {
|
|
XP_STATUSF( "IrConnectRsp call failed with %d", status );
|
|
}
|
|
break;
|
|
|
|
case LEVENT_LM_DISCON_IND:
|
|
XP_WARNF( "LEVENT_LM_DISCON_IND received; failure???" );
|
|
break;
|
|
|
|
case LEVENT_PACKET_HANDLED: {
|
|
IrPacket* packetPtr = parms->packet;
|
|
|
|
packetPtr->buff = NULL;
|
|
packetPtr->len = 0;
|
|
|
|
if ( packetPtr == &globals->conPacket ) {
|
|
|
|
/* don't change the state here. This is just telling us the
|
|
packet's free */
|
|
/* assert_state2( globals, __LINE__, IR_STATE_LMPREQ_SENT, */
|
|
/* IR_STATE_LMPRCV_REQ_SENT ); */
|
|
XP_ASSERT( globals->conPacketInUse );
|
|
/* not true if an incomming connection */
|
|
/* XP_ASSERT( !!getSendQueueHead(globals) ); */
|
|
globals->conPacketInUse = false;
|
|
} else {
|
|
assert_state1( globals, __LINE__, IR_STATE_SEND_DONE );
|
|
((MyIrPacket*)packetPtr)->in_use = false;
|
|
addFreeQueue( globals, packetPtr );
|
|
/* if we've received notification that a send was successful, and
|
|
if we've no further sends to do, shut down the connection.*/
|
|
if ( !!getSendQueueHead(globals) ) { /* another message? */
|
|
globals->ir_state = IR_STATE_LMP_ESTAB;
|
|
} else {
|
|
globals->ir_state = IR_STATE_CAN_DISCONNECT;
|
|
XP_STATUSF( "state:IR_STATE_CAN_DISCONNECT" );
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case LEVENT_DATA_IND:
|
|
assert_state1( globals, __LINE__, IR_STATE_CONN_INCOMMING );
|
|
receiveData( globals, parms->rxBuff, parms->rxLen );
|
|
globals->ir_state = IR_STATE_MESSAGE_RECD;
|
|
break;
|
|
|
|
case LEVENT_STATUS_IND:
|
|
break;
|
|
case LEVENT_DISCOVERY_CNF: /* both sides must do this */
|
|
assert_state1( globals, __LINE__, IR_STATE_DISCOVERY_SENT );
|
|
if ( storeDiscovery( globals, parms->deviceList, con ) ) {
|
|
if ( !!getSendQueueHead( globals ) ) {
|
|
globals->ir_state = IR_STATE_DOLAP;
|
|
} else {
|
|
globals->ir_state = IR_STATE_DISCOVERY_COMPLETE;
|
|
}
|
|
} else { /* discovery failed */
|
|
globals->ir_state = IR_STATE_REDO_DISCOVERY;
|
|
}
|
|
break;
|
|
case LEVENT_LAP_CON_CNF:
|
|
XP_STATUSF( "irlap established" );
|
|
assert_state1( globals, __LINE__, IR_STATE_LAP_SENT );
|
|
globals->ir_state = IR_STATE_LAP_ESTAB;
|
|
break;
|
|
|
|
case LEVENT_LM_CON_CNF: /* requested IrLMP connection successful */
|
|
|
|
XP_STATUSF( "IrLMP connection is up" );
|
|
assert_state1( globals, __LINE__, IR_STATE_LMPREQ_SENT );
|
|
XP_ASSERT( ir_work_exists(globals) );
|
|
/* I'm not sure whether we get this event before or after the one
|
|
releasing the packet passed to IrConnectReq. Both need to happen
|
|
before we can do a send -- though I guess since we're using a
|
|
different packet that's not strictly true. */
|
|
globals->ir_state = IR_STATE_LMP_ESTAB;
|
|
break;
|
|
|
|
case LEVENT_LAP_CON_IND:
|
|
/* indicates that the other side's opened up a connection */
|
|
XP_STATUSF( "other side opened up a LAP connection" );
|
|
globals->ir_state = IR_STATE_LAP_RCV;
|
|
break;
|
|
|
|
/* case LEVENT_TEST_CNF: */
|
|
/* XP_ASSERT( globals->packet_in_use ); */
|
|
/* globals->packet_in_use = false; */
|
|
/* XP_DEBUGF( "LEVENT_TEST_CNF: returned %d", parms->status ); */
|
|
/* break; */
|
|
|
|
/* case LEVENT_TEST_IND: */
|
|
/* XP_DEBUGF( "LEVENT_TEST_IND received" ); */
|
|
/* receiveData( globals, parms->rxBuff, parms->rxLen ); */
|
|
/* break; */
|
|
|
|
default:
|
|
}
|
|
|
|
CALLBACK_EPILOGUE();
|
|
} /* ir_callback_out */
|
|
#endif
|
|
|
|
#ifdef BEYOND_IR
|
|
static void checkAndDeliver( PalmAppGlobals* globals, XWStreamCtxt* instream,
|
|
CommsAddrRec* addr );
|
|
#endif
|
|
|
|
void
|
|
palm_send_on_close( XWStreamCtxt* stream, void* closure )
|
|
{
|
|
PalmAppGlobals* globals = (PalmAppGlobals*)closure;
|
|
CommsConnType conType = comms_getConType( globals->game.comms );
|
|
|
|
XP_ASSERT( !!globals->game.comms );
|
|
comms_send( globals->game.comms, conType, stream );
|
|
} /* palm_send_on_close */
|
|
|
|
# ifndef IR_EXCHMGR
|
|
Boolean
|
|
ir_do_work( PalmAppGlobals* globals )
|
|
{
|
|
IrStatus status;
|
|
Boolean result = false;
|
|
XWStreamCtxt* instream;
|
|
MyIrPacket* packetPtr;
|
|
|
|
printStateTransition( globals );
|
|
|
|
if ( !!getSendQueueHead(globals) /* we're here to send something */
|
|
&& globals->ir_state > IR_STATE_NOTHING_TO_DO
|
|
&& globals->ir_timeout < TimGetTicks() ) {
|
|
Boolean retry;
|
|
|
|
retry = palmaskFromStrId( globals, STR_RESEND_IR, -1, -1 );
|
|
|
|
/* why did I do this? */
|
|
if ( IrIsIrLapConnected( globals->irLibRefNum ) ) {
|
|
status = IrDisconnectIrLap( globals->irLibRefNum );
|
|
XP_ASSERT( status == IR_STATUS_PENDING );
|
|
}
|
|
|
|
if ( retry ) {
|
|
RESET_TIMER(globals);
|
|
} else {
|
|
clearSendQueue( globals );
|
|
}
|
|
globals->ir_state = retry? IR_STATE_DO_DISCOVERY : IR_STATE_NONE;
|
|
|
|
} else {
|
|
|
|
switch( globals->ir_state ) {
|
|
|
|
case IR_STATE_NONE: /* do we need this state anymore? */
|
|
XP_ASSERT( !!getSendQueueHead( globals ) );
|
|
if ( IrIsIrLapConnected(globals->irLibRefNum) ) {
|
|
globals->ir_state = IR_STATE_LAP_ESTAB;
|
|
} else {
|
|
globals->ir_state = IR_STATE_DO_DISCOVERY;
|
|
}
|
|
break;
|
|
|
|
case IR_STATE_DO_DISCOVERY:
|
|
/* might a well set it up here */
|
|
globals->conPacket.buff = globals->conBuff;
|
|
globals->conPacket.len = IR_MAX_CON_PACKET;
|
|
|
|
RESET_TIMER(globals);
|
|
case IR_STATE_REDO_DISCOVERY:
|
|
if ( IrIsIrLapConnected(globals->irLibRefNum) ) {
|
|
globals->ir_state = IR_STATE_LAP_ESTAB;
|
|
} else {
|
|
status = IrDiscoverReq( globals->irLibRefNum,
|
|
&globals->irC_out.irCon );
|
|
|
|
if (status == IR_STATUS_SUCCESS ||
|
|
status == IR_STATUS_PENDING) {
|
|
globals->ir_state = IR_STATE_DISCOVERY_SENT;
|
|
} else {
|
|
XP_STATUSF( "discov failed: %d", status );
|
|
globals->ir_state = IR_STATE_REDO_DISCOVERY;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IR_STATE_DISCOVERY_SENT:
|
|
break;
|
|
|
|
case IR_STATE_DOLAP:
|
|
/* better be a message to send! */
|
|
XP_ASSERT( !!getSendQueueHead( globals ) );
|
|
XP_STATUSF( "calling IrConnectIrLap" );
|
|
status = IrConnectIrLap( globals->irLibRefNum, globals->irDev );
|
|
if (status != IR_STATUS_SUCCESS && status != IR_STATUS_PENDING) {
|
|
XP_STATUSF( "IrConnectIrLap call failed: %d", status );
|
|
} else {
|
|
globals->ir_state = IR_STATE_LAP_SENT;
|
|
}
|
|
break;
|
|
|
|
case IR_STATE_LAP_SENT:
|
|
/* XP_DEBUGF( "state still IR_STATE_LAP_SENT" ); */
|
|
break;
|
|
|
|
case IR_STATE_LAP_ESTAB:
|
|
if ( !globals->conPacketInUse ) {
|
|
/* not true if from other side */
|
|
/* XP_ASSERT( !!globals->conPacket.buff ); */
|
|
XP_ASSERT( IrIsIrLapConnected(globals->irLibRefNum) );
|
|
/* not sure what this means anyway.... */
|
|
/* XP_ASSERT(globals->irC_out.irCon.rLsap== */
|
|
/* globals->save_rLsap); */
|
|
status = IrConnectReq( globals->irLibRefNum,
|
|
&globals->irC_out.irCon,
|
|
&globals->conPacket, 0 );
|
|
if ( status == IR_STATUS_PENDING ) {
|
|
|
|
if ( globals->ir_state == IR_STATE_LAP_ESTAB ) {
|
|
globals->ir_state = IR_STATE_LMPREQ_SENT;
|
|
} else {
|
|
globals->ir_state = IR_STATE_LMPRCV_REQ_SENT;
|
|
}
|
|
|
|
globals->conPacketInUse = true;
|
|
XP_STATUSF( "IrConnectReq succeeded" );
|
|
|
|
} else {
|
|
XP_STATUSF( "IrConnectReq returned %d; will try again",
|
|
status );
|
|
}
|
|
} else {
|
|
XP_WARNF( "Can't call IrConnectReq b/c packet_in_use" );
|
|
}
|
|
break;
|
|
|
|
case IR_STATE_LMP_ESTAB:
|
|
packetPtr = getSendQueueHead( globals );
|
|
XP_ASSERT( !!packetPtr );
|
|
if ( !!packetPtr ) {
|
|
XP_ASSERT( !!packetPtr->packet.buff );
|
|
XP_ASSERT( packetPtr->packet.len > 0 );
|
|
status = IrDataReq( globals->irLibRefNum,
|
|
&globals->irC_out.irCon,
|
|
&packetPtr->packet );
|
|
if ( status == IR_STATUS_PENDING ) {
|
|
packetPtr->in_use = true;
|
|
globals->ir_state = IR_STATE_SEND_DONE;
|
|
} else {
|
|
XP_WARNF( "IrDataReq returned %d", status );
|
|
}
|
|
}
|
|
break;
|
|
|
|
case IR_STATE_MESSAGE_RECD:
|
|
XP_ASSERT( !!globals->rcvBuffSize );
|
|
|
|
instream = mem_stream_make( MEMPOOL globals, 0, NULL );
|
|
stream_open( instream );
|
|
stream_putBytes( instream, globals->rcvBuff,
|
|
globals->rcvBuffSize );
|
|
globals->rcvBuffSize = 0;
|
|
|
|
if ( comms_checkIncommingStream( globals->game.comms, instream,
|
|
&instream, 1 ) ) { /* FIXME!!! */
|
|
result = server_receiveMessage( globals->game.server,
|
|
instream );
|
|
}
|
|
stream_destroy( instream );
|
|
|
|
palm_util_requestTime( &globals->util );
|
|
|
|
globals->ir_state = IR_STATE_CAN_DISCONNECT;
|
|
break; /* comment this out? */
|
|
|
|
#if 1
|
|
case IR_STATE_CAN_DISCONNECT:
|
|
/* send the disconnect message so receiver will know the
|
|
message is finished */
|
|
|
|
/* if the other side disconnects, it'll already be down?? */
|
|
if ( IrIsIrLapConnected( globals->irLibRefNum ) ) {
|
|
status = IrDisconnectIrLap( globals->irLibRefNum );
|
|
XP_ASSERT( status == IR_STATUS_PENDING );
|
|
}
|
|
globals->ir_state = IR_STATE_NONE;
|
|
|
|
break;
|
|
#endif
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return result;
|
|
} /* ir_do_work */
|
|
|
|
void
|
|
ir_show_status( PalmAppGlobals* globals )
|
|
{
|
|
if ( !!globals->mainForm ) {
|
|
XP_U16 x, y;
|
|
WinHandle oldHand = WinSetDrawWindow( (WinHandle)globals->mainForm );
|
|
|
|
x = globals->isLefty?1:154;
|
|
y = 160 - TRAY_HEIGHT - IR_STATUS_HEIGHT;
|
|
|
|
if ( globals->ir_state > IR_STATE_NOTHING_TO_DO ) {
|
|
char buf[2] = { 0, 0 };
|
|
if ( globals->ir_state <= 9 ) {
|
|
buf[0] = '0' + globals->ir_state;
|
|
} else {
|
|
buf[0] = 'A' + globals->ir_state-10;
|
|
}
|
|
WinDrawChars( buf, 1, x, y );
|
|
} else {
|
|
RectangleType r = { {x, y}, {8, 10} };
|
|
WinEraseRectangle( &r, 0);
|
|
}
|
|
|
|
WinSetDrawWindow( oldHand );
|
|
}
|
|
} /* ir_show_status */
|
|
|
|
/* Free any memory associated with message queues, etc.
|
|
*/
|
|
void
|
|
ir_cleanup( PalmAppGlobals* globals )
|
|
{
|
|
MyIrPacket* packet;
|
|
MyIrPacket* next;
|
|
|
|
for ( packet = globals->packetListHead; !!packet; packet = next ) {
|
|
next = packet->next;
|
|
XP_FREE( globals->mpool, packet );
|
|
}
|
|
globals->packetListHead = NULL;
|
|
} /* ir_cleanup */
|
|
#endif
|
|
|
|
#ifdef BEYOND_IR
|
|
# define NETLIB_TIMEOUT 2
|
|
|
|
XP_Bool
|
|
openNetLibIfNot( PalmAppGlobals* globals )
|
|
{
|
|
Err err;
|
|
XP_Bool done = globals->nlStuff.netLibRef != 0;
|
|
|
|
if ( !done ) {
|
|
UInt16 libRef;
|
|
err = SysLibFind( "Net.lib", &libRef);
|
|
if ( err == errNone ) {
|
|
UInt16 ifErrs;
|
|
err = NetLibOpen( libRef, &ifErrs );
|
|
if ( err == errNone ) {
|
|
globals->nlStuff.netLibRef = libRef;
|
|
done = XP_TRUE;
|
|
XP_LOGF( "successful netlib open" );
|
|
} else {
|
|
XP_LOGF( "NetLibOpen failed: err=%d; ifErrs=%d",
|
|
err, ifErrs );
|
|
}
|
|
}
|
|
}
|
|
|
|
return done;
|
|
} /* openNetLibIfNot */
|
|
|
|
static void
|
|
bindSocket( PalmAppGlobals* globals, XP_U16 listenPort )
|
|
{
|
|
NetSocketAddrINType socketAddr;
|
|
UInt16 res;
|
|
Err err;
|
|
|
|
XP_MEMSET( &socketAddr, 0, sizeof(socketAddr) );
|
|
socketAddr.family = netSocketAddrINET;
|
|
socketAddr.port = listenPort;
|
|
|
|
res = NetLibSocketBind( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socketRef,
|
|
(NetSocketAddrType*)&socketAddr,
|
|
sizeof(socketAddr), -1, &err );
|
|
|
|
if ( res == 0 && err == errNone ) {
|
|
globals->nlStuff.listenPort = listenPort;
|
|
XP_LOGF( "successful socket bind on port %d",
|
|
socketAddr.port );
|
|
} else {
|
|
XP_LOGF( "bind failed: %d", err );
|
|
}
|
|
} /* bindSocket */
|
|
|
|
static XP_Bool
|
|
openSocketIfNot( PalmAppGlobals* globals )
|
|
{
|
|
XP_Bool open = globals->nlStuff.socketRef != 0;
|
|
XP_Bool newlyOpen = XP_FALSE;
|
|
|
|
if ( !open ) {
|
|
Err err;
|
|
NetSocketRef socketRef;
|
|
|
|
XP_ASSERT( globals->nlStuff.netLibRef != 0 );
|
|
|
|
socketRef = NetLibSocketOpen( globals->nlStuff.netLibRef,
|
|
netSocketAddrINET,
|
|
netSocketTypeDatagram,
|
|
0, /* protocol (ignored) */
|
|
NETLIB_TIMEOUT,
|
|
&err );
|
|
if ( err == errNone ) {
|
|
globals->nlStuff.socketRef = socketRef;
|
|
newlyOpen = open = XP_TRUE;
|
|
|
|
XP_LOGF( "Opened socket" );
|
|
} else {
|
|
XP_LOGF( "Failed to open socket" );
|
|
}
|
|
|
|
if ( globals->nlStuff.listenPort != 0 ) {
|
|
bindSocket( globals, globals->nlStuff.listenPort );
|
|
}
|
|
}
|
|
return open;
|
|
} /* openSocketIfNot */
|
|
|
|
void
|
|
palm_bind_socket( PalmAppGlobals* globals, XP_U16 newPort )
|
|
{
|
|
if ( openNetLibIfNot( globals ) && openSocketIfNot(globals) ) {
|
|
bindSocket( globals, newPort );
|
|
}
|
|
} /* palm_bind_socket */
|
|
|
|
void
|
|
palm_ip_close( PalmAppGlobals* globals )
|
|
{
|
|
if ( globals->nlStuff.netLibRef != 0 ) {
|
|
|
|
if ( globals->nlStuff.socketRef != 0 ) {
|
|
Err ignore;
|
|
NetLibSocketClose( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socketRef, 0, &ignore);
|
|
globals->nlStuff.socketRef = 0;
|
|
}
|
|
|
|
NetLibClose(globals->nlStuff.netLibRef, 0);
|
|
|
|
globals->nlStuff.netLibRef = 0;
|
|
}
|
|
} /* palm_ip_close */
|
|
|
|
#define MAX_PACKET_SIZE 256
|
|
|
|
static XP_S16
|
|
palm_ip_send( XP_U8* buf, XP_U16 len, CommsAddrRec* addr,
|
|
PalmAppGlobals* globals )
|
|
{
|
|
XP_S16 nSent = 0;
|
|
|
|
XP_LOGF( "palm_ip_send: len=%d", len );
|
|
XP_ASSERT( len < MAX_PACKET_SIZE );
|
|
|
|
if ( openNetLibIfNot( globals ) && openSocketIfNot( globals ) ) {
|
|
Err err;
|
|
NetSocketAddrINType outSocket;
|
|
|
|
XP_MEMSET( &outSocket, 0, sizeof(outSocket) );
|
|
outSocket.family = netSocketAddrINET;
|
|
if ( 0 && !!addr ) {
|
|
outSocket.port = addr->u.ip.port;
|
|
outSocket.addr = addr->u.ip.ipAddr;
|
|
} else {
|
|
/* first time, get address from user settings */
|
|
CommsAddrRec addr;
|
|
XP_U16 ignore;
|
|
comms_getAddr( globals->game.comms, &addr, &ignore );
|
|
|
|
outSocket.port = addr.u.ip.port;
|
|
outSocket.addr = addr.u.ip.ipAddr;
|
|
}
|
|
XP_LOGF( "sending to host 0x%lx, port %d",
|
|
outSocket.addr, outSocket.port );
|
|
|
|
nSent = NetLibSend( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socketRef,
|
|
(void*) buf, len, 0, /* flags */
|
|
&outSocket, sizeof(outSocket),
|
|
NETLIB_TIMEOUT,
|
|
&err );
|
|
|
|
if ( err != errNone || nSent != len ) {
|
|
XP_LOGF( "failed to send %d bytes; sent %d; err=%d",
|
|
len, nSent, err );
|
|
nSent = 0;
|
|
} else {
|
|
XP_LOGF( "sent %d bytes", nSent );
|
|
}
|
|
}
|
|
return nSent;
|
|
} /* palm_ip_send */
|
|
#endif
|
|
|
|
#ifdef BEYOND_IR
|
|
static XWStreamCtxt*
|
|
packetToStream( PalmAppGlobals* globals, CommsAddrRec* retAddr )
|
|
{
|
|
XP_U8 buf[MAX_PACKET_SIZE];
|
|
Err err;
|
|
XP_S16 nRead;
|
|
NetSocketAddrINType fromAddr;
|
|
void* fromAddrP;
|
|
UInt16 fromLen;
|
|
XWStreamCtxt* result;
|
|
|
|
if ( globals->romVersion >= 50 ) {
|
|
fromAddrP = NULL;
|
|
fromLen = 0;
|
|
} else {
|
|
fromAddrP = (void*)&fromAddr;
|
|
fromLen = sizeof( fromAddr );
|
|
}
|
|
|
|
XP_LOGF( "calling NetLibReceive" );
|
|
nRead = NetLibReceive( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socketRef,
|
|
buf, MAX_PACKET_SIZE,
|
|
0, /* flags */
|
|
fromAddrP, &fromLen,
|
|
0, &err );
|
|
XP_LOGF( "back from NetLibReceive" );
|
|
|
|
if ( (nRead > 0) && (err == errNone) ) {
|
|
XP_LOGF( "read data: %d bytes", nRead );
|
|
|
|
result = mem_stream_make( MEMPOOL globals->vtMgr,
|
|
globals, 0, NULL);
|
|
stream_open( result );
|
|
stream_putBytes( result, buf, nRead );
|
|
|
|
/* harvest the return address */
|
|
retAddr->conType = COMMS_CONN_IP;
|
|
retAddr->u.ip.ipAddr = fromAddr.addr;
|
|
retAddr->u.ip.port = fromAddr.port;
|
|
XP_LOGF( "received packet from port %d on host 0x%lx",
|
|
fromAddr.port, fromAddr.addr );
|
|
} else {
|
|
result = NULL;
|
|
XP_LOGF( "didn't read data: %d bytes or err=%d",
|
|
nRead, err );
|
|
}
|
|
|
|
return result;
|
|
} /* packetToStream */
|
|
|
|
void
|
|
checkHandleNetEvents( PalmAppGlobals* globals )
|
|
{
|
|
if ( openNetLibIfNot( globals ) && openSocketIfNot( globals ) ) {
|
|
NetFDSetType readFDs;
|
|
NetFDSetType writeFDs;
|
|
NetFDSetType ignoreFDs;
|
|
XP_S16 nSockets;
|
|
Err err;
|
|
|
|
netFDZero( &readFDs );
|
|
netFDZero( &writeFDs );
|
|
netFDZero( &ignoreFDs );
|
|
|
|
netFDSet( globals->nlStuff.socketRef, &readFDs );
|
|
nSockets = NetLibSelect( globals->nlStuff.netLibRef,
|
|
netFDSetSize, /* built-in constant PENDING */
|
|
&readFDs, &writeFDs, &ignoreFDs,
|
|
1, /* timeout */
|
|
&err );
|
|
|
|
if ( nSockets > 0 && err == errNone ) {
|
|
if ( netFDIsSet( globals->nlStuff.socketRef, &readFDs ) ) {
|
|
|
|
XWStreamCtxt* instream;
|
|
CommsAddrRec raddr;
|
|
|
|
XP_MEMSET( &raddr, 0, sizeof(raddr) );
|
|
|
|
instream = packetToStream( globals, &raddr );
|
|
if ( !!instream ) {
|
|
checkAndDeliver( globals, instream, &raddr );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} /* checkHandleNetEvents */
|
|
#endif
|
|
|
|
/* We're passed an address as we've previously defined it and a buffer
|
|
* containing a message to send. Prepend any palm/ir specific headers to the
|
|
* message, save the buffer somewhere, and fire up the state machine that
|
|
* will eventually get it sent to the address.
|
|
*
|
|
* Note that the caller will queue the message for possible resend, but
|
|
* won't automatically schedule that resend whatever results we return.
|
|
*
|
|
* NOTE also that simply stuffing the buf ptr into the packet won't work
|
|
* if there's any ir-specific packet header I need to prepend to what's
|
|
* outgoing.
|
|
*/
|
|
static XP_S16
|
|
palm_ir_send( XP_U8* buf, XP_U16 len, PalmAppGlobals* globals )
|
|
{
|
|
#ifdef IR_EXCHMGR
|
|
UInt32 sent = 0;
|
|
Err err;
|
|
ExgSocketType exgSocket;
|
|
XP_MEMSET( &exgSocket, 0, sizeof(exgSocket) );
|
|
exgSocket.description = "Crosswords data";
|
|
exgSocket.length = len;
|
|
exgSocket.target = APPID;
|
|
|
|
if ( globals->romVersion >= 40 ) {
|
|
#ifdef BEYOND_IR
|
|
if ( globals->exgLibraryRef == 0 ) {
|
|
exgSocket.name = exgSendBeamPrefix;
|
|
} else {
|
|
exgSocket.libraryRef = globals->exgLibraryRef;
|
|
}
|
|
#else
|
|
exgSocket.name = exgBeamPrefix;
|
|
#endif
|
|
}
|
|
|
|
err = ExgPut( &exgSocket );
|
|
while ( !err && sent < len ) {
|
|
sent += ExgSend( &exgSocket, buf+sent, len-sent, &err );
|
|
XP_ASSERT( sent < 0x7FFF );
|
|
}
|
|
err = ExgDisconnect( &exgSocket, err );
|
|
|
|
#ifdef BEYOND_IR
|
|
/* no need to check for ROM version here */
|
|
if ( globals->exgLibraryRef == 0 ) {
|
|
globals->exgLibraryRef = exgSocket.libraryRef;
|
|
}
|
|
#endif
|
|
|
|
return err==0? sent : 0;
|
|
#else
|
|
MyIrPacket* packet = getFreeSendPacket( globals );
|
|
|
|
packet->packet.buff = buf;
|
|
packet->packet.len = len;
|
|
XP_ASSERT( !packet->in_use );
|
|
|
|
addToSendQueue( globals, packet );
|
|
|
|
return len;
|
|
#endif
|
|
} /* palm_ir_send */
|
|
|
|
XP_S16
|
|
palm_send( XP_U8* buf, XP_U16 len, CommsAddrRec* addr, void* closure )
|
|
{
|
|
PalmAppGlobals* globals = (PalmAppGlobals*)closure;
|
|
#ifdef BEYOND_IR
|
|
|
|
XP_S16 result = 0;
|
|
switch( comms_getConType(globals->game.comms) ) {
|
|
case COMMS_CONN_IR:
|
|
result = palm_ir_send( buf, len, globals );
|
|
break;
|
|
case COMMS_CONN_IP:
|
|
result = palm_ip_send( buf, len, addr, globals );
|
|
break;
|
|
default:
|
|
XP_ASSERT(0);
|
|
}
|
|
return result;
|
|
#else
|
|
return palm_ir_send( buf, len, globals );
|
|
#endif
|
|
} /* palm_send */
|
|
|
|
static void
|
|
checkAndDeliver( PalmAppGlobals* globals, XWStreamCtxt* instream,
|
|
CommsAddrRec* addr )
|
|
{
|
|
if ( comms_checkIncommingStream( globals->game.comms,
|
|
instream, addr ) ) {
|
|
globals->msgReceivedDraw =
|
|
server_receiveMessage( globals->game.server, instream );
|
|
globals->msgReceivedDraw = true;
|
|
}
|
|
stream_destroy( instream );
|
|
palm_util_requestTime( &globals->util );
|
|
} /* checkAndDeliver */
|
|
|
|
#ifdef IR_EXCHMGR
|
|
void
|
|
palm_ir_receiveMove( PalmAppGlobals* globals, ExgSocketPtr socket )
|
|
{
|
|
UInt32 nBytesReceived = -1;
|
|
Err err;
|
|
|
|
err = ExgAccept( socket );
|
|
if ( err == 0 ) {
|
|
XWStreamCtxt* instream;
|
|
|
|
instream = mem_stream_make( MEMPOOL globals->vtMgr, globals,
|
|
CHANNEL_NONE, NULL );
|
|
stream_open( instream );
|
|
|
|
for ( ; ; ) {
|
|
UInt8 buf[128];
|
|
nBytesReceived = ExgReceive( socket, buf, sizeof(buf), &err );
|
|
if ( nBytesReceived == 0 || err != 0 ) {
|
|
break;
|
|
}
|
|
|
|
stream_putBytes( instream, buf, nBytesReceived );
|
|
}
|
|
(void)ExgDisconnect( socket, err );
|
|
|
|
if ( nBytesReceived == 0 ) { /* successful loop exit */
|
|
|
|
CommsAddrRec rec;
|
|
rec.conType = COMMS_CONN_IR;
|
|
checkAndDeliver( globals, instream, &rec );
|
|
}
|
|
}
|
|
} /* palm_ir_receiveMove */
|
|
#else
|
|
static void
|
|
receiveData( PalmAppGlobals* globals, UInt8* buf, UInt16 len )
|
|
{
|
|
XP_ASSERT( !!len );
|
|
XP_ASSERT( !globals->conPacketInUse );
|
|
|
|
XP_ASSERT( !globals->rcvBuffSize ); /* else messages coming in several
|
|
parts; old code handled this */
|
|
XP_MEMCPY( globals->rcvBuff, buf, len );
|
|
globals->rcvBuffSize = len;
|
|
|
|
globals->ir_timeout = IR_NO_TIMEOUT;
|
|
} /* receiveData */
|
|
|
|
/* return the first packet ready to be sent, i.e. whose buf ptr is non-null
|
|
* and whose in_use flag is not set. To make searching faster, keep track of
|
|
* whether there are actually any on the queue. */
|
|
MyIrPacket*
|
|
getSendQueueHead( PalmAppGlobals* globals )
|
|
{
|
|
MyIrPacket* packet = NULL;
|
|
|
|
if ( globals->irSendQueueLen > 0 ) {
|
|
|
|
packet = (MyIrPacket*)globals->packetListHead;
|
|
for ( ; !!packet; packet = packet->next ) {
|
|
if ( !!packet->packet.buff && !packet->in_use ) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return packet;
|
|
} /* getSendQueueHead */
|
|
#endif
|
|
|
|
/* The ptr's already on the list, but we need to move it to the end, behind
|
|
* anything that's already there waiting to be sent. That's because messages
|
|
* need to get sent in order.
|
|
*/
|
|
#ifndef IR_EXCHMGR
|
|
static void
|
|
addToSendQueue( PalmAppGlobals* globals, MyIrPacket* packet )
|
|
{
|
|
MyIrPacket* end = globals->packetListHead;
|
|
|
|
packet->next = NULL;
|
|
|
|
if ( !end ) {
|
|
globals->packetListHead = packet;
|
|
} else {
|
|
|
|
for ( ; !!end->next; end = end->next ) {
|
|
|
|
}
|
|
end->next = packet;
|
|
}
|
|
++globals->irSendQueueLen;
|
|
RESET_TIMER(globals);
|
|
} /* addToSendQueue */
|
|
#endif /* ifndef IR_EXCHMGR */
|
|
|
|
#ifndef IR_EXCHMGR
|
|
static void
|
|
clearSendQueue( PalmAppGlobals* globals )
|
|
{
|
|
MyIrPacket* packet;
|
|
MyIrPacket* next;
|
|
|
|
for ( packet = globals->packetListHead; !!packet; packet = next ) {
|
|
next = packet->next;
|
|
if ( packet->packet.buff != NULL ) {
|
|
packet->packet.buff = NULL;
|
|
packet->packet.len = 0;
|
|
--globals->irSendQueueLen;
|
|
}
|
|
}
|
|
|
|
XP_ASSERT( globals->irSendQueueLen == 0 ) ;
|
|
} /* clearSendQueue */
|
|
|
|
static MyIrPacket*
|
|
getFreeSendPacket( PalmAppGlobals* globals )
|
|
{
|
|
MyIrPacket* packet = globals->packetListHead;
|
|
MyIrPacket* prev;
|
|
|
|
for ( prev = NULL; !!packet; prev = packet, packet = packet->next ) {
|
|
if ( !packet->packet.buff ) {
|
|
XP_ASSERT( packet->packet.len == 0 );
|
|
|
|
/* cut out of list before returning */
|
|
if ( !!prev ) {
|
|
prev->next = packet->next;
|
|
} else {
|
|
XP_ASSERT( globals->packetListHead == packet );
|
|
globals->packetListHead = NULL;
|
|
}
|
|
|
|
return packet;
|
|
}
|
|
}
|
|
packet = XP_MALLOC( globals->mpool, sizeof(*packet) );
|
|
XP_MEMSET( packet, 0, sizeof(*packet) );
|
|
|
|
return packet;
|
|
} /* getFreeSendPacket */
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
#ifndef IR_EXCHMGR
|
|
static char*
|
|
getStateName( IR_STATE state )
|
|
{
|
|
switch ( state ) {
|
|
|
|
case IR_STATE_NONE: return "NONE";
|
|
case IR_STATE_DISCOVERY_COMPLETE: return "DISCOVERY_COMPLETE";
|
|
|
|
|
|
case IR_STATE_NOTHING_TO_DO: return "NOTHING_TO_DO";
|
|
case IR_STATE_NO_OTHER_FOUND: return "NO_OTHER_FOUND";
|
|
case IR_STATE_DO_DISCOVERY: return "DO_DISCOVERY";
|
|
case IR_STATE_REDO_DISCOVERY: return "REDO_DISCOVERY";
|
|
case IR_STATE_DISCOVERY_SENT: return "DISCOVERY_SENT";
|
|
case IR_STATE_DOLAP: return "DOLAP";
|
|
|
|
|
|
case IR_STATE_LAP_SENT: return "LAP_SENT";
|
|
case IR_STATE_LAP_ESTAB: return "LAP_ESTAB";
|
|
|
|
|
|
case IR_STATE_LMPREQ_SENT: return "LMPREQ_SENT";
|
|
case IR_STATE_LMP_ESTAB: return "LMP_ESTAB";
|
|
|
|
|
|
case IR_STATE_SEND_DONE: return "SEND_DONE";
|
|
case IR_STATE_CAN_DISCONNECT: return "CAN_DISCONNECT";
|
|
|
|
case IR_STATE_CONN_RECD: return "CONN_RECD";
|
|
case IR_STATE_LAP_RCV: return "LAP_RCV";
|
|
case IR_STATE_LMPRCV_REQ_SENT: return "LMPRCV_REQ_SENT";
|
|
case IR_STATE_CONN_INCOMMING: return "CONN_INCOMMING";
|
|
case IR_STATE_MESSAGE_RECD: return "MESSAGE_RECD";
|
|
|
|
default:
|
|
return "unknown";
|
|
}
|
|
|
|
} /* getStateName */
|
|
|
|
static void
|
|
assert_state1( PalmAppGlobals* globals, short line, IR_STATE assertState )
|
|
{
|
|
if ( globals->ir_state != assertState ) {
|
|
XP_WARNF( "Line %d: sought %s; found %s", line,
|
|
getStateName(assertState), getStateName(globals->ir_state));
|
|
}
|
|
} /* assert_state1 */
|
|
|
|
static void
|
|
assert_state2( PalmAppGlobals* globals, short line, IR_STATE assertState1,
|
|
IR_STATE assertState2 )
|
|
{
|
|
if ( globals->ir_state != assertState1
|
|
&& globals->ir_state != assertState2){
|
|
XP_WARNF( "Line %d: sought %s or %s; found %s", line,
|
|
getStateName(assertState1), getStateName(assertState2),
|
|
getStateName( globals->ir_state ) );
|
|
}
|
|
|
|
} /* assertState2 */
|
|
|
|
static void
|
|
printStateTransition( PalmAppGlobals* globals )
|
|
{
|
|
if ( globals->ir_state != globals->ir_state_prev ) {
|
|
char* oldState = getStateName( globals->ir_state_prev );
|
|
char* newState = getStateName( globals->ir_state );
|
|
|
|
XP_STATUSF( "ir_st:%s->%s", oldState, newState );
|
|
|
|
globals->ir_state_prev = globals->ir_state;
|
|
}
|
|
} /* printStateTransition */
|
|
# endif /* IR_EXCHMGR */
|
|
#endif /* DEBUG */
|
|
|
|
#endif /* IR_SUPPORT */
|