diff --git a/linux/cursesmain.c b/linux/cursesmain.c index 78e14ecbc..f0a4a1a90 100644 --- a/linux/cursesmain.c +++ b/linux/cursesmain.c @@ -83,16 +83,6 @@ cursesUserError( CursesAppGlobals* globals, char* format, ... ) va_end(ap); } /* cursesUserError */ -static void -curses_util_listenPortChange( XW_UtilCtxt* uc, XP_U16 newPort ) -{ - CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure; - XP_LOGF( "listenPortChange called: not sure what to do" ); - - /* if this isn't true, need to tear down and rebind socket */ - XP_ASSERT( newPort == globals->cGlobals.params->defaultListenPort ); -} /* curses_util_listenPortChange */ - static XP_S16 curses_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi, XP_U16 playerNum, const XP_UCHAR4* texts, XP_U16 nTiles ) @@ -598,13 +588,40 @@ cursesListenOnSocket( CursesAppGlobals* globals, int newSock, globals->fdArray[globals->fdCount].fd = newSock; globals->fdArray[globals->fdCount].events = POLLIN; - globals->streams[globals->fdCount] = stream; - ++globals->fdCount; XP_LOGF( "listenOnSocket: there are now %d sources to poll", globals->fdCount ); } /* cursesListenOnSocket */ +static void +curses_stop_listening( CursesAppGlobals* globals, int sock ) +{ + int count = globals->fdCount; + int i, found = 0; + + for ( i = 0; i < count; ++i ) { + if ( globals->fdArray[i].fd == sock ) { + found = 1; + } else if ( found ) { + globals->fdArray[i-1].fd = globals->fdArray[i].fd; + } + } + + assert( found ); + --globals->fdCount; +} /* curses_stop_listening */ + +static void +curses_socket_changed( void* closure, int oldSock, int newSock ) +{ + CursesAppGlobals* globals = (CursesAppGlobals*)closure; + if ( oldSock != -1 ) { + curses_stop_listening( globals, oldSock ); + } + if ( newSock != -1 ) { + cursesListenOnSocket( globals, newSock, NULL ); + } +} /* curses_socket_changed */ /* * Ok, so this doesn't block yet.... @@ -661,17 +678,18 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch ) CommsAddrRec addrRec; XP_MEMSET( &addrRec, 0, sizeof(addrRec) ); - addrRec.conType = COMMS_CONN_IP; + addrRec.conType = COMMS_CONN_RELAY; - addrRec.u.ip.ipAddr = ntohl(addr_sock.sin_addr.s_addr); + addrRec.u.ip_relay.ipAddr = + ntohl(addr_sock.sin_addr.s_addr); XP_LOGF( "captured incomming ip address: 0x%lx", - addrRec.u.ip.ipAddr ); + addrRec.u.ip_relay.ipAddr ); if ( comms_checkIncomingStream(globals->cGlobals.game.comms, inboundS, &addrRec ) ) { XP_LOGF( "comms read port: %d", - addrRec.u.ip.port ); + addrRec.u.ip_relay.port ); redraw = server_receiveMessage( globals->cGlobals.game.server, inboundS ); @@ -777,7 +795,7 @@ cursesSendOnClose( XWStreamCtxt* stream, void* closure ) CursesAppGlobals* globals = (CursesAppGlobals*)closure; XP_LOGF( "cursesSendOnClose called" ); - result = comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream ); + result = comms_send( globals->cGlobals.game.comms, stream ); } /* cursesSendOnClose */ static XWStreamCtxt* @@ -814,8 +832,6 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util ) util->vtable->m_util_setTimer = curses_util_setTimer; util->vtable->m_util_requestTime = curses_util_requestTime; - util->vtable->m_util_listenPortChange = curses_util_listenPortChange; - util->closure = globals; } /* setupCursesUtilCallbacks */ @@ -825,7 +841,7 @@ sendOnClose( XWStreamCtxt* stream, void* closure ) CursesAppGlobals* globals = closure; XP_LOGF( "curses sendOnClose called" ); XP_ASSERT( !!globals->cGlobals.game.comms ); - comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream ); + comms_send( globals->cGlobals.game.comms, stream ); } /* sendOnClose */ static XP_Bool @@ -858,7 +874,6 @@ void cursesmain( XP_Bool isServer, LaunchParams* params ) { int piperesult; - int sock; DictionaryCtxt* dict; CommsAddrRec addr; XP_U16 gameID; @@ -869,6 +884,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) globals.cGlobals.params = params; globals.cGlobals.socket = -1; + globals.cGlobals.socketChanged = curses_socket_changed; + globals.cGlobals.socketChangedClosure = &globals; + globals.cp.showBoardArrow = XP_TRUE; globals.cp.showRobotScores = params->showRobotScores; @@ -883,11 +901,8 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) piperesult = pipe( globals.timepipe ); XP_ASSERT( piperesult == 0 ); - cursesListenOnSocket( &globals, globals.timepipe[0], NULL ); /* reader pipe */ - - sock = linux_init_socket( &globals.cGlobals ); - cursesListenOnSocket( &globals, sock, NULL ); - + /* reader pipe */ + cursesListenOnSocket( &globals, globals.timepipe[0], NULL ); signal( SIGWINCH, SIGWINCH_handler ); initCurses( &globals ); @@ -898,11 +913,14 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) params->util, (DrawCtx*)globals.draw, gameID, &globals.cp, linux_tcp_send, &globals ); - addr.conType = COMMS_CONN_IP; - addr.u.ip.ipAddr = 0; /* ??? */ - addr.u.ip.port = params->defaultSendPort; - comms_setAddr( globals.cGlobals.game.comms, - &addr, params->defaultListenPort ); + 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 ); + comms_setAddr( globals.cGlobals.game.comms, &addr ); model_setDictionary( globals.cGlobals.game.model, params->dict ); @@ -926,12 +944,6 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) &globals, (XP_PlayerAddr)0, sendOnClose ) ); -#if 0 - cursesListenOnSocket( - &globals, NULL, /* replaces below */ - /* linux_getStreamSocket( params->info.clientInfo.stream ), */ - params->info.clientInfo.stream ); -#endif } else { cursesUserError( &globals, "Unable to open connection to server"); exit( 0 ); diff --git a/linux/cursesmain.h b/linux/cursesmain.h index 9e640b5df..c76f5e883 100644 --- a/linux/cursesmain.h +++ b/linux/cursesmain.h @@ -95,7 +95,6 @@ struct CursesAppGlobals { struct sockaddr_in listenerSockAddr; short fdCount; struct pollfd fdArray[FD_MAX]; /* one for stdio, one for listening socket */ - XWStreamCtxt* streams[FD_MAX]; /* [0], for stdin, will be null.... */ int timepipe[2]; /* for reading/writing "user events" */ }; diff --git a/linux/gtkmain.c b/linux/gtkmain.c index e41cc190d..19cc4a8ae 100644 --- a/linux/gtkmain.c +++ b/linux/gtkmain.c @@ -249,9 +249,11 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget ) stream_destroy( stream ); } else { /* not reading from a saved file */ - XP_U16 gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util ); + XP_U16 gameID; CommsAddrRec addr; + gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util ); + XP_ASSERT( !!params->relayName ); globals->cGlobals.defaultServerName = params->relayName; @@ -262,11 +264,16 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget ) params->util, (DrawCtx*)globals->draw, gameID, &globals->cp, linux_tcp_send, globals ); - addr.conType = COMMS_CONN_IP; - addr.u.ip.ipAddr = 0; /* ??? */ - addr.u.ip.port = params->defaultSendPort; - comms_setAddr( globals->cGlobals.game.comms, - &addr, params->defaultListenPort ); + 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 ); + + /* This may trigger network activity */ + comms_setAddr( globals->cGlobals.game.comms, &addr ); model_setDictionary( globals->cGlobals.game.model, params->dict ); @@ -1141,18 +1148,6 @@ gtk_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo ) return stream; } /* gtk_util_makeStreamFromAddr */ -static void -gtk_util_listenPortChange( XW_UtilCtxt* uc, XP_U16 newPort ) -{ -#ifdef DEBUG - GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure; -#endif - XP_LOGF( "listenPortChange called: not sure what to do" ); - - /* if this isn't true, need to tear down and rebind socket */ - XP_ASSERT( newPort == globals->cGlobals.params->defaultListenPort ); -} /* gtk_util_listenPortChange */ - #ifdef XWFEATURE_SEARCHLIMIT static XP_Bool gtk_util_getTraySearchLimits( XW_UtilCtxt* uc, XP_U16* min, XP_U16* max ) @@ -1244,24 +1239,24 @@ makeShowButtonFromBitmap( GtkAppGlobals* globals, GtkWidget* parent, GtkStyle *style; if ( file_exists( fileName ) ) { - button = gtk_button_new(); + button = gtk_button_new(); - style = gtk_widget_get_style(parent); + style = gtk_widget_get_style(parent); - pixmap = gdk_pixmap_create_from_xpm( parent->window, &mask, - &style->bg[GTK_STATE_NORMAL], - fileName ); - pixmapWid = gtk_pixmap_new( pixmap, mask ); - gtk_container_add( GTK_CONTAINER(button), pixmapWid ); + pixmap = gdk_pixmap_create_from_xpm( parent->window, &mask, + &style->bg[GTK_STATE_NORMAL], + fileName ); + pixmapWid = gtk_pixmap_new( pixmap, mask ); + gtk_container_add( GTK_CONTAINER(button), pixmapWid ); - gtk_widget_show( pixmapWid ); + gtk_widget_show( pixmapWid ); } else { - button = gtk_button_new_with_label( alt ); + button = gtk_button_new_with_label( alt ); } gtk_widget_show( button ); if ( func != NULL ) { - gtk_signal_connect( GTK_OBJECT(button), "clicked", func, globals ); + gtk_signal_connect( GTK_OBJECT(button), "clicked", func, globals ); } return button; @@ -1394,10 +1389,6 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util ) util->vtable->m_util_getTraySearchLimits = gtk_util_getTraySearchLimits; #endif -#ifdef BEYOND_IR - util->vtable->m_util_listenPortChange = gtk_util_listenPortChange; -#endif - util->closure = globals; } /* setupGtkUtilCallbacks */ @@ -1430,7 +1421,7 @@ newConnectionInput( GIOChannel *source, inboundS = stream_from_msgbuf( &globals->cGlobals, buf, nRead ); if ( !!inboundS ) { if ( comms_checkIncomingStream( globals->cGlobals.game.comms, - inboundS, NULL ) ) { + inboundS, NULL ) ) { redraw = server_receiveMessage(globals->cGlobals.game.server , inboundS ); } @@ -1470,6 +1461,19 @@ gtkListenOnSocket( GtkAppGlobals* globals, int newSock ) XP_LOGF( "g_io_add_watch => %d", result ); } /* gtkListenOnSocket */ +static void +gtk_socket_changed( void* closure, int oldSock, int newSock ) +{ + GtkAppGlobals* globals = (GtkAppGlobals*)closure; + if ( oldSock != -1 ) { + g_source_remove( oldSock ); + XP_LOGF( "Removed %d from gtk's list of listened-to sockets" ); + } + if ( newSock != -1 ) { + gtkListenOnSocket( globals, newSock ); + } +} + static void sendOnClose( XWStreamCtxt* stream, void* closure ) { @@ -1477,7 +1481,7 @@ sendOnClose( XWStreamCtxt* stream, void* closure ) GtkAppGlobals* globals = closure; XP_LOGF( "sendOnClose called" ); - result = comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream ); + result = comms_send( globals->cGlobals.game.comms, stream ); } /* sendOnClose */ static void @@ -1507,6 +1511,9 @@ gtkmain( XP_Bool isServer, LaunchParams* params, int argc, char *argv[] ) globals.cGlobals.lastNTilesToUse = MAX_TRAY_TILES; globals.cGlobals.socket = -1; + globals.cGlobals.socketChanged = gtk_socket_changed; + globals.cGlobals.socketChangedClosure = &globals; + globals.cp.showBoardArrow = XP_TRUE; globals.cp.showRobotScores = params->showRobotScores; diff --git a/linux/linuxmain.c b/linux/linuxmain.c index 28c28b6b7..dbd98e857 100644 --- a/linux/linuxmain.c +++ b/linux/linuxmain.c @@ -197,6 +197,7 @@ usage( char* appName, char* msg ) "\t [-v] # put scoreboard in vertical mode\n" "\t [-m] # make the robot duMb (smart is default)\n" "\t [-c] # explain robot scores after each move\n" + "\t [-C COOKIE] # cookie used to groups games on relay\n" "\t\t # (max of four players total, local and remote)\n" "\t [-b boardSize] # number of columns and rows\n" "\t [-e random_seed] \n" @@ -228,12 +229,29 @@ linux_tcp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec, if ( socket == -1 ) { XP_STATUSF( "linux_tcp_send: socket uninitialized" ); - } else { + socket = linux_init_socket( globals ); + if ( socket != -1 ) { + assert( globals->socket == socket ); + (*globals->socketChanged)( globals->socketChangedClosure, + -1, socket ); + } + } + + if ( socket != -1 ) { XP_U16 netLen = htons( buflen ); errno = 0; - (void)send( socket, &netLen, sizeof(netLen), 0 ); - result = send( socket, buf, buflen, 0 ); + result = send( socket, &netLen, sizeof(netLen), 0 ); + if ( result == sizeof(netLen) ) { + result = send( socket, buf, buflen, 0 ); + } + if ( result <= 0 ) { + XP_STATUSF( "closing non-functional socket" ); + close( socket ); + (*globals->socketChanged)( globals->socketChangedClosure, + socket, -1 ); + globals->socket = -1; + } XP_STATUSF( "linux_tcp_send: send returned %d of %d (err=%d)", result, buflen, errno ); @@ -512,6 +530,7 @@ main( int argc, char** argv ) mainParams.defaultListenPort = DEFAULT_LISTEN_PORT; mainParams.defaultSendPort = DEFAULT_SEND_PORT; mainParams.trayOverlaps = XP_FALSE; + mainParams.cookie = "COOKIE"; mainParams.gi.boardSize = 15; mainParams.quitAfter = XP_FALSE; mainParams.sleepOnAnchor = XP_FALSE; @@ -519,6 +538,7 @@ main( int argc, char** argv ) mainParams.undoWhenDone = XP_FALSE; mainParams.gi.timerEnabled = XP_FALSE; mainParams.gi.robotSmartness = SMART_ROBOT; + /* serverName = mainParams.info.clientInfo.serverName = "localhost"; */ #if defined PLATFORM_GTK @@ -540,7 +560,7 @@ main( int argc, char** argv ) #if defined PLATFORM_GTK "o" #endif - "kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:Umvc" ); + "kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:UmvcC:" ); switch( opt ) { case 'h': case '?': @@ -549,6 +569,9 @@ main( int argc, char** argv ) case 'c': mainParams.showRobotScores = XP_TRUE; break; + case 'C': + mainParams.cookie = optarg; + break; case 'd': mainParams.gi.dictName = copyString( MPPARM(mainParams.util->mpool) optarg ); diff --git a/linux/main.h b/linux/main.h index 96ebf6203..7a9f1805b 100644 --- a/linux/main.h +++ b/linux/main.h @@ -43,6 +43,7 @@ typedef struct LaunchParams { DictionaryCtxt* dict; CurGameInfo gi; char* fileName; + char* cookie; VTableMgr* vtMgr; XP_U16 nLocalPlayers; XP_Bool trayOverlaps; /* probably only interesting for GTK case */ @@ -69,6 +70,8 @@ typedef struct LaunchParams { } LaunchParams; +typedef void (*SocketChangedFunc)(void* closure, int oldsock, int newsock ); + typedef struct CommonGlobals { LaunchParams* params; @@ -77,6 +80,8 @@ typedef struct CommonGlobals { /* UDP comms stuff */ char* defaultServerName; int socket; + SocketChangedFunc socketChanged; + void* socketChangedClosure; } CommonGlobals; #endif