From c27abcd4861d16c1c949ef5b9addfe2df00887d5 Mon Sep 17 00:00:00 2001 From: ehouse Date: Fri, 8 Sep 2006 07:23:19 +0000 Subject: [PATCH] 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. --- xwords4/linux/Makefile | 2 +- xwords4/linux/gtkmain.c | 28 ++-- xwords4/linux/linuxbt.c | 267 ++++++++++++++++++++++++++++---------- xwords4/linux/linuxbt.h | 4 +- xwords4/linux/linuxmain.c | 12 +- 5 files changed, 232 insertions(+), 81 deletions(-) diff --git a/xwords4/linux/Makefile b/xwords4/linux/Makefile index c4943f004..e49265483 100644 --- a/xwords4/linux/Makefile +++ b/xwords4/linux/Makefile @@ -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` diff --git a/xwords4/linux/gtkmain.c b/xwords4/linux/gtkmain.c index 143fbbc36..c63f79c6d 100644 --- a/xwords4/linux/gtkmain.c +++ b/xwords4/linux/gtkmain.c @@ -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" ); diff --git a/xwords4/linux/linuxbt.c b/xwords4/linux/linuxbt.c index 28eab8471..b6f485c99 100644 --- a/xwords4/linux/linuxbt.c +++ b/xwords4/linux/linuxbt.c @@ -26,28 +26,99 @@ #include #include +/* #define XW_USE_THREADS */ +#ifdef XW_USE_THREADS +# include +#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 */ diff --git a/xwords4/linux/linuxbt.h b/xwords4/linux/linuxbt.h index d2859f86b..a80fe359c 100644 --- a/xwords4/linux/linuxbt.h +++ b/xwords4/linux/linuxbt.h @@ -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_ */ diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 8d5767ce4..2bf093846 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -34,6 +34,8 @@ #include #include +#include + #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 ); } }