mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-02-06 20:45:54 +01:00
Merge branch 'android_branch' of ssh://xwords.git.sourceforge.net/gitroot/xwords/xwords into android_branch
This commit is contained in:
commit
70f52b162b
24 changed files with 512 additions and 281 deletions
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
1
xwords4/dawg/.gitignore
vendored
1
xwords4/dawg/.gitignore
vendored
|
@ -2,5 +2,6 @@
|
|||
*.xwd
|
||||
*.pdb
|
||||
*.stamp
|
||||
*.dict
|
||||
*.dict.gz
|
||||
dict2dawg
|
||||
|
|
|
@ -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,
|
||||
¶ms->gi, dict, params->util,
|
||||
(DrawCtx*)g_globals.draw,
|
||||
&g_globals.cp, &procs );
|
||||
(void)game_makeFromStream( MEMPOOL stream, &g_globals.cGlobals.game,
|
||||
¶ms->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, ¶ms->gi,
|
||||
params->util, (DrawCtx*)g_globals.draw,
|
||||
&g_globals.cGlobals.cp, &procs );
|
||||
}
|
||||
} else {
|
||||
game_makeNewGame( MEMPOOL &g_globals.cGlobals.game, ¶ms->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, ¶ms->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, ¶ms->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,
|
||||
|
|
|
@ -58,7 +58,6 @@ struct CursesAppGlobals {
|
|||
|
||||
DictionaryCtxt* dictionary;
|
||||
EngineCtxt* engine;
|
||||
CommonPrefs cp;
|
||||
|
||||
XP_Bool amServer; /* this process acting as server */
|
||||
|
||||
|
|
|
@ -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, ¶ms->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 );
|
||||
|
||||
|
|
|
@ -119,8 +119,6 @@ typedef struct GtkAppGlobals {
|
|||
XP_UCHAR stateChar;
|
||||
#endif
|
||||
|
||||
CommonPrefs cp;
|
||||
|
||||
XP_Bool gridOn;
|
||||
XP_Bool dropIncommingMsgs;
|
||||
XP_Bool mouseDown;
|
||||
|
|
|
@ -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,
|
||||
¶ms->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, ¶ms->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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)**************"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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" );
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -54,6 +54,7 @@ id SERIAL
|
|||
,hid INTEGER
|
||||
,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||
,msg BYTEA
|
||||
,msglen INTEGER
|
||||
,UNIQUE ( connName, hid, msg )
|
||||
);
|
||||
EOF
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue