diff --git a/linux/Makefile b/linux/Makefile index 8873e82a0..c4943f004 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -59,6 +59,9 @@ DEFINES += -DFEATURE_TRAY_EDIT #DEFINES += -DDRAW_WITH_PRIMITIVES DEFINES += -DBEYOND_IR +# Bluetooth support +DEFINES += -DXWFEATURE_BLUETOOTH + # Let users pick the tiles going into their trays #DEFINES += -DFEATURE_TRAY_EDIT DEFINES += -DDONT_ABORT_ENGINE @@ -85,10 +88,11 @@ OBJ = $(PLATFORM)/linuxmain.o \ $(PLATFORM)/cursesdlgutil.o \ $(PLATFORM)/cursesletterask.o \ $(PLATFORM)/filestream.o \ + $(PLATFORM)/linuxbt.o \ # $(PLATFORM)/linuxcommpipe.o \ -LIBS = -lm -L $(HOME)/usr/local/pilot/lib $(GPROFFLAG) +LIBS = -lm -lbluetooth -L $(HOME)/usr/local/pilot/lib $(GPROFFLAG) ifneq (,$(findstring DPLATFORM_GTK,$(DEFINES))) LIBS += `pkg-config --libs gtk+-2.0` diff --git a/linux/cursesmain.c b/linux/cursesmain.c index 87b7f8979..62d704254 100644 --- a/linux/cursesmain.c +++ b/linux/cursesmain.c @@ -704,7 +704,8 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch ) --numEvents; - nBytes = linux_receive( &globals->cGlobals, buf, sizeof(buf) ); + nBytes = linux_relay_receive( &globals->cGlobals, buf, + sizeof(buf) ); if ( nBytes != -1 ) { XWStreamCtxt* inboundS; @@ -935,7 +936,10 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) setupCursesUtilCallbacks( &globals, params->util ); - globals.cGlobals.defaultServerName = params->relayName; + if ( params->conType == COMMS_CONN_RELAY ) { + globals.cGlobals.u.relay.defaultServerName + = params->connInfo.relay.relayName; + } cursesListenOnSocket( &globals, 0, NULL ); /* stdin */ @@ -952,16 +956,16 @@ 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_tcp_send, &globals ); + gameID, &globals.cp, linux_send, &globals ); if ( globals.cGlobals.game.comms ) { CommsAddrRec addr; addr.conType = COMMS_CONN_RELAY; addr.u.ip_relay.ipAddr = 0; /* ??? */ - addr.u.ip_relay.port = params->defaultSendPort; - XP_STRNCPY( addr.u.ip_relay.hostName, params->relayName, + addr.u.ip_relay.port = params->connInfo.relay.defaultSendPort; + XP_STRNCPY( addr.u.ip_relay.hostName, params->connInfo.relay.relayName, sizeof(addr.u.ip_relay.hostName) - 1 ); - XP_STRNCPY( addr.u.ip_relay.cookie, params->cookie, + XP_STRNCPY( addr.u.ip_relay.cookie, params->connInfo.relay.cookie, sizeof(addr.u.ip_relay.cookie) - 1 ); comms_setAddr( globals.cGlobals.game.comms, &addr ); } diff --git a/linux/gtkmain.c b/linux/gtkmain.c index 4631eda83..143fbbc36 100644 --- a/linux/gtkmain.c +++ b/linux/gtkmain.c @@ -41,6 +41,7 @@ #include "main.h" #include "linuxmain.h" +#include "linuxbt.h" /* #include "gtkmain.h" */ #include "draw.h" @@ -247,7 +248,7 @@ createOrLoadObjects( GtkAppGlobals* globals ) params->dict, params->util, (DrawCtx*)globals->draw, &globals->cp, - linux_tcp_send, globals ); + linux_send, globals ); stream_destroy( stream ); @@ -255,25 +256,37 @@ createOrLoadObjects( GtkAppGlobals* globals ) XP_U16 gameID; CommsAddrRec addr; + addr.conType = params->conType; + gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util ); - XP_ASSERT( !!params->relayName ); - globals->cGlobals.defaultServerName = params->relayName; + if ( addr.conType == COMMS_CONN_RELAY ) { + XP_ASSERT( !!params->connInfo.relay.relayName ); + globals->cGlobals.u.relay.defaultServerName + = params->connInfo.relay.relayName; + } params->gi.gameID = util_getCurSeconds(globals->cGlobals.params->util); XP_STATUSF( "grabbed gameID: %ld\n", params->gi.gameID ); game_makeNewGame( MEMPOOL &globals->cGlobals.game, ¶ms->gi, params->util, (DrawCtx*)globals->draw, - gameID, &globals->cp, linux_tcp_send, globals ); + gameID, &globals->cp, linux_send, globals ); - addr.conType = COMMS_CONN_RELAY; - addr.u.ip_relay.ipAddr = 0; - addr.u.ip_relay.port = params->defaultSendPort; - XP_STRNCPY( addr.u.ip_relay.hostName, params->relayName, - sizeof(addr.u.ip_relay.hostName) - 1 ); - XP_STRNCPY( addr.u.ip_relay.cookie, params->cookie, - sizeof(addr.u.ip_relay.cookie) - 1 ); + addr.conType = params->conType; + if ( addr.conType == COMMS_CONN_RELAY ) { + addr.u.ip_relay.ipAddr = 0; + addr.u.ip_relay.port = params->connInfo.relay.defaultSendPort; + XP_STRNCPY( addr.u.ip_relay.hostName, params->connInfo.relay.relayName, + sizeof(addr.u.ip_relay.hostName) - 1 ); + XP_STRNCPY( addr.u.ip_relay.cookie, params->connInfo.relay.cookie, + sizeof(addr.u.ip_relay.cookie) - 1 ); + } else if ( addr.conType == COMMS_CONN_BT ) { + XP_ASSERT( sizeof(addr.u.bt.btAddr) + >= sizeof(params->connInfo.bt.hostAddr)); + XP_MEMCPY( &addr.u.bt.btAddr, ¶ms->connInfo.bt.hostAddr, + sizeof(params->connInfo.bt.hostAddr) ); + } /* This may trigger network activity */ if ( !!globals->cGlobals.game.comms ) { @@ -463,6 +476,8 @@ quit( void* XP_UNUSED(dunno), GtkAppGlobals* globals ) game_dispose( &globals->cGlobals.game ); /* takes care of the dict */ gi_disposePlayerInfo( MEMPOOL &globals->cGlobals.params->gi ); + + linux_bt_close( &globals->cGlobals ); vtmgr_destroy( MEMPOOL globals->cGlobals.params->vtMgr ); @@ -547,7 +562,7 @@ 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_tcp_send, globals ); + gameID, &globals->cp, linux_send, globals ); if ( isClient ) { XWStreamCtxt* stream = @@ -1472,7 +1487,14 @@ newConnectionInput( GIOChannel *source, ssize_t nRead; unsigned char buf[512]; - nRead = linux_receive( &globals->cGlobals, buf, sizeof(buf) ); + if ( globals->cGlobals.params->conType == COMMS_CONN_RELAY ) { + nRead = linux_relay_receive( &globals->cGlobals, + buf, sizeof(buf) ); + } else if ( globals->cGlobals.params->conType == COMMS_CONN_BT ) { + nRead = linux_bt_receive( &globals->cGlobals, buf, sizeof(buf) ); + } else { + XP_ASSERT( 0 ); + } if ( !globals->dropIncommingMsgs && nRead > 0 ) { XWStreamCtxt* inboundS; @@ -1482,8 +1504,9 @@ newConnectionInput( GIOChannel *source, if ( !!inboundS ) { if ( comms_checkIncomingStream( globals->cGlobals.game.comms, inboundS, NULL ) ) { - redraw = server_receiveMessage(globals->cGlobals.game.server - , inboundS ); + redraw = + server_receiveMessage(globals->cGlobals.game.server, + inboundS ); } stream_destroy( inboundS ); } @@ -1525,6 +1548,7 @@ static void gtk_socket_changed( void* closure, int oldSock, int newSock ) { GtkAppGlobals* globals = (GtkAppGlobals*)closure; + XP_ASSERT( oldSock == globals->cGlobals.socket ); if ( oldSock != -1 ) { g_source_remove( oldSock ); XP_LOGF( "Removed %d from gtk's list of listened-to sockets" ); @@ -1532,6 +1556,7 @@ gtk_socket_changed( void* closure, int oldSock, int newSock ) if ( newSock != -1 ) { gtkListenOnSocket( globals, newSock ); } + globals->cGlobals.socket = newSock; } static void diff --git a/linux/linuxbt.c b/linux/linuxbt.c new file mode 100644 index 000000000..e9214a30f --- /dev/null +++ b/linux/linuxbt.c @@ -0,0 +1,157 @@ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE";-*- */ +/* + * Copyright 2006 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 XWFEATURE_BLUETOOTH + +#include +#include +#include +#include +#include +#include + + +#include "linuxbt.h" +#include "comms.h" + +typedef struct LinBtStuff { + CommonGlobals* globals; + XP_Bool amMaster; +} LinBtStuff; + +static LinBtStuff* +linBtMake( MPFORMAL XP_Bool amMaster ) +{ + LinBtStuff* btStuff = (LinBtStuff*)XP_MALLOC( mpool, sizeof(*btStuff) ); + XP_MEMSET( btStuff, 0, sizeof(*btStuff) ); + + btStuff->amMaster = amMaster; + + return btStuff; +} + +static void +btConnectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP ) +{ + struct sockaddr_l2 saddr; + int sock; + + XP_MEMSET( &saddr, 0, sizeof(saddr) ); + + // allocate a socket + sock = socket( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP ); + if ( sock < 0 ) { + XP_LOGF( "%s: socket->%s", __FUNCTION__, strerror(errno) ); + } else { + + // set the connection parameters (who to connect to) + saddr.l2_family = AF_BLUETOOTH; + saddr.l2_psm = htobs( XW_PSM ); + XP_MEMCPY( &saddr.l2_bdaddr, &addrP->u.bt.btAddr, + sizeof(saddr.l2_bdaddr) ); + // connect to server + if ( 0 == connect( sock, (struct sockaddr *)&saddr, sizeof(saddr) ) ) { + CommonGlobals* globals = btStuff->globals; + (*globals->socketChanged)( globals->socketChangedClosure, + -1, sock ); + } else { + XP_LOGF( "%s: connect->%s", __FUNCTION__, strerror(errno) ); + } + } +} + +void +linux_bt_open( CommonGlobals* globals, XP_Bool amMaster ) +{ + LinBtStuff* btStuff = globals->u.bt.btStuff; + if ( !btStuff ) { + btStuff = globals->u.bt.btStuff + = linBtMake( MPPARM(globals->params->util->mpool) + amMaster ); + btStuff->globals = globals; + globals->u.bt.btStuff = btStuff; + + } +} + +void +linux_bt_close( CommonGlobals* globals ) +{ + LinBtStuff* btStuff = globals->u.bt.btStuff; + if ( !!btStuff ) { + XP_FREE( globals->params->util->mpool, btStuff ); + globals->u.bt.btStuff = NULL; + } +} + +XP_S16 linux_bt_send( const XP_U8* buf, XP_U16 buflen, + const CommsAddrRec* addrP, + CommonGlobals* globals ) +{ + LinBtStuff* btStuff = globals->u.bt.btStuff; + CommsAddrRec addr; + XP_S16 nSent = -1; + + LOG_FUNC(); + + XP_ASSERT( !!btStuff ); + if ( !addrP ) { + comms_getAddr( globals->game.comms, &addr ); + addrP = &addr; + } + + if ( globals->socket < 0 ) { + btConnectSocket( btStuff, addrP ); + } + + if ( globals->socket >= 0 ) { + nSent = write( globals->socket, buf, buflen ); + if ( nSent < 0 ) { + XP_LOGF( "%s: send->%s", __FUNCTION__, strerror(errno) ); + } else if ( nSent < buflen ) { + XP_LOGF( "%s: send only %d bytes of %d", __FUNCTION__, nSent, + buflen ); + } + } else { + XP_LOGF( "%s: socket still not set", __FUNCTION__ ); + } + + LOG_RETURNF( "%d", nSent ); + return nSent; +} + +XP_S16 +linux_bt_receive( CommonGlobals* globals, XP_U8* buf, XP_U16 buflen ) +{ + XP_S16 nRead = 0; + int sock = globals->socket; + LOG_FUNC(); + XP_ASSERT( sock >= 0 ); + + nRead = read( sock, buf, buflen ); + if ( nRead < 0 ) { + XP_LOGF( "%s: read->%s", __FUNCTION__, strerror(errno) ); + } + + LOG_RETURNF( "%d", nRead ); + return nRead; +} + +#endif /* XWFEATURE_BLUETOOTH */ + diff --git a/linux/linuxbt.h b/linux/linuxbt.h new file mode 100644 index 000000000..d2859f86b --- /dev/null +++ b/linux/linuxbt.h @@ -0,0 +1,36 @@ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE";-*- */ +/* + * Copyright 2006 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. + */ +#ifndef _LINUXBT_H_ +#define _LINUXBT_H_ + +#ifdef XWFEATURE_BLUETOOTH + +#include "main.h" + +void linux_bt_open( CommonGlobals* globals, XP_Bool amMaster ); +void linux_bt_close( CommonGlobals* globals ); + +XP_S16 linux_bt_send( const XP_U8* buf, XP_U16 buflen, + const CommsAddrRec* addrRec, + CommonGlobals* globals ); +XP_S16 linux_bt_receive( CommonGlobals* globals, XP_U8* buf, XP_U16 buflen ); + +#endif /* XWFEATURE_BLUETOOTH */ +#endif /* #ifndef _LINUXBT_H_ */ diff --git a/linux/linuxmain.c b/linux/linuxmain.c index eb3d0c095..52e883bbe 100644 --- a/linux/linuxmain.c +++ b/linux/linuxmain.c @@ -1,4 +1,4 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */ /* * Copyright 2000 by Eric House (xwords@eehouse.org). All rights reserved. * @@ -30,7 +30,12 @@ #include #include +#include +#include +#include + #include "linuxmain.h" +#include "linuxbt.h" #include "main.h" #ifdef PLATFORM_NCURSES # include "cursesmain.h" @@ -245,6 +250,8 @@ usage( char* appName, char* msg ) "\t [-p relay_port] # relay is at this port\n" "\t [-a relay_addr] # use relay (via port spec'd above)\n" "" " (default localhost)\n" + "\t [-B n:name|a:00:11:22:33:44:55]\n" + "\t\t\t# connect via bluetooth [param ignored if -s]\n" /* "# --------------- OR client-only ----------\n" */ /* "\t [-p client_port] # must != server's port if on same device" */ "\nexample: \n" @@ -255,18 +262,17 @@ usage( char* appName, char* msg ) exit(1); } -XP_S16 -linux_tcp_send( XP_U8* buf, XP_U16 buflen, +static XP_S16 +linux_tcp_send( const XP_U8* buf, XP_U16 buflen, const CommsAddrRec* XP_UNUSED(addrRec), - void* closure ) + CommonGlobals* globals ) { - CommonGlobals* globals = (CommonGlobals*)closure; XP_S16 result = 0; int socket = globals->socket; if ( socket == -1 ) { XP_STATUSF( "linux_tcp_send: socket uninitialized" ); - socket = linux_init_socket( globals ); + socket = linux_init_relay_socket( globals ); if ( socket != -1 ) { assert( globals->socket == socket ); (*globals->socketChanged)( globals->socketChangedClosure, @@ -297,8 +303,33 @@ linux_tcp_send( XP_U8* buf, XP_U16 buflen, return result; } /* linux_tcp_send */ +XP_S16 +linux_send( const XP_U8* buf, XP_U16 buflen, + const CommsAddrRec* addrRec, + void* closure ) +{ + XP_S16 nSent = -1; + CommonGlobals* globals = (CommonGlobals*)closure; + CommsConnType conType; + + if ( !!addrRec ) { + conType = addrRec->conType; + } else { + conType = globals->params->conType; + } + + if ( conType == COMMS_CONN_RELAY ) { + nSent = linux_tcp_send( buf, buflen, addrRec, globals ); + } else if ( conType == COMMS_CONN_BT ) { + nSent = linux_bt_send( buf, buflen, addrRec, globals ); + } else { + XP_ASSERT(0); + } + return nSent; +} /* linux_send */ + int -linux_init_socket( CommonGlobals* cGlobals ) +linux_init_relay_socket( CommonGlobals* cGlobals ) { struct sockaddr_in to_sock; struct hostent* host; @@ -312,15 +343,17 @@ linux_init_socket( CommonGlobals* cGlobals ) return -1; } - to_sock.sin_port = htons(cGlobals->params->defaultSendPort); + to_sock.sin_port = htons(cGlobals->params-> + connInfo.relay.defaultSendPort ); XP_STATUSF( "1: sending to port %d", - cGlobals->params->defaultSendPort ); - if (( host = gethostbyname(cGlobals->params->relayName) ) == NULL ) { + cGlobals->params->connInfo.relay.defaultSendPort ); + host = gethostbyname( cGlobals->params->connInfo.relay.relayName ); + if ( NULL == host ) { XP_WARNF( "gethostbyname returned -1\n" ); return -1; } else { XP_WARNF( "gethostbyname for %s worked", - cGlobals->defaultServerName ); + cGlobals->u.relay.defaultServerName ); } memcpy( &(to_sock.sin_addr.s_addr), host->h_addr_list[0], sizeof(struct in_addr)); @@ -338,7 +371,7 @@ linux_init_socket( CommonGlobals* cGlobals ) } return sock; -} /* linux_init_socket */ +} /* linux_init_relay_socket */ static void linux_close_socket( CommonGlobals* cGlobals ) @@ -351,7 +384,7 @@ linux_close_socket( CommonGlobals* cGlobals ) } int -linux_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize ) +linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize ) { int sock = cGlobals->socket; unsigned short tmp; @@ -554,11 +587,15 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code ) #ifdef BEYOND_IR static void -linux_util_addrChange( XW_UtilCtxt* XP_UNUSED(uc), +linux_util_addrChange( XW_UtilCtxt* uc, const CommsAddrRec* XP_UNUSED(oldAddr), - const CommsAddrRec* XP_UNUSED(newAddr) ) + const CommsAddrRec* newAddr, + XP_Bool isServer ) { - XP_LOGF( "linux_util_addrChange called; what to do?" ); + if ( newAddr->conType == COMMS_CONN_BT ) { + CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; + linux_bt_open( cGlobals, isServer ); + } } #endif @@ -574,6 +611,40 @@ defaultRandomSeed() return rs; } /* defaultRandomSeed */ +/* This belongs in linuxbt.c */ +static XP_Bool +nameToBtAddr( const char* name, bdaddr_t* ba ) +{ + XP_Bool success = XP_FALSE; + int id, socket; + LOG_FUNC(); +# define RESPMAX 5 + + id = hci_get_route( NULL ); + socket = hci_open_dev( id ); + if ( id >= 0 && socket >= 0 ) { + long flags = 0L; + inquiry_info inqInfo[RESPMAX]; + inquiry_info* inqInfoP = inqInfo; + int count = hci_inquiry( id, 10, RESPMAX, NULL, &inqInfoP, flags ); + int i; + + for ( i = 0; i < count; ++i ) { + char buf[64]; + if ( 0 >= hci_read_remote_name( socket, &inqInfo[i].bdaddr, + sizeof(buf), buf, 0)) { + if ( 0 == strcmp( buf, name ) ) { + XP_MEMCPY( ba, &inqInfo[i].bdaddr, sizeof(*ba) ); + success = XP_TRUE; + XP_LOGF( "%s: matched %s", __FUNCTION__, name ); + break; + } + } + } + } + return success; +} /* nameToBtAddr */ + int main( int argc, char** argv ) { @@ -586,6 +657,9 @@ main( int argc, char** argv ) unsigned int seed = defaultRandomSeed(); LaunchParams mainParams; XP_U16 robotCount = 0; + + CommsConnType conType = COMMS_CONN_UNUSED; + const char* btaddr = NULL; #ifdef DEBUG { @@ -611,9 +685,9 @@ main( int argc, char** argv ) /* (void)fgetc( stdin ); */ /* defaults */ - mainParams.defaultListenPort = DEFAULT_LISTEN_PORT; - mainParams.defaultSendPort = DEFAULT_SEND_PORT; - mainParams.cookie = "COOKIE"; + mainParams.connInfo.relay.defaultListenPort = DEFAULT_LISTEN_PORT; + mainParams.connInfo.relay.defaultSendPort = DEFAULT_SEND_PORT; + mainParams.connInfo.relay.cookie = "COOKIE"; mainParams.gi.boardSize = 15; mainParams.quitAfter = XP_FALSE; mainParams.sleepOnAnchor = XP_FALSE; @@ -645,7 +719,7 @@ main( int argc, char** argv ) #if defined PLATFORM_GTK "h:" #endif - "kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:HUmvcC:" ); + "kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:HUmvcC:B:" ); switch( opt ) { case '?': usage(argv[0], NULL); @@ -654,7 +728,10 @@ main( int argc, char** argv ) mainParams.showRobotScores = XP_TRUE; break; case 'C': - mainParams.cookie = optarg; + XP_ASSERT( conType == COMMS_CONN_UNUSED || + conType == COMMS_CONN_RELAY ); + mainParams.connInfo.relay.cookie = optarg; + conType = COMMS_CONN_RELAY; break; case 'd': mainParams.gi.dictName = copyString( MPPARM(mainParams.util->mpool) @@ -694,6 +771,9 @@ main( int argc, char** argv ) break; case 'p': sendPortNumString = optarg; + XP_ASSERT( conType == COMMS_CONN_UNUSED || + conType == COMMS_CONN_RELAY ); + conType = COMMS_CONN_RELAY; break; case 'r': ++robotCount; @@ -722,6 +802,9 @@ main( int argc, char** argv ) break; case 'a': /* mainParams.info.clientInfo.serverName = */ + XP_ASSERT( conType == COMMS_CONN_UNUSED || + conType == COMMS_CONN_RELAY ); + conType = COMMS_CONN_RELAY; relayName = optarg; break; case 'q': @@ -730,6 +813,12 @@ main( int argc, char** argv ) case 'b': mainParams.gi.boardSize = atoi(optarg); break; + case 'B': + XP_ASSERT( conType == COMMS_CONN_UNUSED || + conType == COMMS_CONN_BT ); + conType = COMMS_CONN_BT; + btaddr = optarg; + break; case 'v': mainParams.verticalScore = XP_TRUE; break; @@ -766,11 +855,6 @@ main( int argc, char** argv ) mainParams.gi.serverRole = SERVER_ISCLIENT; } - /* convert strings to whatever */ - if ( sendPortNumString != NULL ) { - mainParams.defaultSendPort = atoi( sendPortNumString ); - } - /* sanity checks */ totalPlayerCount = mainParams.nLocalPlayers + mainParams.info.serverInfo.nRemotePlayers; @@ -803,7 +887,38 @@ main( int argc, char** argv ) } } - mainParams.relayName = relayName; + if ( conType == COMMS_CONN_RELAY ) { + mainParams.connInfo.relay.relayName = relayName; + + /* convert strings to whatever */ + if ( sendPortNumString != NULL ) { + mainParams.connInfo.relay.defaultSendPort = + atoi( sendPortNumString ); + } + } else if ( conType == COMMS_CONN_BT ) { + bdaddr_t ba; + XP_Bool success = XP_FALSE; + XP_ASSERT( btaddr ); + if ( btaddr[1] == ':' ) { + if ( btaddr[0] == 'n' ) { + if ( !nameToBtAddr( btaddr+2, &ba ) ) { + fprintf( stderr, "fatal error: unable to find device %s\n", + btaddr + 2 ); + exit(0); + } + success = XP_TRUE; + } else if ( btaddr[0] == 'a' ) { + success = 0 == str2ba( &btaddr[2], &ba ); + XP_ASSERT( success ); + } + } + if ( !success ) { + usage( argv[0], "bad format for -B param" ); + } + XP_MEMCPY( &mainParams.connInfo.bt.hostAddr, &ba, + sizeof(mainParams.connInfo.bt.hostAddr) ); + } + mainParams.conType = conType; /* mainParams.pipe = linuxCommPipeCtxtMake( isServer ); */ diff --git a/linux/linuxmain.h b/linux/linuxmain.h index ac47944df..41b6eca50 100644 --- a/linux/linuxmain.h +++ b/linux/linuxmain.h @@ -37,10 +37,11 @@ typedef struct LinuxBMStruct { DictionaryCtxt* linux_dictionary_make( MPFORMAL const char* dictFileName ); int initListenerSocket( int port ); -XP_S16 linux_tcp_send( XP_U8* buf, XP_U16 buflen, const CommsAddrRec* addrRec, - void* closure ); -int linux_init_socket( CommonGlobals* cGlobals ); -int linux_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize ); +XP_S16 linux_send( const XP_U8* buf, XP_U16 buflen, + const CommsAddrRec* addrRec, void* closure ); +int linux_init_relay_socket( CommonGlobals* cGlobals ); +int linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf, + int bufSize ); void linuxFireTimer( CommonGlobals* cGlobals, XWTimerReason why ); diff --git a/linux/main.h b/linux/main.h index 1ca8a472e..bee095ca2 100644 --- a/linux/main.h +++ b/linux/main.h @@ -20,6 +20,8 @@ #ifndef _MAIN_H_ #define _MAIN_H_ +#include /* for bdaddr_t, which should move */ + #include "comtypes.h" #include "util.h" #include "game.h" @@ -43,7 +45,6 @@ typedef struct LaunchParams { DictionaryCtxt* dict; CurGameInfo gi; char* fileName; - char* cookie; VTableMgr* vtMgr; XP_U16 nLocalPlayers; XP_U16 nHidden; @@ -60,15 +61,24 @@ typedef struct LaunchParams { Connectedness serverRole; - char* relayName; + CommsConnType conType; + union { + struct { + char* relayName; + char* cookie; + short defaultSendPort; + short defaultListenPort; + } relay; + struct { + bdaddr_t hostAddr; /* unused if a host */ + } bt; + } connInfo; + union { ServerInfo serverInfo; ClientInfo clientInfo; } info; - short defaultSendPort; - short defaultListenPort; - } LaunchParams; typedef void (*SocketChangedFunc)(void* closure, int oldsock, int newsock ); @@ -78,14 +88,25 @@ typedef struct CommonGlobals { XWGame game; XP_U16 lastNTilesToUse; - /* UDP comms stuff */ - char* defaultServerName; - int socket; + SocketChangedFunc socketChanged; void* socketChangedClosure; + int socket; /* either relay or bt */ + + union { + struct { + char* defaultServerName; + } relay; + struct { + struct LinBtStuff* btStuff; + } bt; + } u; + TimerProc timerProcs[NUM_TIMERS_PLUS_ONE]; void* timerClosures[NUM_TIMERS_PLUS_ONE]; + + MPSLOT } CommonGlobals; #endif