Merge branch 'android_branch' of ssh://xwords.git.sourceforge.net/gitroot/xwords/xwords into android_branch

This commit is contained in:
Eric House 2011-01-27 14:58:10 -08:00
commit 70f52b162b
24 changed files with 512 additions and 281 deletions

View file

@ -168,13 +168,13 @@
android:defaultValue="false"
/>
<!-- <org.eehouse.android.xw4.PollListPreference -->
<!-- android:key="@string/key_connect_frequency" -->
<!-- android:title="@string/connect_frequency" -->
<!-- android:entries="@array/connect_frequencies" -->
<!-- android:entryValues="@array/connect_frequencies_values" -->
<!-- android:defaultValue="900" -->
<!-- /> -->
<org.eehouse.android.xw4.PollListPreference
android:key="@string/key_connect_frequency"
android:title="@string/connect_frequency"
android:entries="@array/connect_frequencies"
android:entryValues="@array/connect_frequencies_values"
android:defaultValue="900"
/>
</PreferenceScreen>
<PreferenceScreen android:title="@string/advanced"

View file

@ -826,7 +826,8 @@ selectPlayerImpl( BoardCtxt* board, XP_U16 newPlayer, XP_Bool reveal,
if ( reveal ) {
checkRevealTray( board );
}
} else if ( canPeek || newPlayer == curTurn ) {
} else if ( canPeek || ((newPlayer == curTurn)
&& LP_IS_LOCAL( &board->gi->players[newPlayer]))) {
PerTurnInfo* newInfo = &board->pti[newPlayer];
XP_U16 oldPlayer = board->selPlayer;
model_foreachPendingCell( board->model, newPlayer,

View file

@ -284,7 +284,9 @@ comms_make( MPFORMAL XW_UtilCtxt* util, XP_Bool isServer,
MPASSIGN(result->mpool, mpool);
result->isServer = isServer;
XP_MEMCPY( &result->procs, procs, sizeof(result->procs) );
if ( !!procs ) {
XP_MEMCPY( &result->procs, procs, sizeof(result->procs) );
}
result->util = util;
#ifdef XWFEATURE_RELAY
@ -1308,9 +1310,13 @@ relayPreProcess( CommsCtxt* comms, XWStreamCtxt* stream, XWHostID* senderID )
cookieID, srcID, destID );
/* If these values don't check out, drop it */
XP_ASSERT( COMMS_RELAYSTATE_ALLCONNECTED == comms->r.relayState
|| COMMS_RELAYSTATE_CONNECTED == comms->r.relayState
|| COMMS_RELAYSTATE_RECONNECTED == comms->r.relayState );
/* When a message comes in via proxy (rather than a connection) state
may not be as expected. Just commenting these out is probably the
wrong fix. Maybe instead the constructor takes a flag that means
"assume you're connected" Revisit this. */
/* XP_ASSERT( COMMS_RELAYSTATE_ALLCONNECTED == comms->r.relayState */
/* || COMMS_RELAYSTATE_CONNECTED == comms->r.relayState */
/* || COMMS_RELAYSTATE_RECONNECTED == comms->r.relayState ); */
if ( destID == comms->r.myHostID ) { /* When would this not happen? */
consumed = XP_FALSE;

View file

@ -229,7 +229,9 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
gi->nPlayers );
server_prefsChanged( game->server, cp );
board_prefsChanged( game->board, cp );
draw_dictChanged( draw, dict );
if ( !!draw ) {
draw_dictChanged( draw, dict );
}
success = XP_TRUE;
} while( XP_FALSE );
}

View file

@ -2,5 +2,6 @@
*.xwd
*.pdb
*.stamp
*.dict
*.dict.gz
dict2dawg

View file

