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....
This commit is contained in:
Andy2 2011-09-30 06:32:21 -07:00
parent c952ebd8e6
commit c992c65015
4 changed files with 239 additions and 47 deletions

View file

@ -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,

View file

@ -35,6 +35,7 @@
#include <time.h>
#include <syslog.h>
#include <stdarg.h>
#include <linux/un.h>
#ifdef XWFEATURE_BLUETOOTH
# include <bluetooth/bluetooth.h>
@ -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 )
&params->gi, params->dict,
&params->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, &notDone );
}
}
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, &params->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,
&params->gi, params->dict,
&params->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, &notDone );
}
}
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 */

View file

@ -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

View file

@ -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 */