Attempt to listen for connections on a separate thread so connected

game could disconnect and reconnect, but still need work on adding a
socket to the main thread's io queue from a different thread.
This commit is contained in:
ehouse 2006-09-08 07:23:19 +00:00
parent 2c5d15a8dd
commit c27abcd486
5 changed files with 232 additions and 81 deletions

View file

@ -92,7 +92,7 @@ OBJ = $(PLATFORM)/linuxmain.o \
# $(PLATFORM)/linuxcommpipe.o \
LIBS = -lm -lbluetooth -L $(HOME)/usr/local/pilot/lib $(GPROFFLAG)
LIBS = -pthread -lm -lbluetooth -L $(HOME)/usr/local/pilot/lib $(GPROFFLAG)
ifneq (,$(findstring DPLATFORM_GTK,$(DEFINES)))
LIBS += `pkg-config --libs gtk+-2.0`

View file

@ -1467,21 +1467,29 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
util->closure = globals;
} /* setupGtkUtilCallbacks */
static gboolean
newConnectionInput( GIOChannel *source,
GIOCondition condition,
gpointer data )
{
gboolean keepSource;
int sock = g_io_channel_unix_get_fd( source );
GtkAppGlobals* globals = (GtkAppGlobals*)data;
XP_ASSERT( sock == globals->cGlobals.socket );
XP_LOGF( "%s:condition = 0x%x", __FUNCTION__, (int)condition );
if ( (condition & G_IO_HUP) != 0 ) {
/* XP_ASSERT( sock == globals->cGlobals.socket ); */
if ( (condition & (G_IO_HUP | G_IO_ERR)) != 0 ) {
XP_LOGF( "dropping socket %d", sock );
close( sock );
globals->cGlobals.socket = -1;
return FALSE; /* remove the event source */
#ifdef XWFEATURE_BLUETOOTH
if ( COMMS_CONN_BT == globals->cGlobals.params->conType ) {
linux_bt_socketclosed( &globals->cGlobals, sock );
}
#endif
keepSource = FALSE; /* remove the event source */
} else if ( (condition & G_IO_IN) != 0 ) {
ssize_t nRead;
@ -1491,7 +1499,7 @@ newConnectionInput( GIOChannel *source,
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) );
nRead = linux_bt_receive( sock, buf, sizeof(buf) );
} else {
XP_ASSERT( 0 );
}
@ -1526,8 +1534,9 @@ newConnectionInput( GIOChannel *source,
} else {
XP_LOGF( "errno from read: %d", errno );
}
keepSource = TRUE;
}
return TRUE; /* FALSE means to remove event source */
return keepSource; /* FALSE means to remove event source */
} /* newConnectionInput */
/* Make gtk listen for events on the socket that clients will use to
@ -1536,19 +1545,20 @@ newConnectionInput( GIOChannel *source,
static void
gtkListenOnSocket( GtkAppGlobals* globals, int newSock )
{
GIOChannel* channel = g_io_channel_unix_new( newSock );
guint result = g_io_add_watch( channel,
G_IO_IN | G_IO_HUP,
G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_PRI,
newConnectionInput,
globals );
XP_LOGF( "g_io_add_watch => %d", result );
XP_LOGF( "g_io_add_watch(%d) => %d", newSock, result );
} /* gtkListenOnSocket */
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" );

View file

