From c992c65015d319d21e4d6b042b173dab6c490e61 Mon Sep 17 00:00:00 2001 From: Andy2 Date: Fri, 30 Sep 2011 06:32:21 -0700 Subject: [PATCH] changes to support automated testing of background messages sends: new param gives name of Unix domain socket to be used to accept connection that passes in messages from relay and receives messages to be sent back. Works once but needs debugging.... --- xwords4/linux/cursesmain.c | 86 +++++++++++++---- xwords4/linux/linuxmain.c | 188 +++++++++++++++++++++++++++++++------ xwords4/linux/linuxmain.h | 10 +- xwords4/linux/main.h | 2 + 4 files changed, 239 insertions(+), 47 deletions(-) diff --git a/xwords4/linux/cursesmain.c b/xwords4/linux/cursesmain.c index e66f93454..b96d2b74b 100644 --- a/xwords4/linux/cursesmain.c +++ b/xwords4/linux/cursesmain.c @@ -1,6 +1,6 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE"; -*- */ +/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights + * Copyright 2000-2011 by Eric House (xwords@eehouse.org). All rights * reserved. * * This program is free software; you can redistribute it and/or @@ -52,6 +52,7 @@ #include "xwproto.h" #include "xwstream.h" #include "xwstate.h" +#include "strutils.h" #include "server.h" #include "memstream.h" #include "util.h" @@ -1575,6 +1576,53 @@ positionSizeStuff( CursesAppGlobals* globals, int width, int height ) board_invalAll( board ); } /* positionSizeStuff */ +static XP_Bool +relay_sendNoConn_curses( const XP_U8* msg, XP_U16 len, + const XP_UCHAR* relayID, void* closure ) +{ + LOG_FUNC(); + CursesAppGlobals* globals = (CursesAppGlobals*)closure; + CommonGlobals* cGlobals = &globals->cGlobals; + int fd = cGlobals->nbsFD; + XP_Bool success = 0 <= fd; + if ( success ) { + XP_LOGF( "%s: given %d bytes for %s", __func__, len, relayID ); + + // format: total msg lenth: 2 + // number-of-relayIDs: 2 + // for-each-relayid: relayid + '\n': varies + // message count: 1 + // for-each-message: length: 2 + // message: varies + + XWStreamCtxt* stream = + mem_stream_make( MPPARM(globals->cGlobals.params->util->mpool) + globals->cGlobals.params->vtMgr, + globals, CHANNEL_NONE, NULL ); + stream_putU16( stream, 1 ); /* number of relayIDs */ + stream_catString( stream, relayID ); + stream_putU8( stream, '\n' ); + stream_putU16( stream, 1 ); /* message count */ + stream_putU16( stream, len ); + stream_putBytes( stream, msg, len ); + + XP_U16 siz = stream_getSize( stream ); + XP_U8 buf[siz]; + stream_getBytes( stream, buf, siz ); + XP_U16 tmp = XP_HTONS( siz ); + ssize_t nwritten = write( fd, &tmp, sizeof(tmp) ); + XP_ASSERT( nwritten == sizeof(tmp) ); + nwritten = write( fd, buf/*stream_getPtr( stream )*/, siz ); + log_hex( buf/*stream_getPtr( stream )*/, siz, __func__ ); + XP_ASSERT( nwritten == siz ); + stream_destroy( stream ); + } else { + XP_LOGF( "%s: nbsFD=%d", __func__, fd ); + } + LOG_RETURNF( "%d", success ); + return success; +} /* relay_sendNoConn_curses */ + static void relay_status_curses( void* XP_UNUSED(closure), CommsRelayState XP_UNUSED_DBG(state) ) @@ -1654,6 +1702,7 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) g_globals.cGlobals.cp.robotThinkMin = params->robotThinkMin; g_globals.cGlobals.cp.robotThinkMax = params->robotThinkMax; #endif + g_globals.cGlobals.nbsFD = -1; setupCursesUtilCallbacks( &g_globals, params->util ); @@ -1681,8 +1730,26 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) struct sigaction act2 = { .sa_handler = SIGWINCH_handler }; sigaction( SIGWINCH, &act2, NULL ); + TransportProcs procs = { + .closure = &g_globals, + .send = LINUX_SEND, +#ifdef COMMS_HEARTBEAT + .reset = linux_reset, +#endif +#ifdef XWFEATURE_RELAY + .rstatus = relay_status_curses, + .rconnd = relay_connd_curses, + .rerror = relay_error_curses, + .sendNoConn = relay_sendNoConn_curses, + .flags = COMMS_XPORT_FLAGS_HASNOCONN, +#endif + }; + + if ( !!params->pipe && !!params->fileName ) { - read_pipe_then_close( &g_globals.cGlobals ); + read_pipe_then_close( &g_globals.cGlobals, &procs ); + } else if ( !!params->nbs && !!params->fileName ) { + do_nbs_then_close( &g_globals.cGlobals, &procs ); } else { initCurses( &g_globals ); @@ -1691,19 +1758,6 @@ cursesmain( XP_Bool isServer, LaunchParams* params ) g_globals.draw = (struct CursesDrawCtx*) cursesDrawCtxtMake( g_globals.boardWin ); - TransportProcs procs = { - .closure = &g_globals, - .send = LINUX_SEND, -#ifdef COMMS_HEARTBEAT - .reset = linux_reset, -#endif -#ifdef XWFEATURE_RELAY - .rstatus = relay_status_curses, - .rconnd = relay_connd_curses, - .rerror = relay_error_curses, -#endif - }; - if ( !!params->fileName && file_exists( params->fileName ) ) { XWStreamCtxt* stream; stream = streamFromFile( &g_globals.cGlobals, params->fileName, diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 46fc72319..8b7da8aaf 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -35,6 +35,7 @@ #include #include #include +#include #ifdef XWFEATURE_BLUETOOTH # include @@ -189,9 +190,11 @@ strFromStream( XWStreamCtxt* stream ) return buf; } /* strFromStream */ -void -read_pipe_then_close( CommonGlobals* cGlobals ) +static void +handle_messages_from( CommonGlobals* cGlobals, const TransportProcs* procs, + int fdin ) { + LOG_FUNC(); LaunchParams* params = cGlobals->params; XWStreamCtxt* stream = streamFromFile( cGlobals, params->fileName, cGlobals ); @@ -204,45 +207,167 @@ read_pipe_then_close( CommonGlobals* cGlobals ) ¶ms->gi, params->dict, ¶ms->dicts, params->util, NULL /*draw*/, - &cGlobals->cp, NULL ); + &cGlobals->cp, procs ); XP_ASSERT( opened ); stream_destroy( stream ); XP_Bool handled = XP_FALSE; - int fd = open( params->pipe, O_RDONLY ); - while ( fd >= 0 ) { - unsigned short len; - ssize_t nRead = blocking_read( fd, (unsigned char*)&len, sizeof(len) ); - if ( nRead != 2 ) { + unsigned short len; + for ( ; ; ) { + ssize_t nRead = blocking_read( fdin, (unsigned char*)&len, + sizeof(len) ); + if ( nRead != sizeof(len) ) { + XP_LOGF( "%s: 1: unexpected nRead: %d", __func__, nRead ); break; } len = ntohs( len ); + if ( 0 == len ) { + break; + } unsigned char buf[len]; - nRead = blocking_read( fd, buf, len ); + nRead = blocking_read( fdin, buf, len ); if ( nRead != len ) { + XP_LOGF( "%s: 2: unexpected nRead: %d", __func__, nRead ); break; } stream = mem_stream_make( MPPARM(cGlobals->params->util->mpool) - params->vtMgr, cGlobals, CHANNEL_NONE, NULL ); + params->vtMgr, cGlobals, CHANNEL_NONE, + NULL ); stream_putBytes( stream, buf, len ); if ( comms_checkIncomingStream( cGlobals->game.comms, stream, NULL ) ) { - handled = server_receiveMessage( cGlobals->game.server, - stream ) || handled; + ServerCtxt* server = cGlobals->game.server; + (void)server_do( server, NULL ); + handled = server_receiveMessage( server, stream ) || handled; + + XP_Bool notDone; + XP_U16 ii; + for ( ii = 0, notDone = XP_TRUE; notDone && ii < 5; ++ii ) { + (void)server_do( server, ¬Done ); + } } stream_destroy( stream ); } - LOG_RETURNF( "%d", handled ); - /* Write it out */ - /* stream = mem_stream_make( MEMPOOLCG(cGlobals) params->vtMgr, */ - /* cGlobals, 0, writeToFile ); */ - /* stream_open( stream ); */ - /* game_saveToStream( &cGlobals->game, ¶ms->gi, stream ); */ - /* stream_destroy( stream ); */ + LOG_RETURN_VOID(); +} /* handle_messages_from */ + +void +read_pipe_then_close( CommonGlobals* cGlobals, const TransportProcs* procs ) +{ + LOG_FUNC(); + LaunchParams* params = cGlobals->params; + XWStreamCtxt* stream = + streamFromFile( cGlobals, params->fileName, cGlobals ); + +#ifdef DEBUG + XP_Bool opened = +#endif + game_makeFromStream( MPPARM(cGlobals->params->util->mpool) + stream, &cGlobals->game, + ¶ms->gi, params->dict, + ¶ms->dicts, params->util, + NULL /*draw*/, + &cGlobals->cp, procs ); + XP_ASSERT( opened ); + stream_destroy( stream ); + + XP_Bool handled = XP_FALSE; + int fd = open( params->pipe, O_RDWR ); + XP_ASSERT( fd >= 0 ); + if ( fd >= 0 ) { + unsigned short len; + for ( ; ; ) { + ssize_t nRead = blocking_read( fd, (unsigned char*)&len, + sizeof(len) ); + if ( nRead != sizeof(len) ) { + XP_LOGF( "%s: 1: unexpected nRead: %d", __func__, nRead ); + break; + } + len = ntohs( len ); + if ( 0 == len ) { + break; + } + unsigned char buf[len]; + nRead = blocking_read( fd, buf, len ); + if ( nRead != len ) { + XP_LOGF( "%s: 2: unexpected nRead: %d", __func__, nRead ); + break; + } + stream = mem_stream_make( MPPARM(cGlobals->params->util->mpool) + params->vtMgr, cGlobals, CHANNEL_NONE, + NULL ); + stream_putBytes( stream, buf, len ); + + if ( comms_checkIncomingStream( cGlobals->game.comms, + stream, NULL ) ) { + ServerCtxt* server = cGlobals->game.server; + (void)server_do( server, NULL ); + handled = server_receiveMessage( server, stream ) || handled; + + XP_Bool notDone; + XP_U16 ii; + for ( ii = 0, notDone = XP_TRUE; notDone && ii < 5; ++ii ) { + (void)server_do( server, ¬Done ); + } + } + stream_destroy( stream ); + } + + /* 0-length packet closes it off */ + XP_LOGF( "%s: writing 0-length packet", __func__ ); + len = 0; + ssize_t nwritten = write( fd, &len, sizeof(len) ); + XP_ASSERT( nwritten == sizeof(len) ); + + close( fd ); + } + + LOG_RETURN_VOID(); } /* read_pipe_then_close */ +void +do_nbs_then_close( CommonGlobals* cGlobals, const TransportProcs* procs ) +{ + LOG_FUNC(); + int sockfd = socket( AF_UNIX, SOCK_STREAM, 0 ); + + struct sockaddr_un addr; + addr.sun_family = AF_UNIX; + strcpy( addr.sun_path, cGlobals->params->nbs ); + + int err = bind( sockfd, (struct sockaddr*)&addr, sizeof(addr) ); + if ( 0 != err ) { + XP_LOGF( "%s: bind=>%s", __func__, strerror( errno ) ); + XP_ASSERT( 0 ); + } + XP_LOGF( "calling listen" ); + err = listen( sockfd, 1 ); + assert( 0 == err ); + + struct sockaddr remote; + socklen_t addrlen = sizeof(remote); + XP_LOGF( "calling accept" ); + int fd = accept( sockfd, &remote, &addrlen ); + XP_LOGF( "%s: accept=>%d", __func__, fd ); + assert( 0 <= fd ); + + /* do stuff here */ + cGlobals->nbsFD = fd; + handle_messages_from( cGlobals, procs, fd ); + cGlobals->nbsFD = -1; + + /* Do I need this? Will reader get err if I close? */ + unsigned short len = 0; + ssize_t nwritten = write( fd, &len, sizeof(len) ); + XP_ASSERT( nwritten == sizeof(len) ); + + close( fd ); + close( sockfd ); + LOG_RETURN_VOID(); +} /* do_nbs_then_close */ + typedef enum { CMD_SKIP_GAMEOVER ,CMD_SHOW_OTHERSCORES @@ -280,6 +405,7 @@ typedef enum { ,CMD_VERTICALSCORE ,CMD_NOPEEK ,CMD_ADDPIPE + ,CMD_ADDNBS #ifdef XWFEATURE_SEARCHLIMIT ,CMD_HINTRECT #endif @@ -354,6 +480,8 @@ static CmdInfoRec CmdInfoRecs[] = { ,{ CMD_VERTICALSCORE, false, "vertical", "scoreboard is vertical" } ,{ CMD_NOPEEK, false, "no-peek", "disallow scoreboard tap changing player" } ,{ CMD_ADDPIPE, true, "with-pipe", "named pipe to listen on for relay msgs" } + ,{ CMD_ADDNBS, true, "with-nbs", + "nbs socket to listen/reply on for relay msgs" } #ifdef XWFEATURE_SEARCHLIMIT ,{ CMD_HINTRECT, false, "hintrect", "enable draggable hint-limits rect" } #endif @@ -659,14 +787,15 @@ blocking_read( int fd, unsigned char* buf, int len ) { int nRead = 0; while ( nRead < len ) { - ssize_t siz = read( fd, buf + nRead, len - nRead ); - if ( siz <= 0 ) { - XP_LOGF( "read => %d, errno=%d (\"%s\")", nRead, - errno, strerror(errno) ); - nRead = -1; - break; - } - nRead += siz; + XP_LOGF( "%s: blocking for %d bytes", __func__, len ); + ssize_t siz = read( fd, buf + nRead, len - nRead ); + if ( siz <= 0 ) { + XP_LOGF( "read => %d, errno=%d (\"%s\")", nRead, + errno, strerror(errno) ); + nRead = -1; + break; + } + nRead += siz; } return nRead; } @@ -1186,6 +1315,9 @@ main( int argc, char** argv ) case CMD_ADDPIPE: mainParams.pipe = optarg; break; + case CMD_ADDNBS: + mainParams.nbs = optarg; + break; #ifdef XWFEATURE_SLOW_ROBOT case CMD_SLOWROBOT: if ( !parsePair( optarg, &mainParams.robotThinkMin, @@ -1397,7 +1529,7 @@ main( int argc, char** argv ) free( mainParams.util ); - XP_LOGF( "exiting main" ); + XP_LOGF( "%s exiting main", argv[0] ); return 0; } /* main */ diff --git a/xwords4/linux/linuxmain.h b/xwords4/linux/linuxmain.h index b9ae258d2..a83997cba 100644 --- a/xwords4/linux/linuxmain.h +++ b/xwords4/linux/linuxmain.h @@ -1,6 +1,7 @@ -/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make -k";-*- */ +/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */ /* - * Copyright 1997-2008 by Eric House (xwords@eehouse.org). All rights reserved. + * Copyright 1997-2011 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 @@ -74,6 +75,9 @@ XP_Bool linShiftFocus( CommonGlobals* cGlobals, XP_Key key, BoardObjectType* nxtP ); #endif -void read_pipe_then_close( CommonGlobals* cGlobals ); +void read_pipe_then_close( CommonGlobals* cGlobals, + const TransportProcs* procs ); +void do_nbs_then_close( CommonGlobals* cGlobals, + const TransportProcs* procs ); #endif diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h index 0dbac5ee5..dad380f49 100644 --- a/xwords4/linux/main.h +++ b/xwords4/linux/main.h @@ -50,6 +50,7 @@ typedef struct LaunchParams { PlayerDicts dicts; char* fileName; char* pipe; + char* nbs; char* bonusFile; VTableMgr* vtMgr; XP_U16 nLocalPlayers; @@ -161,6 +162,7 @@ struct CommonGlobals { * polling mechanism.*/ AddAcceptorFunc addAcceptor; Acceptor acceptor; + int nbsFD; #ifdef XWFEATURE_RELAY int socket; /* relay */