@ -1458,12 +1458,12 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
g_globals.cGlobals.socketChangedClosure = &g_globals;
g_globals.cGlobals.addAcceptor = curses_socket_acceptor;
g_globals.cp.showBoardArrow = XP_TRUE;
g_globals.cp.showRobotScores = params->showRobotScores;
g_globals.cp.hideTileValues = params->hideValues;
g_globals.cGlobals.cp.showBoardArrow = XP_TRUE;
g_globals.cGlobals.cp.showRobotScores = params->showRobotScores;
g_globals.cGlobals.cp.hideTileValues = params->hideValues;
#ifdef XWFEATURE_SLOW_ROBOT
g_globals.cp.robotThinkMin = params->robotThinkMin;
g_globals.cp.robotThinkMax = params->robotThinkMax;
g_globals.cGlobals.cp.robotThinkMin = params->robotThinkMin;
g_globals.cGlobals.cp.robotThinkMax = params->robotThinkMax;
#endif
dict = params->dict;
@ -1490,136 +1490,141 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
struct sigaction act2 = { .sa_handler = SIGWINCH_handler };
sigaction( SIGWINCH, &act2, NULL );
initCurses( &g_globals );
getmaxyx( g_globals.boardWin, height, width );
if ( !!params->pipe && !!params->fileName ) {
read_pipe_then_close( &g_globals.cGlobals );
} else {
g_globals.draw = (struct CursesDrawCtx*)
cursesDrawCtxtMake( g_globals.boardWin );
initCurses( &g_globals );
getmaxyx( g_globals.boardWin, height, width );
TransportProcs procs = {
.closure = &g_globals,
.send = LINUX_SEND,
g_globals.draw = (struct CursesDrawCtx*)
cursesDrawCtxtMake( g_globals.boardWin );
TransportProcs procs = {
.closure = &g_globals,
.send = LINUX_SEND,
#ifdef COMMS_HEARTBEAT
.reset = linux_reset,
.reset = linux_reset,
#endif
#ifdef XWFEATURE_RELAY
.rstatus = relay_status_curses,
.rconnd = relay_connd_curses,
.rerror = relay_error_curses,
.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,
&g_globals );
if ( !!params->fileName && file_exists( params->fileName ) ) {
XWStreamCtxt* stream;
stream = streamFromFile( &g_globals.cGlobals, params->fileName,
&g_globals );
(void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game,
&params->gi, dict, params->util,
(DrawCtx*)g_globals.draw,
&g_globals.cp, &procs );
(void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game,
&params->gi, dict, params->util,
(DrawCtx*)g_globals.draw,
&g_globals.cGlobals.cp, &procs );
stream_destroy( stream );
stream_destroy( stream );
if ( !isServer && params->gi.serverRole == SERVER_ISSERVER ) {
isServer = XP_TRUE;
if ( !isServer && params->gi.serverRole == SERVER_ISSERVER ) {
isServer = XP_TRUE;
}
} else {
game_makeNewGame( MEMPOOL &g_globals.cGlobals.game, &params->gi,
params->util, (DrawCtx*)g_globals.draw,
&g_globals.cGlobals.cp, &procs );
}
} else {
game_makeNewGame( MEMPOOL &g_globals.cGlobals.game, &params->gi,
params->util, (DrawCtx*)g_globals.draw,
&g_globals.cp, &procs );
}
#ifndef XWFEATURE_STANDALONE_ONLY
if ( g_globals.cGlobals.game.comms ) {
CommsAddrRec addr = {0};
if ( g_globals.cGlobals.game.comms ) {
CommsAddrRec addr = {0};
if ( 0 ) {
if ( 0 ) {
# ifdef XWFEATURE_RELAY
} else if ( params->conType == COMMS_CONN_RELAY ) {
addr.conType = COMMS_CONN_RELAY;
addr.u.ip_relay.ipAddr = 0; /* ??? */
addr.u.ip_relay.port = params->connInfo.relay.defaultSendPort;
addr.u.ip_relay.seeksPublicRoom = params->connInfo.relay.seeksPublicRoom;
addr.u.ip_relay.advertiseRoom = params->connInfo.relay.advertiseRoom;
XP_STRNCPY( addr.u.ip_relay.hostName, params->connInfo.relay.relayName,
sizeof(addr.u.ip_relay.hostName) - 1 );
XP_STRNCPY( addr.u.ip_relay.invite, params->connInfo.relay.invite,
sizeof(addr.u.ip_relay.invite) - 1 );
} else if ( params->conType == COMMS_CONN_RELAY ) {
addr.conType = COMMS_CONN_RELAY;
addr.u.ip_relay.ipAddr = 0; /* ??? */
addr.u.ip_relay.port = params->connInfo.relay.defaultSendPort;
addr.u.ip_relay.seeksPublicRoom = params->connInfo.relay.seeksPublicRoom;
addr.u.ip_relay.advertiseRoom = params->connInfo.relay.advertiseRoom;
XP_STRNCPY( addr.u.ip_relay.hostName, params->connInfo.relay.relayName,
sizeof(addr.u.ip_relay.hostName) - 1 );
XP_STRNCPY( addr.u.ip_relay.invite, params->connInfo.relay.invite,
sizeof(addr.u.ip_relay.invite) - 1 );
# endif
# ifdef XWFEATURE_SMS
} else if ( params->conType == COMMS_CONN_SMS ) {
addr.conType = COMMS_CONN_SMS;
XP_STRNCPY( addr.u.sms.phone, params->connInfo.sms.serverPhone,
sizeof(addr.u.sms.phone) - 1 );
addr.u.sms.port = params->connInfo.sms.port;
} else if ( params->conType == COMMS_CONN_SMS ) {
addr.conType = COMMS_CONN_SMS;
XP_STRNCPY( addr.u.sms.phone, params->connInfo.sms.serverPhone,
sizeof(addr.u.sms.phone) - 1 );
addr.u.sms.port = params->connInfo.sms.port;
# endif
# ifdef XWFEATURE_BLUETOOTH
} else if ( params->conType == COMMS_CONN_BT ) {
addr.conType = COMMS_CONN_BT;
XP_ASSERT( sizeof(addr.u.bt.btAddr)
>= sizeof(params->connInfo.bt.hostAddr));
XP_MEMCPY( &addr.u.bt.btAddr, &params->connInfo.bt.hostAddr,
sizeof(params->connInfo.bt.hostAddr) );
} else if ( params->conType == COMMS_CONN_BT ) {
addr.conType = COMMS_CONN_BT;
XP_ASSERT( sizeof(addr.u.bt.btAddr)
>= sizeof(params->connInfo.bt.hostAddr));
XP_MEMCPY( &addr.u.bt.btAddr, &params->connInfo.bt.hostAddr,
sizeof(params->connInfo.bt.hostAddr) );
# endif
}
comms_setAddr( g_globals.cGlobals.game.comms, &addr );
}
comms_setAddr( g_globals.cGlobals.game.comms, &addr );
}
#endif
model_setDictionary( g_globals.cGlobals.game.model, params->dict );
model_setDictionary( g_globals.cGlobals.game.model, params->dict );
positionSizeStuff( &g_globals, width, height );
positionSizeStuff( &g_globals, width, height );
#ifndef XWFEATURE_STANDALONE_ONLY
/* send any events that need to get off before the event loop begins */
if ( !isServer ) {
if ( 1 /* stream_open( params->info.clientInfo.stream ) */) {
server_initClientConnection( g_globals.cGlobals.game.server,
mem_stream_make( MEMPOOL
params->vtMgr,
&g_globals,
(XP_PlayerAddr)0,
sendOnClose ) );
} else {
cursesUserError( &g_globals, "Unable to open connection to server");
exit( 0 );
/* send any events that need to get off before the event loop begins */
if ( !isServer ) {
if ( 1 /* stream_open( params->info.clientInfo.stream ) */) {
server_initClientConnection( g_globals.cGlobals.game.server,
mem_stream_make( MEMPOOL
params->vtMgr,
&g_globals,
(XP_PlayerAddr)0,
sendOnClose ) );
} else {
cursesUserError( &g_globals, "Unable to open connection to server");
exit( 0 );
}
}
}
#endif
server_do( g_globals.cGlobals.game.server );
server_do( g_globals.cGlobals.game.server );
g_globals.menuList = g_boardMenuList;
drawMenuLargeOrSmall( &g_globals, g_boardMenuList );
board_draw( g_globals.cGlobals.game.board );
g_globals.menuList = g_boardMenuList;
drawMenuLargeOrSmall( &g_globals, g_boardMenuList );
board_draw( g_globals.cGlobals.game.board );
while ( !g_globals.timeToExit ) {
int ch = 0;
if ( blocking_gotEvent( &g_globals, &ch ) ) {
remapKey( &ch );
if (
while ( !g_globals.timeToExit ) {
int ch = 0;
if ( blocking_gotEvent( &g_globals, &ch ) ) {
remapKey( &ch );
if (
#ifdef CURSES_SMALL_SCREEN
handleKeyEvent( &g_globals, g_rootMenuListShow, ch ) ||
handleKeyEvent( &g_globals, g_rootMenuListShow, ch ) ||
#endif
handleKeyEvent( &g_globals, g_globals.menuList, ch )
|| handleKeyEvent( &g_globals, g_sharedMenuList, ch )
|| passKeyToBoard( &g_globals, ch ) ) {
if ( g_globals.doDraw ) {
board_draw( g_globals.cGlobals.game.board );
g_globals.doDraw = XP_FALSE;
handleKeyEvent( &g_globals, g_globals.menuList, ch )
|| handleKeyEvent( &g_globals, g_sharedMenuList, ch )
|| passKeyToBoard( &g_globals, ch ) ) {
if ( g_globals.doDraw ) {
board_draw( g_globals.cGlobals.game.board );
g_globals.doDraw = XP_FALSE;
}
}
}
}
}
}
if ( !!g_globals.cGlobals.params->fileName ) {
XWStreamCtxt* outStream;
outStream = mem_stream_make(
MPPARM(g_globals.cGlobals.params->util->mpool)
g_globals.cGlobals.params->vtMgr,
&g_globals.cGlobals, 0, writeToFile );
outStream =
mem_stream_make( MPPARM(g_globals.cGlobals.params->util->mpool)
g_globals.cGlobals.params->vtMgr,
&g_globals.cGlobals, 0, writeToFile );
stream_open( outStream );
game_saveToStream( &g_globals.cGlobals.game,

View file

@ -58,7 +58,6 @@ struct CursesAppGlobals {
DictionaryCtxt* dictionary;
EngineCtxt* engine;
CommonPrefs cp;
XP_Bool amServer; /* this process acting as server */

View file

@ -39,6 +39,8 @@
#endif
#include <sys/types.h>
#include <unistd.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "main.h"
#include "linuxmain.h"
@ -419,7 +421,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
&globals->cGlobals.params->gi,
params->dict, params->util,
(DrawCtx*)globals->draw,
&globals->cp, &procs );
&globals->cGlobals.cp, &procs );
stream_destroy( stream );
}
@ -440,7 +442,7 @@ createOrLoadObjects( GtkAppGlobals* globals )
game_makeNewGame( MEMPOOL &globals->cGlobals.game, &params->gi,
params->util, (DrawCtx*)globals->draw,
&globals->cp, &procs );
&globals->cGlobals.cp, &procs );
addr.conType = params->conType;
if ( 0 ) {
@ -782,7 +784,7 @@ new_game_impl( GtkAppGlobals* globals, XP_Bool fireConnDlg )
game_reset( MEMPOOL &globals->cGlobals.game, gi,
globals->cGlobals.params->util,
&globals->cp, &procs );
&globals->cGlobals.cp, &procs );
#ifndef XWFEATURE_STANDALONE_ONLY
if ( !!globals->cGlobals.game.comms ) {
@ -1878,7 +1880,7 @@ newConnectionInput( GIOChannel *source,
GIOCondition condition,
gpointer data )
{
gboolean keepSource;
gboolean keepSource = TRUE;
int sock = g_io_channel_unix_get_fd( source );
GtkAppGlobals* globals = (GtkAppGlobals*)data;
@ -1886,25 +1888,7 @@ newConnectionInput( GIOChannel *source,
/* XP_ASSERT( sock == globals->cGlobals.socket ); */
if ( (condition & (G_IO_HUP | G_IO_ERR)) != 0 ) {
XP_LOGF( "dropping socket %d", sock );
close( sock );
#ifdef XWFEATURE_RELAY
globals->cGlobals.socket = -1;
#endif
if ( 0 ) {
#ifdef XWFEATURE_BLUETOOTH
} else if ( COMMS_CONN_BT == globals->cGlobals.params->conType ) {
linux_bt_socketclosed( &globals->cGlobals, sock );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( COMMS_CONN_IP_DIRECT == globals->cGlobals.params->conType ) {
linux_udp_socketclosed( &globals->cGlobals, sock );
#endif
}
keepSource = FALSE; /* remove the event source */
} else if ( (condition & G_IO_IN) != 0 ) {
if ( (condition & G_IO_IN) != 0 ) {
ssize_t nRead;
unsigned char buf[512];
CommsAddrRec* addrp = NULL;
@ -1972,8 +1956,27 @@ newConnectionInput( GIOChannel *source,
} else {
XP_LOGF( "errno from read: %d/%s", errno, strerror(errno) );
}
keepSource = TRUE;
}
if ( (condition & (G_IO_HUP | G_IO_ERR)) != 0 ) {
XP_LOGF( "dropping socket %d", sock );
close( sock );
#ifdef XWFEATURE_RELAY
globals->cGlobals.socket = -1;
#endif
if ( 0 ) {
#ifdef XWFEATURE_BLUETOOTH
} else if ( COMMS_CONN_BT == globals->cGlobals.params->conType ) {
linux_bt_socketclosed( &globals->cGlobals, sock );
#endif
#ifdef XWFEATURE_IP_DIRECT
} else if ( COMMS_CONN_IP_DIRECT == globals->cGlobals.params->conType ) {
linux_udp_socketclosed( &globals->cGlobals, sock );
#endif
}
keepSource = FALSE; /* remove the event source */
}
return keepSource; /* FALSE means to remove event source */
} /* newConnectionInput */
@ -2144,16 +2147,16 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
globals.cGlobals.addAcceptor = gtk_socket_acceptor;
#endif
globals.cp.showBoardArrow = XP_TRUE;
globals.cp.hideTileValues = params->hideValues;
globals.cp.skipCommitConfirm = params->skipCommitConfirm;
globals.cp.sortNewTiles = params->sortNewTiles;
globals.cp.showColors = params->showColors;
globals.cp.allowPeek = params->allowPeek;
globals.cp.showRobotScores = params->showRobotScores;
globals.cGlobals.cp.showBoardArrow = XP_TRUE;
globals.cGlobals.cp.hideTileValues = params->hideValues;
globals.cGlobals.cp.skipCommitConfirm = params->skipCommitConfirm;
globals.cGlobals.cp.sortNewTiles = params->sortNewTiles;
globals.cGlobals.cp.showColors = params->showColors;
globals.cGlobals.cp.allowPeek = params->allowPeek;
globals.cGlobals.cp.showRobotScores = params->showRobotScores;
#ifdef XWFEATURE_SLOW_ROBOT
globals.cp.robotThinkMin = params->robotThinkMin;
globals.cp.robotThinkMax = params->robotThinkMax;
globals.cGlobals.cp.robotThinkMin = params->robotThinkMin;
globals.cGlobals.cp.robotThinkMax = params->robotThinkMax;
#endif
setupGtkUtilCallbacks( &globals, params->util );
@ -2259,11 +2262,14 @@ gtkmain( LaunchParams* params, int argc, char *argv[] )
/* | GDK_POINTER_MOTION_HINT_MASK */
);
gtk_widget_show( window );
if ( !!params->pipe && !!params->fileName ) {
read_pipe_then_close( &globals.cGlobals );
} else {
gtk_widget_show( window );
gtk_main();
/* MONCONTROL(1); */
gtk_main();
}
/* MONCONTROL(1); */
cleanup( &globals );

View file

@ -119,8 +119,6 @@ typedef struct GtkAppGlobals {
XP_UCHAR stateChar;
#endif
CommonPrefs cp;
XP_Bool gridOn;
XP_Bool dropIncommingMsgs;
XP_Bool mouseDown;

View file

@ -185,6 +185,57 @@ strFromStream( XWStreamCtxt* stream )
return buf;
} /* strFromStream */
void
read_pipe_then_close( CommonGlobals* cGlobals )
{
LaunchParams* params = cGlobals->params;
XWStreamCtxt* stream =
streamFromFile( cGlobals, params->fileName, cGlobals );
XP_Bool opened = game_makeFromStream( MPPARM(cGlobals->params->util->mpool)
stream, &cGlobals->game,
&params->gi,
params->dict, params->util,
NULL /*draw*/,
&cGlobals->cp, NULL );
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 ) {
break;
}
len = ntohs( len );
unsigned char buf[len];
nRead = blocking_read( fd, buf, len );
if ( nRead != len ) {
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 ) ) {
handled = server_receiveMessage( cGlobals->game.server,
stream ) || handled;
}
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 ); */
} /* read_pipe_then_close */
typedef enum {
CMD_SKIP_GAMEOVER
,CMD_SHOW_OTHERSCORES
@ -216,6 +267,8 @@ typedef enum {
,CMD_HIDEVALUES
,CMD_SKIPCONFIRM
,CMD_VERTICALSCORE
,CMD_NOPEEK
,CMD_ADDPIPE
#ifdef XWFEATURE_SEARCHLIMIT
,CMD_HINTRECT
#endif
@ -283,6 +336,8 @@ static CmdInfoRec CmdInfoRecs[] = {
,{ CMD_HIDEVALUES, false, "hide-values", "show letters, not nums, on tiles" }
,{ CMD_SKIPCONFIRM, false, "skip-confirm", "don't confirm before commit" }
,{ 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" }
#ifdef XWFEATURE_SEARCHLIMIT
,{ CMD_HINTRECT, false, "hintrect", "enable draggable hint-limits rect" }
#endif
@ -581,13 +636,28 @@ linux_close_socket( CommonGlobals* cGlobals )
close( socket );
}
int
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 ) {
nRead = -1;
break;
}
nRead += siz;
}
return nRead;
}
int
linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize )
{
int sock = cGlobals->socket;
unsigned short tmp;
unsigned short packetSize;
ssize_t nRead = recv( sock, &tmp, sizeof(tmp), 0 );
ssize_t nRead = blocking_read( sock, (unsigned char*)&tmp, sizeof(tmp) );
if ( nRead != 2 ) {
XP_LOGF( "recv => %d, errno=%d (\"%s\")", nRead, errno, strerror(errno) );
linux_close_socket( cGlobals );
@ -597,7 +667,7 @@ linux_relay_receive( CommonGlobals* cGlobals, unsigned char* buf, int bufSize )
packetSize = ntohs( tmp );
assert( packetSize <= bufSize );
nRead = recv( sock, buf, packetSize, 0 );
nRead = blocking_read( sock, buf, packetSize );
if ( nRead < 0 ) {
XP_WARNF( "%s: errno=%d (\"%s\")\n", __func__, errno,
strerror(errno) );
@ -1044,10 +1114,15 @@ main( int argc, char** argv )
case CMD_VERTICALSCORE:
mainParams.verticalScore = XP_TRUE;
break;
case CMD_NOPEEK:
mainParams.allowPeek = XP_FALSE;
case CMD_ADDPIPE:
mainParams.pipe = optarg;
break;
#ifdef XWFEATURE_SLOW_ROBOT
case CMD_SLOWROBOT:
if ( !parsePair( optarg, &mainParams.robotThinkMin,
&mainParams.robotThinkMax ) ) {
&mainParams.robotThinkMax ) ) {
usage(argv[0], "bad param" );
}
break;

View file

@ -64,6 +64,8 @@ XWStreamCtxt* streamFromFile( CommonGlobals* cGlobals, char* name,
void* closure );
void writeToFile( XWStreamCtxt* stream, void* closure );
int blocking_read( int fd, unsigned char* buf, int len );
void linux_close_socket( CommonGlobals* cGlobals );
#ifdef KEYBOARD_NAV
@ -72,4 +74,6 @@ XP_Bool linShiftFocus( CommonGlobals* cGlobals, XP_Key key,
BoardObjectType* nxtP );
#endif
void read_pipe_then_close( CommonGlobals* cGlobals );
#endif

View file

@ -48,6 +48,7 @@ typedef struct LaunchParams {
DictionaryCtxt* dict;
CurGameInfo gi;
char* fileName;
char* pipe;
VTableMgr* vtMgr;
XP_U16 nLocalPlayers;
XP_U16 nHidden;
@ -136,6 +137,7 @@ typedef struct _TimerInfo {
struct CommonGlobals {
LaunchParams* params;
CommonPrefs cp;
XWGame game;
XP_U16 lastNTilesToUse;

View file

@ -128,12 +128,14 @@ launch() {
close_device() {
ID=$1
MVTO=$2
REASON="$3"
if [ ${PIDS[$ID]} -ne 0 ]; then
kill ${PIDS[$ID]} 2>/dev/null
wait ${PIDS[$ID]}
fi
unset PIDS[$ID]
unset CMDS[$ID]
echo "closing game: $REASON" >> ${LOGS[$ID]}
if [ -n "$MVTO" ]; then
[ -f ${FILES[$ID]} ] && mv ${FILES[$ID]} $MVTO
mv ${LOGS[$ID]} $MVTO
@ -178,7 +180,7 @@ maybe_resign() {
if grep -q XWRELAY_ALLHERE $LOG; then
if [ 0 -eq $(($RANDOM % $RESIGN_RATIO)) ]; then
echo "making $LOG $(connName $LOG) resign..."
kill_from_log $LOG && close_device $KEY $DEADDIR
kill_from_log $LOG && close_device $KEY $DEADDIR "resignation forced"
fi
fi
fi
@ -213,13 +215,13 @@ check_game() {
for ID in $OTHERS $KEY; do
echo -n "${LOGS[$ID]}, "
kill_from_log ${LOGS[$ID]} || true
close_device $ID $DONEDIR
close_device $ID $DONEDIR "game over"
done
date
elif grep -q 'relay_error_curses(XWRELAY_ERROR_DELETED)' $LOG; then
echo "deleting $LOG $(connName $LOG) b/c another resigned"
kill_from_log $LOG || true
close_device $KEY $DEADDIR
close_device $KEY $DEADDIR "other resigned"
else
maybe_resign $KEY
fi
@ -239,7 +241,7 @@ run_cmds() {
PIDS[$KEY]=$!
else
sleep 2 # make sure it's had some time
kill ${PIDS[$KEY]}
kill ${PIDS[$KEY]} || true
PIDS[$KEY]=0
check_game $KEY
fi
@ -250,7 +252,7 @@ run_cmds() {
mkdir -p ${LOGDIR}/not_done
echo "processing unfinished games...."
for KEY in ${!CMDS[*]}; do
close_device $KEY ${LOGDIR}/not_done
close_device $KEY ${LOGDIR}/not_done "unfinished game"
done
fi
}
@ -266,4 +268,10 @@ run_cmds
print_stats
wait
echo "*********$0 finished: $(date) (took $(($(date +%s)-$STARTTIME)) seconds)**************"
SECONDS=$(($(date +%s)-$STARTTIME))
HOURS=$((SECONDS/3600))
SECONDS=$((SECONDS%3600))
MINUTES=$((SECONDS/60))
SECONDS=$((SECONDS%60))
echo "*********$0 finished: $(date) (took $HOURS:$MINUTES:$SECONDS)**************"

View file

@ -41,9 +41,10 @@ OBJ = $(patsubst %.cpp,%.o,$(SRC))
LDFLAGS += -pthread -g $(STATIC) \
-L$(shell pg_config --libdir) -lpq
CPPFLAGS += -DSPAWN_SELF -DDO_HTTP -g -Wall \
CPPFLAGS += -DSPAWN_SELF -g -Wall \
-I $(shell pg_config --includedir) \
-DSVN_REV=\"$(shell cat $(GITINFO) 2>/dev/null || echo -n $(HASH) )\"
# CPPFLAGS += -DDO_HTTP
# turn on semaphore debugging
# CPPFLAGS += -DDEBUG_LOCKS

View file

@ -434,14 +434,15 @@ DBMgr::StoreMessage( const char* const connName, int hid,
const unsigned char* buf, int len )
{
size_t newLen;
const char* fmt = "INSERT INTO " MSGS_TABLE " (connname, hid, msg)"
" VALUES( '%s', %d, E'%s')";
const char* fmt = "INSERT INTO " MSGS_TABLE " (connname, hid, msg, msglen)"
" VALUES( '%s', %d, E'%s', %d)";
unsigned char* bytes = PQescapeByteaConn( getThreadConn(), buf, len, &newLen );
assert( NULL != bytes );
char query[newLen+128];
unsigned int siz = snprintf( query, sizeof(query), fmt, connName, hid, bytes );
unsigned int siz = snprintf( query, sizeof(query), fmt, connName, hid,
bytes, len );
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
PQfreemem( bytes );
assert( siz < sizeof(query) );
@ -450,13 +451,14 @@ DBMgr::StoreMessage( const char* const connName, int hid,
}
bool
DBMgr::GetStoredMessage( const char* const connName, int hid,
unsigned char* buf, size_t* buflen, int* msgID )
DBMgr::GetNthStoredMessage( const char* const connName, int hid,
int nn, unsigned char* buf, size_t* buflen,
int* msgID )
{
const char* fmt = "SELECT id, msg FROM " MSGS_TABLE
" WHERE connName = '%s' AND hid = %d ORDER BY id LIMIT 1";
const char* fmt = "SELECT id, msg, msglen FROM " MSGS_TABLE
" WHERE connName = '%s' AND hid = %d ORDER BY id LIMIT 1 OFFSET %d";
char query[256];
snprintf( query, sizeof(query), fmt, connName, hid );
snprintf( query, sizeof(query), fmt, connName, hid, nn );
logf( XW_LOGINFO, "%s: query: %s", __func__, query );
PGresult* result = PQexec( getThreadConn(), query );
@ -465,7 +467,10 @@ DBMgr::GetStoredMessage( const char* const connName, int hid,
bool found = nTuples == 1;
if ( found ) {
*msgID = atoi( PQgetvalue( result, 0, 0 ) );
if ( NULL != msgID ) {
*msgID = atoi( PQgetvalue( result, 0, 0 ) );
}
size_t msglen = atoi( PQgetvalue( result, 0, 2 ) );
/* int len = PQgetlength( result, 0, 1 ); */
const unsigned char* from =
@ -476,11 +481,19 @@ DBMgr::GetStoredMessage( const char* const connName, int hid,
memcpy( buf, bytes, to_length );
PQfreemem( bytes );
*buflen = to_length;
assert( 0 == msglen || to_length == msglen );
}
PQclear( result );
return found;
}
bool
DBMgr::GetStoredMessage( const char* const connName, int hid,
unsigned char* buf, size_t* buflen, int* msgID )
{
return GetNthStoredMessage( connName, hid, 0, buf, buflen, msgID );
}
void
DBMgr::RemoveStoredMessage( int msgID )
{

View file

@ -76,6 +76,8 @@ class DBMgr {
const unsigned char* const buf, int len );
bool GetStoredMessage( const char* const connName, int hid,
unsigned char* buf, size_t* buflen, int* msgID );
bool GetNthStoredMessage( const char* const connName, int hid, int nn,
unsigned char* buf, size_t* buflen, int* msgID );
void RemoveStoredMessage( int msgID );
private:

View file

@ -54,7 +54,8 @@ usage( const char * const argv0 )
fprintf( stderr, "usage: %s \\\n", argv0 );
fprintf( stderr, "\t[-p <port>] # (default %d)\\\n", DEFAULT_PORT );
fprintf( stderr, "\t[-a <host>] # (default: %s)\\\n", DEFAULT_HOST );
fprintf( stderr, "\t -r # list open public rooms\\\n" );
fprintf( stderr, "\t[-r] # list open public rooms\\\n" );
fprintf( stderr, "\t[-f <connName:devid> # fetch message > stdout\\\n" );
fprintf( stderr, "\t[-l <n>] # language for rooms "
"(1=English default)\\\n" );
fprintf( stderr, "\t[-n <n>] # number of players (2 default)\\\n" );
@ -118,7 +119,8 @@ do_rooms( int sockfd, int lang, int nPlayers )
}
static void
do_msgs( int sockfd, const char** connNames, int nConnNames )
write_connnames( int sockfd, char cmd,
const char** connNames, int nConnNames )
{
unsigned short len, netlen;
int ii;
@ -126,7 +128,7 @@ do_msgs( int sockfd, const char** connNames, int nConnNames )
len += 1 + strlen( connNames[ii] );
}
unsigned char hdr[] = { 0, PRX_HAS_MSGS };
unsigned char hdr[] = { 0, cmd };
unsigned short netNConnNames = htons( nConnNames );
netlen = sizeof(hdr) + sizeof( netNConnNames ) + len;
netlen = htons( netlen );
@ -137,6 +139,12 @@ do_msgs( int sockfd, const char** connNames, int nConnNames )
write( sockfd, connNames[ii], strlen(connNames[ii]) );
write( sockfd, "\n", 1 );
}
}
static void
do_msgs( int sockfd, const char** connNames, int nConnNames )
{
write_connnames( sockfd, PRX_HAS_MSGS, connNames, nConnNames );
fprintf( stderr, "Waiting for response....\n" );
unsigned char reply[1024];
@ -159,9 +167,57 @@ do_msgs( int sockfd, const char** connNames, int nConnNames )
fprintf( stdout, "%s -- %d\n", connNames[ii], count );
}
}
} /* do_msgs */
static void
do_fetch( int sockfd, const char** connNames, int nConnNames )
{
assert( 1 == nConnNames );
write_connnames( sockfd, PRX_GET_MSGS, connNames, nConnNames );
fprintf( stderr, "Waiting for response....\n" );
unsigned char reply[1024];
int nRead = read_packet( sockfd, reply, sizeof(reply) );
if ( nRead > 2 ) {
const unsigned char* bufp = reply;
const unsigned char* const end = bufp + nRead;
unsigned short count;
memcpy( &count, bufp, sizeof( count ) );
bufp += sizeof( count );
count = ntohs( count );
assert( count == nConnNames );
fprintf( stderr, "got count: %d\n", count );
/* Now we have an array of <countPerDev> <len><len bytes> pairs. Just
write em as long as it makes sense. countPerDev makes no sense as
other than 1 unless the UI is changed so I don't have to write to
STDOUT -- e.g. by passing in named pipes to correspond to each
deviceid provided */
while ( bufp < end ) {
unsigned short countPerDev;
memcpy( &countPerDev, bufp, sizeof( countPerDev ) );
bufp += sizeof( countPerDev );
countPerDev = ntohs( countPerDev );
while ( bufp < end && countPerDev-- > 0 ) {
unsigned short len;
memcpy( &len, bufp, sizeof( len ) );
len = ntohs( len ) + sizeof( len );
if ( bufp + len > end ) {
break;
}
write( STDOUT_FILENO, bufp, len );
bufp += len;
}
}
if ( bufp != end ) {
fprintf( stderr, "error: message not internally as expected\n" );
}
}
}
static void
do_deletes( int sockfd, const char** connNames, int nConnNames )
{
@ -217,12 +273,13 @@ main( int argc, char * const argv[] )
bool doRooms = false;
bool doMgs = false;
bool doDeletes = false;
bool doFetch = false;
const char* host = DEFAULT_HOST;
char const* connNames[MAX_CONN_NAMES];
int nConnNames = 0;
for ( ; ; ) {
int opt = getopt( argc, argv, "a:d:p:rl:n:m:" );
int opt = getopt( argc, argv, "a:d:f:p:rl:n:m:" );
if ( opt < 0 ) {
break;
}
@ -239,6 +296,10 @@ main( int argc, char * const argv[] )
connNames[nConnNames++] = optarg;
doDeletes = true;
break;
case 'f':
connNames[nConnNames++] = optarg;
doFetch = true;
break;
case 'l':
lang = atoi(optarg);
break;
@ -294,6 +355,12 @@ main( int argc, char * const argv[] )
if ( doDeletes ) {
do_deletes( sockfd, connNames, nConnNames );
}
if ( doFetch ) {
if ( nConnNames != 1 ) {
usage( argv[0] );
}
do_fetch( sockfd, connNames, nConnNames );
}
close( sockfd );

View file

@ -104,19 +104,19 @@ XWThreadPool::Stop()
int ii;
for ( ii = 0; ii < m_nThreads; ++ii ) {
enqueue( 0 );
enqueue( 0, STYPE_UNKNOWN );
}
interrupt_poll();
}
void
XWThreadPool::AddSocket( int socket )
XWThreadPool::AddSocket( int socket, SockType stype )
{
logf( XW_LOGINFO, "%s(%d)", __func__, socket );
{
RWWriteLock ml( &m_activeSocketsRWLock );
m_activeSockets.push_back( socket );
m_activeSockets.push_back( pair<int,SockType>(socket, stype) );
}
interrupt_poll();
}
@ -128,9 +128,9 @@ XWThreadPool::RemoveSocket( int socket )
{
RWWriteLock ml( &m_activeSocketsRWLock );
vector<int>::iterator iter = m_activeSockets.begin();
vector< pair<int,SockType> >::iterator iter = m_activeSockets.begin();
while ( iter != m_activeSockets.end() ) {
if ( *iter == socket ) {
if ( iter->first == socket ) {
m_activeSockets.erase( iter );
found = true;
break;
@ -171,23 +171,27 @@ XWThreadPool::CloseSocket( int socket )
void
XWThreadPool::EnqueueKill( int socket, const char* const why )
{
enqueue( socket, Q_KILL );
enqueue( socket, STYPE_UNKNOWN, Q_KILL );
}
bool
XWThreadPool::get_process_packet( int socket )
XWThreadPool::get_process_packet( int socket, SockType stype )
{
bool success = false;
short packetSize;
assert( sizeof(packetSize) == 2 );
unsigned char buf[MAX_MSG_LEN];
unsigned char buf[MAX_MSG_LEN+1];
int nRead = read_packet( socket, buf, sizeof(buf) );
if ( nRead < 0 ) {
EnqueueKill( socket, "bad packet" );
} else {
} else if ( STYPE_GAME == stype ) {
logf( XW_LOGINFO, "calling m_pFunc" );
success = (*m_pFunc)( buf, nRead, socket );
} else {
buf[nRead] = '\0';
handle_proxy_packet( buf, nRead, socket );
CloseSocket( socket );
}
return success;
} /* get_process_packet */
@ -230,8 +234,8 @@ XWThreadPool::real_tpool_main()
pr.m_socket );
switch ( pr.m_act ) {
case Q_READ:
if ( get_process_packet( pr.m_socket ) ) {
AddSocket( pr.m_socket );
if ( get_process_packet( pr.m_socket, pr.m_type ) ) {
AddSocket( pr.m_socket, pr.m_type );
}
break;
case Q_KILL:
@ -267,6 +271,7 @@ XWThreadPool::real_listener()
int nSocketsAllocd = 1;
struct pollfd* fds = (pollfd*)calloc( nSocketsAllocd, sizeof(fds[0]) );
SockType* stypes = (SockType*)calloc( nSocketsAllocd, sizeof(stypes[0]) );
#ifdef LOG_POLL
char* log = (char*)malloc( 4 * nSocketsAllocd );
#endif
@ -282,31 +287,35 @@ XWThreadPool::real_listener()
if ( nSockets > nSocketsAllocd ) {
fds = (struct pollfd*)realloc( fds, nSockets * sizeof(fds[0]) );
stypes = (SockType*)realloc( stypes, nSockets * sizeof(stypes[0]) );
#ifdef LOG_POLL
log = (char*)realloc( log, nSockets * 4 );
#endif
nSocketsAllocd = nSockets;
}
struct pollfd* curfd = fds;
int curfd = 0;
curfd->fd = m_pipeRead;
curfd->events = flags;
fds[curfd].fd = m_pipeRead;
fds[curfd].events = flags;
#ifdef LOG_POLL
logLen += snprintf( log+logLen, logCapacity - logLen, "%d,", curfd->fd );
logLen += snprintf( log+logLen, logCapacity - logLen, "%d,",
fds[curfd].fd );
#endif
++curfd;
vector<int>::iterator iter = m_activeSockets.begin();
while ( iter != m_activeSockets.end() ) {
curfd->fd = *iter++;
curfd->events = flags;
vector< pair<int,SockType> >::iterator iter;
for ( iter = m_activeSockets.begin(); iter != m_activeSockets.end();
++iter ) {
fds[curfd].fd = iter->first;
stypes[curfd] = iter->second;
fds[curfd].events = flags;
#ifdef LOG_POLL
if ( logCapacity > logLen ) {
logLen += snprintf( log+logLen, logCapacity - logLen, "%d,",
curfd->fd );
fds[curfd].fd );
}
#endif
assert( curfd < fds + nSockets );
assert( curfd < nSockets );
++curfd;
}
pthread_rwlock_unlock( &m_activeSocketsRWLock );
@ -343,13 +352,13 @@ XWThreadPool::real_listener()
if ( nEvents > 0 ) {
--nSockets;
curfd = &fds[1];
curfd = 1;
int ii;
for ( ii = 0; ii < nSockets && nEvents > 0; ++ii ) {
if ( curfd->revents != 0 ) {
int socket = curfd->fd;
if ( fds[curfd].revents != 0 ) {
int socket = fds[curfd].fd;
if ( !RemoveSocket( socket ) ) {
/* no further processing if it's been removed while
we've been sleeping in poll */
@ -357,11 +366,12 @@ XWThreadPool::real_listener()
continue;
}
if ( 0 != (curfd->revents & (POLLIN | POLLPRI)) ) {
if ( 0 != (fds[curfd].revents & (POLLIN | POLLPRI)) ) {
logf( XW_LOGINFO, "enqueuing %d", socket );
enqueue( socket );
enqueue( socket, stypes[curfd] );
} else {
logf( XW_LOGERROR, "odd revents: %x", curfd->revents );
logf( XW_LOGERROR, "odd revents: %x",
fds[curfd].revents );
EnqueueKill( socket, "error/hup in poll()" );
}
--nEvents;
@ -386,10 +396,10 @@ XWThreadPool::listener_main( void* closure )
}
void
XWThreadPool::enqueue( int socket, QAction act )
XWThreadPool::enqueue( int socket, SockType stype, QAction act )
{
MutexLock ml( &m_queueMutex );
QueuePr pr = { act, socket };
QueuePr pr = { act, socket, stype };
m_queue.push_back( pr );
logf( XW_LOGINFO, "calling pthread_cond_signal" );

View file

@ -35,6 +35,8 @@ using namespace std;
class XWThreadPool {
public:
typedef enum { STYPE_UNKNOWN, STYPE_GAME, STYPE_PROXY } SockType;
static XWThreadPool* GetTPool();
typedef bool (*packet_func)( unsigned char* buf, int bufLen, int socket );
typedef void (*kill_func)( int socket );
@ -46,7 +48,7 @@ class XWThreadPool {
void Stop();
/* Add to set being listened on */
void AddSocket( int socket );
void AddSocket( int socket, SockType stype );
/* remove from tpool altogether, and close */
void CloseSocket( int socket );
@ -54,17 +56,18 @@ class XWThreadPool {
private:
typedef enum { Q_READ, Q_KILL } QAction;
typedef struct { QAction m_act; int m_socket; } QueuePr;
typedef struct { QAction m_act; int m_socket; SockType m_type; } QueuePr;
/* Remove from set being listened on */
bool RemoveSocket( int socket );
void enqueue( int socket, QAction act = Q_READ );
void enqueue( int socket, SockType stype, QAction act = Q_READ );
void release_socket_locked( int socket );
void grab_elem_locked( QueuePr* qpp );
void print_in_use( void );
bool get_process_packet( int socket );
bool get_process_packet( int socket, SockType stype );
void interrupt_poll();
void* real_tpool_main();
@ -74,7 +77,7 @@ class XWThreadPool {
static void* listener_main( void* closure );
/* Sockets main thread listens on */
vector<int> m_activeSockets;
vector< pair<int,SockType> >m_activeSockets;
pthread_rwlock_t m_activeSocketsRWLock;
/* Sockets waiting for a thread to read 'em */

View file

@ -12,8 +12,10 @@ HEARTBEAT=60
# Default -- if not set -- is an infinite timeout.
# ALLCONN=300
# How many worker threads in the thread pool? Default is five.
NTHREADS=3
# How many worker threads in the thread pool? Default is five. Let's
# keep this at 1 until the race condition is fixed. All interaction
# with crefs should be from this one thread, including proxy stuff.
NTHREADS=1
# How many seconds to wait for device to ack new connName
DEVACK=3

View file

@ -77,8 +77,6 @@
#include "dbmgr.h"
static int s_nSpawns = 0;
#define MAX_PROXY_LEN 64
#define MAX_PROXY_COUNT 48
void
logf( XW_LogLevel level, const char* format, ... )
@ -193,7 +191,8 @@ parseRelayID( const char* const in, char* buf, HostID* hid )
}
static bool
getNetShort( unsigned char** bufpp, unsigned char* end, unsigned short* out )
getNetShort( unsigned char** bufpp, const unsigned char* end,
unsigned short* out )
{
bool ok = *bufpp + 2 <= end;
if ( ok ) {
@ -206,7 +205,8 @@ getNetShort( unsigned char** bufpp, unsigned char* end, unsigned short* out )
} /* getNetShort */
static bool
getNetByte( unsigned char** bufpp, unsigned char* end, unsigned char* out )
getNetByte( unsigned char** bufpp, const unsigned char* end,
unsigned char* out )
{
bool ok = *bufpp < end;
if ( ok ) {
@ -683,7 +683,7 @@ read_packet( int sock, unsigned char* buf, int buflen )
nread = recv( sock, &msgLen, sizeof(msgLen), MSG_WAITALL );
if ( nread == sizeof(msgLen) ) {
msgLen = ntohs( msgLen );
if ( msgLen <= buflen ) {
if ( msgLen < buflen ) {
nread = recv( sock, buf, msgLen, MSG_WAITALL );
if ( nread == msgLen ) {
result = nread;
@ -693,16 +693,82 @@ read_packet( int sock, unsigned char* buf, int buflen )
return result;
}
static void*
handle_proxy_tproc( void* closure )
static void
pushShort( vector<unsigned char>& out, unsigned short num )
{
blockSignals();
int sock = (int)closure;
num = htons( num );
out.insert( out.end(), (unsigned char*)&num, ((unsigned char*)&num) + 2 );
}
unsigned char buf[MAX_PROXY_MSGLEN];
int len = read_packet( sock, buf, sizeof(buf)-1 );
static void
pushMsgs( vector<unsigned char>& out, DBMgr* dbmgr, const char* connName,
HostID hid, int msgCount )
{
int ii;
for ( ii = 0; ii < msgCount; ++ii ) {
unsigned char buf[1024];
size_t buflen = sizeof(buf);
if ( !dbmgr->GetNthStoredMessage( connName, hid, ii, buf,
&buflen, NULL ) ) {
logf( XW_LOGERROR, "%s: %dth message not there", __func__, ii );
break;
}
pushShort( out, buflen );
out.insert( out.end(), buf, buf + buflen );
}
}
static void
handleMsgsMsg( int sock, bool sendFull,
unsigned char* bufp, const unsigned char* end )
{
unsigned short nameCount;
if ( getNetShort( &bufp, end, &nameCount ) ) {
char* in = (char*)bufp;
DBMgr* dbmgr = DBMgr::Get();
unsigned short count;
/* This is wrong now */
/* reply format: PRX_GET_MSGS case: <message len><n_msgs>[<len><msg>]*
* PRX_HAS_MSGS case: <message len><n_msgs><count>*
*/
vector<unsigned char> out(4); /* space for len and n_msgs */
assert( out.size() == 4 );
char* saveptr;
for ( count = 0; ; ++count ) {
char* name = strtok_r( in, "\n", &saveptr );
if ( NULL == name ) {
break;
}
HostID hid;
char connName[MAX_CONNNAME_LEN+1];
if ( !parseRelayID( name, connName, &hid ) ) {
break;
}
/* For each relayID, write the number of messages and then each
message (in the getmsg case) */
int msgCount = dbmgr->PendingMsgCount( connName, hid );
pushShort( out, msgCount );
if ( sendFull ) {
pushMsgs( out, dbmgr, connName, hid, msgCount );
}
in = NULL;
}
unsigned short tmp = htons( out.size() - sizeof(tmp) );
memcpy( &out[0], &tmp, sizeof(tmp) );
tmp = htons( count );
memcpy( &out[2], &tmp, sizeof(tmp) );
write( sock, &out[0], out.size() );
}
}
void
handle_proxy_packet( unsigned char* buf, int len, int sock )
{
if ( len > 0 ) {
buf[len] = '\0'; /* so can use strtok */
unsigned char* bufp = buf;
unsigned char* end = bufp + len;
if ( (0 == *bufp++) ) { /* protocol */
@ -729,42 +795,12 @@ handle_proxy_tproc( void* closure )
}
break;
case PRX_HAS_MSGS:
case PRX_GET_MSGS:
if ( len >= 2 ) {
unsigned short nameCount;
if ( getNetShort( &bufp, end, &nameCount ) ) {
char* in = (char*)bufp;
char* saveptr;
vector<int> ids;
for ( ; ; ) {
char* name = strtok_r( in, "\n", &saveptr );
if ( NULL == name ) {
break;
}
HostID hid;
char connName[MAX_CONNNAME_LEN+1];
if ( parseRelayID( name, connName, &hid ) ) {
ids.push_back( DBMgr::Get()->
PendingMsgCount( connName, hid ) );
}
in = NULL;
}
unsigned short len =
(ids.size() * sizeof(unsigned short))
+ sizeof( unsigned short );
len = htons( len );
write( sock, &len, sizeof(len) );
len = htons( nameCount );
write( sock, &len, sizeof(len) );
vector<int>::const_iterator iter;
for ( iter = ids.begin(); iter != ids.end(); ++iter ) {
unsigned short num = *iter;
num = htons( num );
write( sock, &num, sizeof(num) );
}
}
handleMsgsMsg( sock, PRX_GET_MSGS == cmd, bufp, end );
}
break;
break; /* PRX_HAS_MSGS */
case PRX_DEVICE_GONE:
logf( XW_LOGINFO, "%s: got PRX_DEVICE_GONE", __func__ );
if ( len >= 2 ) {
@ -799,24 +835,11 @@ handle_proxy_tproc( void* closure )
}
len = 0; /* return a 0-length message */
write( sock, &len, sizeof(len) );
break;
break; /* PRX_DEVICE_GONE */
}
}
}
sleep( 2 );
close( sock );
return NULL;
} /* handle_proxy_tproc */
static void
handle_proxy_connect( int sock )
{
pthread_t thread;
if ( 0 == pthread_create( &thread, NULL, handle_proxy_tproc,
(void*)sock ) ) {
pthread_detach( thread );
}
} /* handle_proxy_connect */
} /* handle_proxy_packet */
int
main( int argc, char** argv )
@ -839,17 +862,13 @@ main( int argc, char** argv )
/* Verify sizes here... */
assert( sizeof(CookieID) == 2 );
/* Read options. Options trump config file values when they conflict, but
the name of the config file is an option so we have to get that
first. */
for ( ; ; ) {
int opt = getopt(argc, argv, "h?c:p:n:i:f:l:t:"
#ifdef DO_HTTP
"w:s:"
#endif
int opt = getopt(argc, argv, "h?c:p:n:i:f:l:t:s:w:"
"DF" );
if ( opt == -1 ) {
@ -870,6 +889,11 @@ main( int argc, char** argv )
case 's':
cssFile = optarg;
break;
#else
case 'w':
case 's':
fprintf( stderr, "option -%c disabled and ignored\n", opt );
break;
#endif
case 'D':
doDaemon = false;
@ -1120,15 +1144,14 @@ main( int argc, char** argv )
int newSock = accept( listener, (sockaddr*)&newaddr,
&siz );
if ( perGame ) {
logf( XW_LOGINFO,
"accepting connection from %s on socket %d",
inet_ntoa(newaddr.sin_addr), newSock );
logf( XW_LOGINFO,
"accepting connection from %s on socket %d",
inet_ntoa(newaddr.sin_addr), newSock );
tPool->AddSocket( newSock,
perGame ? XWThreadPool::STYPE_GAME
: XWThreadPool::STYPE_PROXY );
tPool->AddSocket( newSock );
} else {
handle_proxy_connect( newSock );
}
--retval;
}
}

View file

@ -154,6 +154,7 @@ enum { PRX_NONE /* 0 is an illegal value */
,PRX_PUB_ROOMS /* list all public rooms for lang/nPlayers */
,PRX_HAS_MSGS /* return message counts for connName/devid array */
,PRX_DEVICE_GONE /* return message counts for connName/devid array */
,PRX_GET_MSGS /* return full messages for connName/devid array */
}
#ifndef CANT_DO_TYPEDEF
XWPRXYCMD

View file

@ -54,6 +54,7 @@ id SERIAL
,hid INTEGER
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
,msg BYTEA
,msglen INTEGER
,UNIQUE ( connName, hid, msg )
);
EOF

View file

@ -30,6 +30,7 @@ int GetNSpawns(void);
int make_socket( unsigned long addr, unsigned short port );
int read_packet( int sock, unsigned char* buf, int buflen );
void handle_proxy_packet( unsigned char* buf, int bufLen, int socket );
const char* cmdToStr( XWRELAY_Cmd cmd );