@ -26,28 +26,99 @@
#include <bluetooth/bluetooth.h>
#include <bluetooth/l2cap.h>
/* #define XW_USE_THREADS */
#ifdef XW_USE_THREADS
# include <pthread.h>
#endif
#include "linuxbt.h"
#include "comms.h"
#define MAX_CLIENTS 3
typedef struct BtaddrSockMap {
bdaddr_t btaddr;
int sock;
} BtaddrSockMap;
typedef struct LinBtStuff {
CommonGlobals* globals;
int listener; /* socket */
union {
struct {
#ifdef XW_USE_THREADS
pthread_t acceptThread;
#endif
BtaddrSockMap socks[MAX_CLIENTS];
XP_U16 nSocks;
XP_Bool threadDie;
} master;
} u;
XP_Bool amMaster;
} LinBtStuff;
static void
lbt_addSock( LinBtStuff* btStuff, const bdaddr_t* btaddr, int sock )
{
XP_U16 i;
XP_ASSERT( btStuff->amMaster );
XP_ASSERT( btStuff->u.master.nSocks < MAX_CLIENTS - 1 );
for ( i = 0; i < MAX_CLIENTS; ++i ) {
BtaddrSockMap* mp = &btStuff->u.master.socks[i];
if ( mp->sock == -1 ) {
XP_MEMCPY( &mp->btaddr, btaddr, sizeof(mp->btaddr) );
mp->sock = sock;
++btStuff->u.master.nSocks;
break;
}
}
XP_ASSERT( i < MAX_CLIENTS );
} /* lbt_addSock */
static void
lbt_removeSock( LinBtStuff* btStuff, int sock )
{
XP_U16 i;
XP_ASSERT( btStuff->amMaster );
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;
--btStuff->u.master.nSocks;
break;
}
}
XP_ASSERT( i < MAX_CLIENTS );
} /* lbt_addSock */
static LinBtStuff*
linBtMake( MPFORMAL XP_Bool amMaster )
lbt_make( MPFORMAL XP_Bool amMaster )
{
LinBtStuff* btStuff = (LinBtStuff*)XP_MALLOC( mpool, sizeof(*btStuff) );
XP_MEMSET( btStuff, 0, sizeof(*btStuff) );
btStuff->amMaster = amMaster;
if ( amMaster ) {
XP_U16 i;
for ( i = 0; i < MAX_CLIENTS; ++i ) {
btStuff->u.master.socks[i].sock = -1;
}
}
return btStuff;
}
} /* lbt_make */
static void
btConnectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
lbt_connectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
{
struct sockaddr_l2 saddr;
int sock;
@ -74,37 +145,80 @@ btConnectSocket( LinBtStuff* btStuff, const CommsAddrRec* addrP )
XP_LOGF( "%s: connect->%s", __FUNCTION__, strerror(errno) );
}
}
} /* btConnectSocket */
} /* lbt_connectSocket */
static void
btWaitConnection( CommonGlobals* globals )
waitForOne( LinBtStuff* btStuff )
{
struct sockaddr_l2 saddr;
int sock;
struct sockaddr_l2 inaddr;
int listener, sock;
socklen_t slen;
listener = socket( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP );
// accept one connection
XP_LOGF( "%s: blocking on accept", __FUNCTION__ );
slen = sizeof( inaddr );
sock = accept( btStuff->listener, (struct sockaddr *)&inaddr, &slen );
XP_LOGF( "%s: accept returned; sock = %d", __FUNCTION__, sock );
{
char buf[18];
(void)ba2str( &inaddr.l2_bdaddr, buf );
XP_LOGF( "got connection from %s", buf );
}
if ( sock >= 0 ) {
CommonGlobals* globals = btStuff->globals;
lbt_addSock( btStuff, &inaddr.l2_bdaddr, sock );
(*globals->socketChanged)( globals->socketChangedClosure,
-1, sock );
} else {
XP_LOGF( "%s: accept failed with %s", __FUNCTION__,
strerror(errno) );
}
} /* waitForOne */
#ifdef XW_USE_THREADS
static void*
lbt_acceptThreadProc( void* arg )
{
CommonGlobals* globals = (CommonGlobals*)arg;
LinBtStuff* btStuff = globals->u.bt.btStuff;
while ( !btStuff->u.master.threadDie ) {
waitForOne( btStuff );
}
LOG_RETURN_VOID();
return NULL;
} /* acceptThreadProc */
#endif
static void
lbt_waitConnection( CommonGlobals* globals )
{
LinBtStuff* btStuff = globals->u.bt.btStuff;
struct sockaddr_l2 saddr;
btStuff->listener = socket( AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP );
XP_MEMSET( &saddr, 0, sizeof(saddr) );
saddr.l2_family = AF_BLUETOOTH;
saddr.l2_bdaddr = *BDADDR_ANY;
saddr.l2_psm = htobs( XW_PSM );
bind( btStuff->listener, (struct sockaddr *)&saddr, sizeof(saddr) );
bind( listener, (struct sockaddr *)&saddr, sizeof(saddr) );
listen( btStuff->listener, MAX_CLIENTS );
listen( listener, 3 ); /* eventually can accept up to 3 -- piconet */
// accept one connection
XP_LOGF( "%s: blocking on accept", __FUNCTION__ );
slen = sizeof( inaddr );
sock = accept( listener, (struct sockaddr *)&inaddr, &slen );
XP_LOGF( "%s: accept returned", __FUNCTION__ );
close( listener );
(*globals->socketChanged)( globals->socketChangedClosure,
-1, sock );
#ifdef XW_USE_THREADS
int pthread_err;
btStuff->u.master.threadDie = XP_FALSE;
pthread_err = pthread_create( &btStuff->u.master.acceptThread,
NULL, lbt_acceptThreadProc, globals );
XP_ASSERT( 0 == pthread_err );
pthread_detach( btStuff->u.master.acceptThread );
#else
waitForOne( btStuff );
#endif
}
void
@ -113,69 +227,81 @@ 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 );
= lbt_make( MPPARM(globals->params->util->mpool) amMaster );
btStuff->globals = globals;
globals->u.bt.btStuff = btStuff;
}
if ( amMaster ) {
btWaitConnection( globals );
if ( amMaster ) {
lbt_waitConnection( globals );
}
}
}
} /* linux_bt_open */
void
linux_bt_close( CommonGlobals* globals )
{
LinBtStuff* btStuff = globals->u.bt.btStuff;
if ( !!btStuff ) {
if ( btStuff->amMaster ) {
#ifdef XW_USE_THREADS
int ret;
btStuff->u.master.threadDie = XP_TRUE;
ret = pthread_join( btStuff->u.master.acceptThread, NULL );
if ( 0 != ret ) {
XP_LOGF( "pthread_join=>%s", strerror(errno) );
}
#endif
close( btStuff->listener );
}
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;
}
} /* linux_bt_close */
XP_S16
linux_bt_receive( CommonGlobals* globals, XP_U8* buf, XP_U16 buflen )
linux_bt_send( const XP_U8* buf, XP_U16 buflen,
const CommsAddrRec* addrP,
CommonGlobals* globals )
{
XP_S16 nSent = -1;
LinBtStuff* btStuff = globals->u.bt.btStuff;
if ( !!btStuff ) {
CommsAddrRec addr;
LOG_FUNC();
XP_ASSERT( !!btStuff );
if ( !addrP ) {
comms_getAddr( globals->game.comms, &addr );
addrP = &addr;
}
if ( globals->socket < 0 ) {
lbt_connectSocket( 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;
} /* linux_bt_send */
XP_S16
linux_bt_receive( int sock, XP_U8* buf, XP_U16 buflen )
{
XP_S16 nRead = 0;
int sock = globals->socket;
LOG_FUNC();
XP_ASSERT( sock >= 0 );
@ -188,5 +314,12 @@ linux_bt_receive( CommonGlobals* globals, XP_U8* buf, XP_U16 buflen )
return nRead;
}
void
linux_bt_socketclosed( CommonGlobals* globals, int sock )
{
LinBtStuff* btStuff = globals->u.bt.btStuff;
lbt_removeSock( btStuff, sock );
}
#endif /* XWFEATURE_BLUETOOTH */

View file

@ -30,7 +30,9 @@ 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 );
XP_S16 linux_bt_receive( int sock, XP_U8* buf, XP_U16 buflen );
void linux_bt_socketclosed( CommonGlobals* globals, int sock );
#endif /* XWFEATURE_BLUETOOTH */
#endif /* #ifndef _LINUXBT_H_ */

View file

@ -34,6 +34,8 @@
#include <bluetooth/hci.h>
#include <bluetooth/hci_lib.h>
#include <pthread.h>
#include "linuxmain.h"
#include "linuxbt.h"
#include "main.h"
@ -64,11 +66,13 @@ linux_debugf( char* format, ... )
struct tm* timp;
struct timeval tv;
struct timezone tz;
pthread_t me = pthread_self();
gettimeofday( &tv, &tz );
timp = localtime( &tv.tv_sec );
sprintf( buf, "%d:%d:%d: ", timp->tm_hour, timp->tm_min, timp->tm_sec );
sprintf( buf, "<%p>%d:%d:%d: ", (void*)me,
timp->tm_hour, timp->tm_min, timp->tm_sec );
va_start(ap, format);
@ -321,6 +325,8 @@ linux_send( const XP_U8* buf, XP_U16 buflen,
if ( conType == COMMS_CONN_RELAY ) {
nSent = linux_tcp_send( buf, buflen, addrRec, globals );
} else if ( conType == COMMS_CONN_BT ) {
XP_Bool isServer = comms_getIsServer( globals->game.comms );
linux_bt_open( globals, isServer );
nSent = linux_bt_send( buf, buflen, addrRec, globals );
} else {
XP_ASSERT(0);
@ -589,11 +595,11 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code )
static void
linux_util_addrChange( XW_UtilCtxt* uc,
const CommsAddrRec* XP_UNUSED(oldAddr),
const CommsAddrRec* newAddr,
XP_Bool isServer )
const CommsAddrRec* newAddr )
{
if ( newAddr->conType == COMMS_CONN_BT ) {
CommonGlobals* cGlobals = (CommonGlobals*)uc->closure;
XP_Bool isServer = comms_getIsServer( cGlobals->game.comms );
linux_bt_open( cGlobals, isServer );
}
}