From 1fba8494f367eea25d2cac7262b69f5f04fbc879 Mon Sep 17 00:00:00 2001 From: ehouse Date: Sun, 6 Mar 2005 18:07:00 +0000 Subject: [PATCH] Replace UDP-based messaging with TCP. Stream protocol says distinct message is length plus data. Use non-deprecated gtk select-like function. With these changes can play full games through the relay on gtk. Untested on ncurses but probably broken. --- linux/cursesmain.c | 9 +-- linux/gtkmain.c | 134 ++++++++++++++++-------------------- linux/gtkmain.h | 1 - linux/linuxmain.c | 166 +++++++++++++++------------------------------ linux/linuxmain.h | 5 +- linux/main.h | 3 +- 6 files changed, 124 insertions(+), 194 deletions(-) diff --git a/linux/cursesmain.c b/linux/cursesmain.c index c3b043a5d..946909111 100644 --- a/linux/cursesmain.c +++ b/linux/cursesmain.c @@ -871,6 +871,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) globals.amServer = isServer; globals.cGlobals.params = params; + globals.cGlobals.socket = -1; globals.cp.showBoardArrow = XP_TRUE; globals.cp.showRobotScores = params->showRobotScores; @@ -879,7 +880,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) setupCursesUtilCallbacks( &globals, params->util ); - globals.cGlobals.defaultServerName = params->info.clientInfo.serverName; + globals.cGlobals.defaultServerName = params->relayName; cursesListenOnSocket( &globals, 0, NULL ); /* stdin */ @@ -888,8 +889,8 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) cursesListenOnSocket( &globals, globals.timepipe[0], NULL ); /* reader pipe */ - sock = initListenerSocket( params->defaultListenPort ); - cursesListenOnSocket( &globals, sock, NULL ); + sock = linux_init_socket( &globals.cGlobals ); + cursesListenOnSocket( &globals, sock, NULL ); signal( SIGWINCH, SIGWINCH_handler ); initCurses( &globals ); @@ -899,7 +900,7 @@ 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_udp_send, &globals ); + gameID, &globals.cp, linux_tcp_send, &globals ); addr.conType = COMMS_CONN_IP; addr.u.ip.ipAddr = 0; /* ??? */ diff --git a/linux/gtkmain.c b/linux/gtkmain.c index eaff5a272..603ef5564 100644 --- a/linux/gtkmain.c +++ b/linux/gtkmain.c @@ -244,7 +244,7 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget ) params->dict, params->util, (DrawCtx*)globals->draw, &globals->cp, - linux_udp_send, globals ); + linux_tcp_send, globals ); stream_destroy( stream ); @@ -252,17 +252,15 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget ) XP_U16 gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util ); CommsAddrRec addr; - if ( serverRole == SERVER_ISCLIENT ) { - globals->cGlobals.defaultServerName = - params->info.clientInfo.serverName; - } + XP_ASSERT( !!params->relayName ); + globals->cGlobals.defaultServerName = params->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_udp_send, globals ); + gameID, &globals->cp, linux_tcp_send, globals ); addr.conType = COMMS_CONN_IP; addr.u.ip.ipAddr = 0; /* ??? */ @@ -307,13 +305,10 @@ configure_event( GtkWidget *widget, GdkEventConfigure *event, firstTime = (globals->draw == NULL); if ( firstTime ) { - int listenSocket = - initListenerSocket(globals->cGlobals.params->defaultListenPort); + int listenSocket = linux_init_socket( &globals->cGlobals ); gtkListenOnSocket( globals, listenSocket ); createOrLoadObjects( globals, widget ); - } else { -/* gdk_pixmap_unref( ((GtkDrawCtx*)globals->draw)->pixmap ); */ } width = widget->allocation.width - (RIGHT_MARGIN + BOARD_LEFT_MARGIN); @@ -544,7 +539,7 @@ new_game( GtkWidget* widget, GtkAppGlobals* globals ) XP_STATUSF( "grabbed gameID: %ld\n", gameID ); game_reset( MEMPOOL &globals->cGlobals.game, gi, gameID, &globals->cp, - linux_udp_send, globals ); + linux_tcp_send, globals ); if ( isClient ) { XWStreamCtxt* stream = @@ -1406,92 +1401,80 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util ) util->closure = globals; } /* setupGtkUtilCallbacks */ -static void -newConnectionInput( gpointer data, gint source, - GdkInputCondition condition ) + +static gboolean +newConnectionInput( GIOChannel *source, + GIOCondition condition, + gpointer data ) { + int sock = g_io_channel_unix_get_fd( source ); GtkAppGlobals* globals = (GtkAppGlobals*)data; - struct sockaddr_in addr_sock; - - int flen, nBytes; - char buf[256]; - char* bufPtr = buf; - XP_LOGF( "Incomming message!!!" ); + XP_ASSERT( sock == globals->cGlobals.socket ); - memset( buf, 0, sizeof(buf) ); - flen = sizeof(struct sockaddr_in); - nBytes = recvfrom( source, buf, sizeof(buf), 0, - (struct sockaddr *)&addr_sock, &flen ); - XP_ASSERT( nBytes != -1 ); + if ( (condition & G_IO_HUP) != 0 ) { - if ( !globals->dropIncommingMsgs && nBytes != -1 ) { - XWStreamCtxt* inboundS; - XP_Bool redraw = XP_FALSE; + globals->cGlobals.socket = -1; + return FALSE; /* remove the event source */ - /* somehow, we need to associate a return address with a client. This - is the address we'll be using from now on. So when a connection is - made, pass the return address to the comms module. It can decide - from the message if it's seen the message source before.*/ + } else if ( (condition & G_IO_IN) != 0 ) { + ssize_t nRead; + unsigned short packetSize; + unsigned short tmp; + unsigned char buf[512]; - /* inboundS = linux_make_inbound_socketStream( */ - /* inboundSocket, &returnSockAddr, addrLen ); */ + XP_LOGF( "activity on socket %d", sock ); + nRead = recv( sock, &tmp, sizeof(tmp), 0 ); + assert( nRead == 2 ); - inboundS = stream_from_msgbuf( &globals->cGlobals, bufPtr, nBytes ); - if ( !!inboundS ) { - CommsAddrRec addrRec; + packetSize = ntohs( tmp ); + nRead = recv( sock, buf, packetSize, 0 ); - XP_MEMSET( &addrRec, 0, sizeof(addrRec) ); - addrRec.conType = COMMS_CONN_IP; - - addrRec.u.ip.ipAddr = ntohl(addr_sock.sin_addr.s_addr); - XP_LOGF( "captured incomming ip address: 0x%lx", - addrRec.u.ip.ipAddr ); - - if ( comms_checkIncommingStream( globals->cGlobals.game.comms, - inboundS, &addrRec ) ) { - redraw = server_receiveMessage( globals->cGlobals.game.server, - inboundS ); + if ( !globals->dropIncommingMsgs && nRead > 0 ) { + XWStreamCtxt* inboundS; + XP_Bool redraw = XP_FALSE; + + inboundS = stream_from_msgbuf( &globals->cGlobals, buf, nRead ); + if ( !!inboundS ) { + if ( comms_checkIncommingStream( globals->cGlobals.game.comms, + inboundS, NULL ) ) { + redraw = server_receiveMessage(globals->cGlobals.game.server + , inboundS ); + } + stream_destroy( inboundS ); } - stream_destroy( inboundS ); - } - /* if there's something to draw resulting from the message, we need to - give the main loop time to reflect that on the screen before giving - the server another shot. So just call the idle proc. */ - if ( redraw ) { - gtk_util_requestTime( globals->cGlobals.params->util ); + /* if there's something to draw resulting from the message, we + need to give the main loop time to reflect that on the screen + before giving the server another shot. So just call the idle + proc. */ + if ( redraw ) { + gtk_util_requestTime( globals->cGlobals.params->util ); + } else { + redraw = server_do( globals->cGlobals.game.server ); + } + if ( redraw ) { + board_draw( globals->cGlobals.game.board ); + } } else { - redraw = server_do( globals->cGlobals.game.server ); + XP_LOGF( "errno from read: %d", errno ); } - if ( redraw ) { - board_draw( globals->cGlobals.game.board ); - } - } else { - XP_LOGF( "errno from accept: %d", errno ); } - + return TRUE; /* FALSE means to remove event source */ } /* newConnectionInput */ -static void -newConnectionDestroy( gpointer data ) -{ - XP_LOGF( "newConnectionDestroy called" ); -} /* newConnectionDestroy */ - /* Make gtk listen for events on the socket that clients will use to * connect to us. */ static void gtkListenOnSocket( GtkAppGlobals* globals, int newSock ) { - guint result = gtk_input_add_full( newSock, - GDK_INPUT_READ, - newConnectionInput, - (GtkCallbackMarshal)0L, - globals, - newConnectionDestroy ); - globals->listenSockKey = result; + GIOChannel* channel = g_io_channel_unix_new( newSock ); + guint result = g_io_add_watch( channel, + G_IO_IN | G_IO_HUP, + newConnectionInput, + globals ); + XP_LOGF( "g_io_add_watch => %d", result ); } /* gtkListenOnSocket */ static void @@ -1529,6 +1512,7 @@ gtkmain( XP_Bool isServer, LaunchParams* params, int argc, char *argv[] ) globals.cGlobals.params = params; globals.cGlobals.lastNTilesToUse = MAX_TRAY_TILES; + globals.cGlobals.socket = -1; globals.cp.showBoardArrow = XP_TRUE; globals.cp.showRobotScores = params->showRobotScores; diff --git a/linux/gtkmain.h b/linux/gtkmain.h index dfb11b448..938e8e4fe 100644 --- a/linux/gtkmain.h +++ b/linux/gtkmain.h @@ -70,7 +70,6 @@ typedef struct GtkAppGlobals { GtkAdjustment* adjustment; ClientStreamRec clientRecs[MAX_NUM_PLAYERS]; - guint listenSockKey; /* save return from gtk_input_add_full */ CommonPrefs cp; diff --git a/linux/linuxmain.c b/linux/linuxmain.c index 906d46545..6ec36f1aa 100644 --- a/linux/linuxmain.c +++ b/linux/linuxmain.c @@ -28,7 +28,6 @@ #include #include #include -#include #include #include "linuxmain.h" @@ -200,7 +199,6 @@ usage( char* appName, char* msg ) "\t [-c] # explain robot scores after each move\n" "\t\t # (max of four players total, local and remote)\n" "\t [-b boardSize] # number of columns and rows\n" - "\t [-l listen_port] # port for inet connection (4999 default)\n" "\t [-e random_seed] \n" "\t [-t initial_minutes_on_timer] \n" "# --------------- choose client or server ----------\n" @@ -208,106 +206,83 @@ usage( char* appName, char* msg ) "\t -d xwd_file # provides tile counts & values\n" "\t\t # list each player as local or remote\n" "\t [-N]* # remote client (listen for connection)\n" - "# --------------- OR client-only ----------\n" - "\t [-a server_addr] # be a client (on port spec'd above)\n" - "\t [-p client_port] # must != server's port if on same device" + "\t [-a relay_addr] # use relay (via port spec'd above)\n" "" " (default localhost)\n" + "\t [-p relay_port] # relay is at this port\n" +/* "# --------------- OR client-only ----------\n" */ +/* "\t [-p client_port] # must != server's port if on same device" */ "\nexample: \n" - "\tserver: ./xwords -d dict.xwd -s -r Eric -N\n" - "\tclient: ./xwords -d dict.xwd -r Kati -p 4998 -l 6000\n" + "\tserver: ./xwords -d dict.xwd -s -a localhost -p 10999 -r Eric -N\n" + "\tclient: ./xwords -d dict.xwd -a localhost -p 10999 -r Kati\n" , appName ); exit(1); } XP_S16 -linux_udp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec, +linux_tcp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec, void* closure ) { CommonGlobals* globals = (CommonGlobals*)closure; + XP_S16 result = 0; + int socket = globals->socket; + + if ( socket == -1 ) { + XP_STATUSF( "linux_tcp_send: socket uninitialized" ); + } else { + XP_U16 netLen = htons( buflen ); + errno = 0; + + (void)send( socket, &netLen, sizeof(netLen), 0 ); + result = send( socket, buf, buflen, 0 ); + + XP_STATUSF( "linux_tcp_send: send returned %d of %d (err=%d)", + result, buflen, errno ); + } + + return result; +} /* linux_tcp_send */ + +int +linux_init_socket( CommonGlobals* cGlobals ) +{ struct sockaddr_in to_sock; struct hostent* host; - XP_S16 result; - int sock; -/* XP_U8* msg; */ - - XP_LOGF( "linux_udp_send" ); - - /* make a local copy of the address to send to */ - sock = socket( AF_INET, SOCK_DGRAM, 0 ); + int sock = cGlobals->socket; if ( sock == -1 ) { - XP_DEBUGF( "socket returned -1\n" ); - return -1; - } - if ( !!addrRec ) { + /* make a local copy of the address to send to */ + sock = socket( AF_INET, SOCK_STREAM, 0 ); + if ( sock == -1 ) { + XP_DEBUGF( "socket returned -1\n" ); + return -1; + } - XP_ASSERT( addrRec->conType == COMMS_CONN_IP ); - XP_MEMSET( &to_sock, 0, sizeof(to_sock) ); - XP_STATUSF( "target IP = 0x%lx", addrRec->u.ip.ipAddr ); - to_sock.sin_addr.s_addr = htonl(addrRec->u.ip.ipAddr); - to_sock.sin_port = htons(addrRec->u.ip.port); - - XP_STATUSF( "0: sending to port %d(0x%x)", - addrRec->u.ip.port, addrRec->u.ip.port ); - } else { - - to_sock.sin_port = htons(globals->params->defaultSendPort); + to_sock.sin_port = htons(cGlobals->params->defaultSendPort); XP_STATUSF( "1: sending to port %d", - globals->params->defaultSendPort ); - if (( host = gethostbyname(globals->defaultServerName) ) == NULL ) { + cGlobals->params->defaultSendPort ); + if (( host = gethostbyname(cGlobals->params->relayName) ) == NULL ) { XP_WARNF( "gethostbyname returned -1\n" ); return -1; } else { XP_WARNF( "gethostbyname for %s worked", - globals->defaultServerName ); + cGlobals->defaultServerName ); } memcpy( &(to_sock.sin_addr.s_addr), host->h_addr_list[0], sizeof(struct in_addr)); + to_sock.sin_family = AF_INET; + + errno = 0; + if ( 0 == connect( sock, (const struct sockaddr*)&to_sock, + sizeof(to_sock) ) ) { + cGlobals->socket = sock; + } else { + close( sock ); + XP_STATUSF( "connect failed: %d", errno ); + } } - to_sock.sin_family = AF_INET; -/* msg = malloc( buflen ); */ -/* XP_MEMCPY( msg, buf, buflen ); */ - - errno = 0; - XP_STATUSF( "checking: errno=%d", (short)errno ); - result = sendto( sock, buf, buflen, 0, - (struct sockaddr *)&to_sock, sizeof(to_sock) ); - XP_STATUSF( "foo: sendto returned %d of %d (err=%d)", - result, buflen, errno ); - close(sock); - -/* free( msg ); */ - - return result; -} /* linux_udp_send */ - -int -initListenerSocket( int port ) -{ - int newSocket; - int result; - struct sockaddr_in sockAddr; - - XP_DEBUGF( "opening socket to listen on port %d", port ); - - newSocket = socket( AF_INET, DGRAM_TYPE, 0 ); - XP_DEBUGF( "socket returned %d", newSocket ); - - sockAddr.sin_family = AF_INET; - sockAddr.sin_addr.s_addr = htonl(INADDR_ANY); - sockAddr.sin_port = htons(port); - - result = bind( newSocket, (struct sockaddr*)&sockAddr, sizeof(sockAddr) ); - XP_LOGF( "bind on port %d returned %d; errno=%d", - port, result, errno ); - - -/* result = listen( newSocket, 5 ); */ -/* XP_DEBUGF( "listen returned %d; errno=%d\n", result, errno ); */ - - return newSocket; -} /* initListenerSocket */ + return sock; +} /* linux_init_socket */ /* Create a stream for the incomming message buffer, and read in any information specific to our platform's comms layer (return address, say) @@ -485,9 +460,8 @@ main( int argc, char** argv ) int opt; int totalPlayerCount = 0; XP_Bool isServer = XP_FALSE; - char* listenPortNumString = NULL; char* sendPortNumString = NULL; - char* serverName = "localhost"; + char* relayName = "localhost"; unsigned int seed = defaultRandomSeed(); LaunchParams mainParams; XP_U16 robotCount = 0; @@ -592,9 +566,6 @@ main( int argc, char** argv ) mainParams.gi.players[index].isLocal = XP_FALSE; ++mainParams.info.serverInfo.nRemotePlayers; break; - case 'l': - listenPortNumString = optarg; - break; case 'p': sendPortNumString = optarg; break; @@ -622,7 +593,7 @@ main( int argc, char** argv ) break; case 'a': /* mainParams.info.clientInfo.serverName = */ - serverName = optarg; + relayName = optarg; break; case 'q': mainParams.quitAfter = XP_TRUE; @@ -667,9 +638,6 @@ main( int argc, char** argv ) } /* convert strings to whatever */ - if ( listenPortNumString ) { - mainParams.defaultListenPort = atoi( listenPortNumString ); - } if ( sendPortNumString != NULL ) { mainParams.defaultSendPort = atoi( sendPortNumString ); } @@ -706,31 +674,7 @@ main( int argc, char** argv ) } } - /* setup sockets and any other stuff not specific to GTK or ncurses */ - if ( isServer ) { - } else { - /* struct hostent* hostinfo; */ - /* hostinfo = gethostbyname( serverName ); */ - /* if ( !hostinfo ) { */ - /* fprintf( stderr, "unable to get host info for %s\n", serverName ); */ - /* exit( 0 ); */ - /* } else { */ - /* char* hostName = inet_ntoa( *(struct in_addr*)hostinfo->h_addr ); */ - /* unsigned long int serverAddr; */ - /* fprintf( stderr, "gethostbyname returned %s\n", hostName ); */ - /* serverAddr = inet_addr(hostName); */ - /* fprintf( stderr, "inet_addr returned %lu\n", serverAddr ); */ - - /* mainParams.info.clientInfo.stream = */ - /* linux_make_outbound_socketStream( serverAddr, serverPort ); */ - - /* if ( !stream_open( mainParams.info.clientInfo.stream ) { */ - /* fprintf( stderr, "ERROR: unable to connect to server\n" ); */ - /* exit(0); */ - /* } */ - /* } */ - mainParams.info.clientInfo.serverName = serverName; - } + mainParams.relayName = relayName; /* mainParams.pipe = linuxCommPipeCtxtMake( isServer ); */ diff --git a/linux/linuxmain.h b/linux/linuxmain.h index 477828872..4a2006dfb 100644 --- a/linux/linuxmain.h +++ b/linux/linuxmain.h @@ -37,9 +37,10 @@ typedef struct LinuxBMStruct { DictionaryCtxt* linux_dictionary_make( MPFORMAL char* dictFileName ); int initListenerSocket( int port ); -XP_S16 linux_udp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec, +XP_S16 linux_tcp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec, void* closure ); -XWStreamCtxt* stream_from_msgbuf( CommonGlobals* globals, char* bufPtr, +int linux_init_socket( CommonGlobals* cGlobals ); +XWStreamCtxt* stream_from_msgbuf( CommonGlobals* cGlobals, char* bufPtr, XP_U16 nBytes ); XP_UCHAR* linux_getErrString( UtilErrID id ); XP_UCHAR* strFromStream( XWStreamCtxt* stream ); diff --git a/linux/main.h b/linux/main.h index 233a4547c..96ebf6203 100644 --- a/linux/main.h +++ b/linux/main.h @@ -31,7 +31,6 @@ typedef struct ServerInfo { } ServerInfo; typedef struct ClientInfo { - char* serverName; /* still need this? */ } ClientInfo; typedef struct LinuxUtilCtxt { @@ -59,6 +58,7 @@ typedef struct LaunchParams { Connectedness serverRole; + char* relayName; union { ServerInfo serverInfo; ClientInfo clientInfo; @@ -76,6 +76,7 @@ typedef struct CommonGlobals { XP_U16 lastNTilesToUse; /* UDP comms stuff */ char* defaultServerName; + int socket; } CommonGlobals; #endif