mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-01 06:19:57 +01:00
3c6405d0d1
A full robot vs. robot game now works between two Treos. Added UI to choose BT as transport mechanism, and added new send proc to establish socket connection between host and guest. Works only for two devices: no piconet yet. No error recovery, ability to quit game in middle, start new game, etc.
380 lines
12 KiB
C
380 lines
12 KiB
C
/* -*-mode: C; fill-column: 77; c-basic-offset: 4; -*- */
|
|
/*
|
|
* Copyright 2001-2005 by Eric House (xwords@eehouse.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 BEYOND_IR
|
|
|
|
#include <TimeMgr.h>
|
|
|
|
#include "palmip.h"
|
|
#include "memstream.h"
|
|
|
|
#define NETLIB_TIMEOUT (5 * sysTicksPerSecond)
|
|
#define NAMELOOKUP_TIMEOUT (60*sysTicksPerSecond)
|
|
|
|
void
|
|
palm_ip_setup( PalmAppGlobals* globals )
|
|
{
|
|
globals->nlStuff.socket = -1;
|
|
globals->nlStuff.netLibRef = 0; /* probably unnecessary */
|
|
}
|
|
|
|
static void
|
|
close_socket( PalmAppGlobals* globals )
|
|
{
|
|
if ( globals->nlStuff.socket != -1 ) {
|
|
Err ignore;
|
|
NetLibSocketClose( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socket, 0, &ignore);
|
|
globals->nlStuff.socket = -1;
|
|
}
|
|
} /* close_socket */
|
|
|
|
void
|
|
palm_ip_close( PalmAppGlobals* globals )
|
|
{
|
|
if ( globals->nlStuff.netLibRef != 0 ) {
|
|
|
|
close_socket( globals );
|
|
|
|
NetLibClose(globals->nlStuff.netLibRef, 0);
|
|
|
|
globals->nlStuff.netLibRef = 0;
|
|
}
|
|
} /* palm_ip_close */
|
|
|
|
static 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 XP_Bool
|
|
connectSocket( PalmAppGlobals* globals, const CommsAddrRec* addr )
|
|
{
|
|
XP_Bool success;
|
|
Err err;
|
|
NetSocketAddrINType socketAddr;
|
|
|
|
socketAddr.family = netSocketAddrINET;
|
|
socketAddr.port = XP_HTONS( addr->u.ip_relay.port );
|
|
socketAddr.addr = XP_HTONL( addr->u.ip_relay.ipAddr );
|
|
|
|
success = ( 0 == NetLibSocketConnect( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socket,
|
|
(NetSocketAddrType*)&socketAddr,
|
|
sizeof(socketAddr), NETLIB_TIMEOUT,
|
|
&err ) );
|
|
if ( !success ) {
|
|
XP_LOGF( "NetLibSocketConnect => %d", err );
|
|
}
|
|
return success;
|
|
} /* connectSocket */
|
|
|
|
static XP_Bool
|
|
openSocketIfNot( PalmAppGlobals* globals, const CommsAddrRec* addr )
|
|
{
|
|
XP_Bool open = globals->nlStuff.socket != -1;
|
|
|
|
if ( !open ) {
|
|
Err err;
|
|
NetSocketRef socket;
|
|
|
|
XP_ASSERT( globals->nlStuff.netLibRef != 0 );
|
|
|
|
socket = NetLibSocketOpen( globals->nlStuff.netLibRef,
|
|
netSocketAddrINET,
|
|
netSocketTypeStream,
|
|
0, /* protocol (ignored) */
|
|
NETLIB_TIMEOUT, &err );
|
|
if ( err == errNone ) {
|
|
NetSocketLingerType lt;
|
|
|
|
XP_LOGF( "Opened socket %d", socket );
|
|
|
|
/* Just for grins, turn linger off; suggested by
|
|
* http://tomfrauen.blogspot.com/2005/01/some-palm-os-network-programming.html
|
|
*/
|
|
lt.onOff = true;
|
|
lt.time = 0;
|
|
NetLibSocketOptionSet( globals->nlStuff.netLibRef, socket,
|
|
netSocketOptLevelSocket,
|
|
netSocketOptSockLinger, <, sizeof(lt),
|
|
NETLIB_TIMEOUT, &err );
|
|
|
|
globals->nlStuff.socket = socket;
|
|
open = connectSocket( globals, addr );
|
|
if ( !open ) {
|
|
close_socket( globals );
|
|
}
|
|
|
|
} else {
|
|
XP_LOGF( "Failed to open socket: %d", err );
|
|
}
|
|
}
|
|
return open;
|
|
} /* openSocketIfNot */
|
|
|
|
static XP_Bool
|
|
resolveAddressIfNot( PalmAppGlobals* globals, CommsAddrRec* addr,
|
|
XP_Bool* resolvedP )
|
|
{
|
|
XP_Bool resolved = addr->u.ip_relay.ipAddr != 0
|
|
&& !globals->nlStuff.ipAddrInval;
|
|
*resolvedP = XP_FALSE;
|
|
|
|
if ( !resolved ) {
|
|
NetHostInfoBufType niBuf;
|
|
NetHostInfoPtr result;
|
|
Err err;
|
|
|
|
result = NetLibGetHostByName( globals->nlStuff.netLibRef,
|
|
addr->u.ip_relay.hostName,
|
|
&niBuf, NAMELOOKUP_TIMEOUT, &err );
|
|
if ( result == NULL ) {
|
|
XP_LOGF( "NetLibGetHostByName => %d", err );
|
|
} else {
|
|
|
|
XP_ASSERT( result->addrLen == sizeof(addr->u.ip_relay.ipAddr) );
|
|
/* Addresses are in host byte order. So just copy. */
|
|
XP_MEMCPY( &addr->u.ip_relay.ipAddr, result->addrListP[0],
|
|
sizeof( addr->u.ip_relay.ipAddr ) );
|
|
XP_LOGF( "got address 0x%lx for %s", addr->u.ip_relay.ipAddr,
|
|
addr->u.ip_relay.hostName );
|
|
|
|
*resolvedP = resolved = XP_TRUE;
|
|
globals->nlStuff.ipAddrInval = XP_FALSE;
|
|
|
|
comms_setAddr( globals->game.comms, addr );
|
|
}
|
|
}
|
|
return resolved;
|
|
} /* resolveAddressIfNot */
|
|
|
|
void
|
|
ip_addr_change( PalmAppGlobals* globals, const CommsAddrRec* oldAddr,
|
|
const CommsAddrRec* newAddr )
|
|
{
|
|
/* If host name changing, close any open socket and set up to inval
|
|
the cached ip address. */
|
|
if ( 0 != XP_STRNCMP( oldAddr->u.ip_relay.hostName,
|
|
newAddr->u.ip_relay.hostName,
|
|
sizeof( oldAddr->u.ip_relay.hostName ) ) ) {
|
|
|
|
close_socket( globals );
|
|
globals->nlStuff.ipAddrInval = XP_TRUE;
|
|
}
|
|
|
|
} /* ip_addr_change */
|
|
|
|
/* Deal with NetLibSend's willingness to send less than the full buffer */
|
|
static XP_Bool
|
|
sendLoop( PalmAppGlobals* globals, const XP_U8* buf, XP_U16 len )
|
|
{
|
|
XP_U16 totalSent = 0;
|
|
|
|
do {
|
|
XP_S16 thisSent;
|
|
Err err;
|
|
thisSent = NetLibSend( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socket,
|
|
(void*)(buf + totalSent),
|
|
len - totalSent, 0, /* flags */
|
|
NULL, 0, NETLIB_TIMEOUT, &err );
|
|
|
|
if ( thisSent == 0 ) {
|
|
globals->nlStuff.socket = -1; /* mark socket closed */
|
|
return XP_FALSE;
|
|
} else if ( thisSent < 0 ) {
|
|
XP_LOGF( "NetLibSend => %d", err );
|
|
return XP_FALSE;
|
|
} else {
|
|
totalSent += thisSent;
|
|
if ( totalSent < len ) {
|
|
XP_LOGF( "looping in sendLoop: %d of %d sent so far",
|
|
totalSent, len );
|
|
}
|
|
}
|
|
} while ( totalSent < len );
|
|
|
|
XP_LOGF( "sendLoop sent %d bytes", len );
|
|
return XP_TRUE;
|
|
} /* sendLoop */
|
|
|
|
XP_S16
|
|
palm_ip_send( const XP_U8* buf, XP_U16 len, const CommsAddrRec* addrp,
|
|
PalmAppGlobals* globals )
|
|
{
|
|
CommsAddrRec localRec;
|
|
CommsAddrRec* addr = &localRec;
|
|
XP_S16 nSent = 0;
|
|
XP_Bool resolved = XP_FALSE;
|
|
|
|
XP_LOGF( "palm_ip_send: len=%d", len );
|
|
XP_ASSERT( len < MAX_MSG_LEN );
|
|
|
|
if ( !!addrp ) {
|
|
XP_MEMCPY( addr, addrp, sizeof(*addr) );
|
|
} else {
|
|
comms_getAddr( globals->game.comms, addr );
|
|
}
|
|
|
|
if ( openNetLibIfNot( globals ) ) {
|
|
if ( resolveAddressIfNot( globals, addr, &resolved ) ) {
|
|
if ( resolved ) {
|
|
comms_setAddr( globals->game.comms, addr );
|
|
}
|
|
|
|
if ( openSocketIfNot( globals, addr ) ) {
|
|
XP_U16 netlen;
|
|
|
|
/* Send the length */
|
|
netlen = XP_HTONS( len );
|
|
if ( sendLoop( globals, (XP_U8*)&netlen, sizeof(netlen) )
|
|
&& sendLoop( globals, buf, len ) ) {
|
|
nSent = len;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return nSent;
|
|
} /* palm_ip_send */
|
|
|
|
/* Deal with NetLibReceive's willingness to return will fewer bytes than
|
|
requested. */
|
|
static XP_Bool
|
|
recvLoop( PalmAppGlobals* globals, XP_U8* buf, XP_U16 lenSought )
|
|
{
|
|
XP_U32 timeout = TimGetSeconds() + 5;
|
|
XP_U16 totalRead = 0;
|
|
NetSocketAddrINType fromAddr;
|
|
void* fromAddrP;
|
|
UInt16 fromLen;
|
|
|
|
if ( globals->romVersion >= 50 ) {
|
|
fromAddrP = NULL;
|
|
fromLen = 0;
|
|
} else {
|
|
fromAddrP = (void*)&fromAddr;
|
|
fromLen = sizeof( fromAddr );
|
|
}
|
|
|
|
/* Be sure there's a way to timeout quickly here!!! */
|
|
while ( totalRead < lenSought && TimGetSeconds() < timeout ) {
|
|
Err err;
|
|
Int16 nRead = NetLibReceive( globals->nlStuff.netLibRef,
|
|
globals->nlStuff.socket,
|
|
buf, lenSought, 0, /* flags */
|
|
fromAddrP, &fromLen,
|
|
NETLIB_TIMEOUT, &err );
|
|
|
|
if ( (nRead < 0) && (err != netErrTimeout) ) {
|
|
XP_LOGF( "NetLibReceive => %d", err );
|
|
return XP_FALSE;
|
|
} else if ( nRead == 0 ) {
|
|
XP_LOGF( "NetLibReceive; socket close" );
|
|
globals->nlStuff.socket = -1;
|
|
return XP_FALSE;
|
|
} else {
|
|
totalRead += nRead;
|
|
}
|
|
}
|
|
|
|
XP_LOGF( "recvLoop got %d bytes", totalRead );
|
|
return totalRead == lenSought;
|
|
} /* recvLoop */
|
|
|
|
static XWStreamCtxt*
|
|
packetToStream( PalmAppGlobals* globals )
|
|
{
|
|
XP_U8 buf[MAX_MSG_LEN];
|
|
XWStreamCtxt* result = NULL;
|
|
XP_U16 netlen;
|
|
|
|
if ( recvLoop( globals, (XP_U8*)&netlen, sizeof(netlen) ) ) {
|
|
netlen = XP_NTOHS( netlen );
|
|
XP_LOGF( "netlen = %d", netlen );
|
|
if ( recvLoop( globals, buf, netlen ) ) {
|
|
|
|
result = mem_stream_make( MEMPOOL globals->vtMgr,
|
|
globals, 0, NULL);
|
|
stream_open( result );
|
|
stream_putBytes( result, buf, netlen );
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} /* packetToStream */
|
|
|
|
void
|
|
checkHandleNetEvents( PalmAppGlobals* globals )
|
|
{
|
|
if ( ipSocketIsOpen( globals ) ) {
|
|
NetFDSetType readFDs;
|
|
NetFDSetType writeFDs;
|
|
NetFDSetType ignoreFDs;
|
|
XP_S16 nSockets;
|
|
UInt16 width;
|
|
Err err;
|
|
|
|
netFDZero( &readFDs );
|
|
netFDZero( &writeFDs );
|
|
netFDZero( &ignoreFDs );
|
|
|
|
netFDSet( globals->nlStuff.socket, &readFDs );
|
|
netFDSet( sysFileDescStdIn, &readFDs );
|
|
width = XP_MAX( globals->nlStuff.socket, sysFileDescStdIn );
|
|
|
|
XP_ASSERT( globals->nlStuff.netLibRef != 0 );
|
|
nSockets = NetLibSelect( globals->nlStuff.netLibRef,
|
|
width + 1,
|
|
&readFDs, &writeFDs, &ignoreFDs,
|
|
globals->runningOnPOSE? 0 : NETLIB_TIMEOUT,
|
|
&err );
|
|
|
|
if ( nSockets > 0 && netFDIsSet(globals->nlStuff.socket, &readFDs) ) {
|
|
|
|
XWStreamCtxt* instream = packetToStream( globals );
|
|
if ( !!instream ) {
|
|
checkAndDeliver( globals, instream );
|
|
}
|
|
}
|
|
}
|
|
} /* checkHandleNetEvents */
|
|
|
|
#endif
|