fix and cleanup linux client to move to using tcp. Add the ability to

deal with socket dying and (maybe) being replaced.  Only connect on
demand now, when first packet's ready to go.
This commit is contained in:
ehouse 2005-03-19 22:07:53 +00:00
parent 820664d212
commit 3d54ec402a
5 changed files with 122 additions and 76 deletions

View file

@ -83,16 +83,6 @@ cursesUserError( CursesAppGlobals* globals, char* format, ... )
va_end(ap);
} /* cursesUserError */
static void
curses_util_listenPortChange( XW_UtilCtxt* uc, XP_U16 newPort )
{
CursesAppGlobals* globals = (CursesAppGlobals*)uc->closure;
XP_LOGF( "listenPortChange called: not sure what to do" );
/* if this isn't true, need to tear down and rebind socket */
XP_ASSERT( newPort == globals->cGlobals.params->defaultListenPort );
} /* curses_util_listenPortChange */
static XP_S16
curses_util_userPickTile( XW_UtilCtxt* uc, const PickInfo* pi, XP_U16 playerNum,
const XP_UCHAR4* texts, XP_U16 nTiles )
@ -598,13 +588,40 @@ cursesListenOnSocket( CursesAppGlobals* globals, int newSock,
globals->fdArray[globals->fdCount].fd = newSock;
globals->fdArray[globals->fdCount].events = POLLIN;
globals->streams[globals->fdCount] = stream;
++globals->fdCount;
XP_LOGF( "listenOnSocket: there are now %d sources to poll",
globals->fdCount );
} /* cursesListenOnSocket */
static void
curses_stop_listening( CursesAppGlobals* globals, int sock )
{
int count = globals->fdCount;
int i, found = 0;
for ( i = 0; i < count; ++i ) {
if ( globals->fdArray[i].fd == sock ) {
found = 1;
} else if ( found ) {
globals->fdArray[i-1].fd = globals->fdArray[i].fd;
}
}
assert( found );
--globals->fdCount;
} /* curses_stop_listening */
static void
curses_socket_changed( void* closure, int oldSock, int newSock )
{
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
if ( oldSock != -1 ) {
curses_stop_listening( globals, oldSock );
}
if ( newSock != -1 ) {
cursesListenOnSocket( globals, newSock, NULL );
}
} /* curses_socket_changed */
/*
* Ok, so this doesn't block yet....
@ -661,17 +678,18 @@ blocking_gotEvent( CursesAppGlobals* globals, int* ch )
CommsAddrRec addrRec;
XP_MEMSET( &addrRec, 0, sizeof(addrRec) );
addrRec.conType = COMMS_CONN_IP;
addrRec.conType = COMMS_CONN_RELAY;
addrRec.u.ip.ipAddr = ntohl(addr_sock.sin_addr.s_addr);
addrRec.u.ip_relay.ipAddr =
ntohl(addr_sock.sin_addr.s_addr);
XP_LOGF( "captured incomming ip address: 0x%lx",
addrRec.u.ip.ipAddr );
addrRec.u.ip_relay.ipAddr );
if ( comms_checkIncomingStream(globals->cGlobals.game.comms,
inboundS,
&addrRec ) ) {
XP_LOGF( "comms read port: %d",
addrRec.u.ip.port );
addrRec.u.ip_relay.port );
redraw =
server_receiveMessage( globals->cGlobals.game.server,
inboundS );
@ -777,7 +795,7 @@ cursesSendOnClose( XWStreamCtxt* stream, void* closure )
CursesAppGlobals* globals = (CursesAppGlobals*)closure;
XP_LOGF( "cursesSendOnClose called" );
result = comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream );
result = comms_send( globals->cGlobals.game.comms, stream );
} /* cursesSendOnClose */
static XWStreamCtxt*
@ -814,8 +832,6 @@ setupCursesUtilCallbacks( CursesAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_setTimer = curses_util_setTimer;
util->vtable->m_util_requestTime = curses_util_requestTime;
util->vtable->m_util_listenPortChange = curses_util_listenPortChange;
util->closure = globals;
} /* setupCursesUtilCallbacks */
@ -825,7 +841,7 @@ sendOnClose( XWStreamCtxt* stream, void* closure )
CursesAppGlobals* globals = closure;
XP_LOGF( "curses sendOnClose called" );
XP_ASSERT( !!globals->cGlobals.game.comms );
comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream );
comms_send( globals->cGlobals.game.comms, stream );
} /* sendOnClose */
static XP_Bool
@ -858,7 +874,6 @@ void
cursesmain( XP_Bool isServer, LaunchParams* params )
{
int piperesult;
int sock;
DictionaryCtxt* dict;
CommsAddrRec addr;
XP_U16 gameID;
@ -869,6 +884,9 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
globals.cGlobals.params = params;
globals.cGlobals.socket = -1;
globals.cGlobals.socketChanged = curses_socket_changed;
globals.cGlobals.socketChangedClosure = &globals;
globals.cp.showBoardArrow = XP_TRUE;
globals.cp.showRobotScores = params->showRobotScores;
@ -883,11 +901,8 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
piperesult = pipe( globals.timepipe );
XP_ASSERT( piperesult == 0 );
cursesListenOnSocket( &globals, globals.timepipe[0], NULL ); /* reader pipe */
sock = linux_init_socket( &globals.cGlobals );
cursesListenOnSocket( &globals, sock, NULL );
/* reader pipe */
cursesListenOnSocket( &globals, globals.timepipe[0], NULL );
signal( SIGWINCH, SIGWINCH_handler );
initCurses( &globals );
@ -898,11 +913,14 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
params->util, (DrawCtx*)globals.draw,
gameID, &globals.cp, linux_tcp_send, &globals );
addr.conType = COMMS_CONN_IP;
addr.u.ip.ipAddr = 0; /* ??? */
addr.u.ip.port = params->defaultSendPort;
comms_setAddr( globals.cGlobals.game.comms,
&addr, params->defaultListenPort );
addr.conType = COMMS_CONN_RELAY;
addr.u.ip_relay.ipAddr = 0; /* ??? */
addr.u.ip_relay.port = params->defaultSendPort;
XP_STRNCPY( addr.u.ip_relay.hostName, params->relayName,
sizeof(addr.u.ip_relay.hostName) - 1 );
XP_STRNCPY( addr.u.ip_relay.cookie, params->cookie,
sizeof(addr.u.ip_relay.cookie) - 1 );
comms_setAddr( globals.cGlobals.game.comms, &addr );
model_setDictionary( globals.cGlobals.game.model, params->dict );
@ -926,12 +944,6 @@ cursesmain( XP_Bool isServer, LaunchParams* params )
&globals,
(XP_PlayerAddr)0,
sendOnClose ) );
#if 0
cursesListenOnSocket(
&globals, NULL, /* replaces below */
/* linux_getStreamSocket( params->info.clientInfo.stream ), */
params->info.clientInfo.stream );
#endif
} else {
cursesUserError( &globals, "Unable to open connection to server");
exit( 0 );

View file

@ -95,7 +95,6 @@ struct CursesAppGlobals {
struct sockaddr_in listenerSockAddr;
short fdCount;
struct pollfd fdArray[FD_MAX]; /* one for stdio, one for listening socket */
XWStreamCtxt* streams[FD_MAX]; /* [0], for stdin, will be null.... */
int timepipe[2]; /* for reading/writing "user events" */
};

View file

@ -249,9 +249,11 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget )
stream_destroy( stream );
} else { /* not reading from a saved file */
XP_U16 gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util );
XP_U16 gameID;
CommsAddrRec addr;
gameID = (XP_U16)util_getCurSeconds( globals->cGlobals.params->util );
XP_ASSERT( !!params->relayName );
globals->cGlobals.defaultServerName = params->relayName;
@ -262,11 +264,16 @@ createOrLoadObjects( GtkAppGlobals* globals, GtkWidget *widget )
params->util, (DrawCtx*)globals->draw,
gameID, &globals->cp, linux_tcp_send, globals );
addr.conType = COMMS_CONN_IP;
addr.u.ip.ipAddr = 0; /* ??? */
addr.u.ip.port = params->defaultSendPort;
comms_setAddr( globals->cGlobals.game.comms,
&addr, params->defaultListenPort );
addr.conType = COMMS_CONN_RELAY;
addr.u.ip_relay.ipAddr = 0;
addr.u.ip_relay.port = params->defaultSendPort;
XP_STRNCPY( addr.u.ip_relay.hostName, params->relayName,
sizeof(addr.u.ip_relay.hostName) - 1 );
XP_STRNCPY( addr.u.ip_relay.cookie, params->cookie,
sizeof(addr.u.ip_relay.cookie) - 1 );
/* This may trigger network activity */
comms_setAddr( globals->cGlobals.game.comms, &addr );
model_setDictionary( globals->cGlobals.game.model, params->dict );
@ -1141,18 +1148,6 @@ gtk_util_makeStreamFromAddr(XW_UtilCtxt* uc, XP_PlayerAddr channelNo )
return stream;
} /* gtk_util_makeStreamFromAddr */
static void
gtk_util_listenPortChange( XW_UtilCtxt* uc, XP_U16 newPort )
{
#ifdef DEBUG
GtkAppGlobals* globals = (GtkAppGlobals*)uc->closure;
#endif
XP_LOGF( "listenPortChange called: not sure what to do" );
/* if this isn't true, need to tear down and rebind socket */
XP_ASSERT( newPort == globals->cGlobals.params->defaultListenPort );
} /* gtk_util_listenPortChange */
#ifdef XWFEATURE_SEARCHLIMIT
static XP_Bool
gtk_util_getTraySearchLimits( XW_UtilCtxt* uc, XP_U16* min, XP_U16* max )
@ -1244,24 +1239,24 @@ makeShowButtonFromBitmap( GtkAppGlobals* globals, GtkWidget* parent,
GtkStyle *style;
if ( file_exists( fileName ) ) {
button = gtk_button_new();
button = gtk_button_new();
style = gtk_widget_get_style(parent);
style = gtk_widget_get_style(parent);
pixmap = gdk_pixmap_create_from_xpm( parent->window, &mask,
&style->bg[GTK_STATE_NORMAL],
fileName );
pixmapWid = gtk_pixmap_new( pixmap, mask );
gtk_container_add( GTK_CONTAINER(button), pixmapWid );
pixmap = gdk_pixmap_create_from_xpm( parent->window, &mask,
&style->bg[GTK_STATE_NORMAL],
fileName );
pixmapWid = gtk_pixmap_new( pixmap, mask );
gtk_container_add( GTK_CONTAINER(button), pixmapWid );
gtk_widget_show( pixmapWid );
gtk_widget_show( pixmapWid );
} else {
button = gtk_button_new_with_label( alt );
button = gtk_button_new_with_label( alt );
}
gtk_widget_show( button );
if ( func != NULL ) {
gtk_signal_connect( GTK_OBJECT(button), "clicked", func, globals );
gtk_signal_connect( GTK_OBJECT(button), "clicked", func, globals );
}
return button;
@ -1394,10 +1389,6 @@ setupGtkUtilCallbacks( GtkAppGlobals* globals, XW_UtilCtxt* util )
util->vtable->m_util_getTraySearchLimits = gtk_util_getTraySearchLimits;
#endif
#ifdef BEYOND_IR
util->vtable->m_util_listenPortChange = gtk_util_listenPortChange;
#endif
util->closure = globals;
} /* setupGtkUtilCallbacks */
@ -1430,7 +1421,7 @@ newConnectionInput( GIOChannel *source,
inboundS = stream_from_msgbuf( &globals->cGlobals, buf, nRead );
if ( !!inboundS ) {
if ( comms_checkIncomingStream( globals->cGlobals.game.comms,
inboundS, NULL ) ) {
inboundS, NULL ) ) {
redraw = server_receiveMessage(globals->cGlobals.game.server
, inboundS );
}
@ -1470,6 +1461,19 @@ gtkListenOnSocket( GtkAppGlobals* globals, int newSock )
XP_LOGF( "g_io_add_watch => %d", result );
} /* gtkListenOnSocket */
static void
gtk_socket_changed( void* closure, int oldSock, int newSock )
{
GtkAppGlobals* globals = (GtkAppGlobals*)closure;
if ( oldSock != -1 ) {
g_source_remove( oldSock );
XP_LOGF( "Removed %d from gtk's list of listened-to sockets" );
}
if ( newSock != -1 ) {
gtkListenOnSocket( globals, newSock );
}
}
static void
sendOnClose( XWStreamCtxt* stream, void* closure )
{
@ -1477,7 +1481,7 @@ sendOnClose( XWStreamCtxt* stream, void* closure )
GtkAppGlobals* globals = closure;
XP_LOGF( "sendOnClose called" );
result = comms_send( globals->cGlobals.game.comms, COMMS_CONN_IP, stream );
result = comms_send( globals->cGlobals.game.comms, stream );
} /* sendOnClose */
static void
@ -1507,6 +1511,9 @@ gtkmain( XP_Bool isServer, LaunchParams* params, int argc, char *argv[] )
globals.cGlobals.lastNTilesToUse = MAX_TRAY_TILES;
globals.cGlobals.socket = -1;
globals.cGlobals.socketChanged = gtk_socket_changed;
globals.cGlobals.socketChangedClosure = &globals;
globals.cp.showBoardArrow = XP_TRUE;
globals.cp.showRobotScores = params->showRobotScores;

View file

@ -197,6 +197,7 @@ usage( char* appName, char* msg )
"\t [-v] # put scoreboard in vertical mode\n"
"\t [-m] # make the robot duMb (smart is default)\n"
"\t [-c] # explain robot scores after each move\n"
"\t [-C COOKIE] # cookie used to groups games on relay\n"
"\t\t # (max of four players total, local and remote)\n"
"\t [-b boardSize] # number of columns and rows\n"
"\t [-e random_seed] \n"
@ -228,12 +229,29 @@ linux_tcp_send( XP_U8* buf, XP_U16 buflen, CommsAddrRec* addrRec,
if ( socket == -1 ) {
XP_STATUSF( "linux_tcp_send: socket uninitialized" );
} else {
socket = linux_init_socket( globals );
if ( socket != -1 ) {
assert( globals->socket == socket );
(*globals->socketChanged)( globals->socketChangedClosure,
-1, socket );
}
}
if ( socket != -1 ) {
XP_U16 netLen = htons( buflen );
errno = 0;
(void)send( socket, &netLen, sizeof(netLen), 0 );
result = send( socket, buf, buflen, 0 );
result = send( socket, &netLen, sizeof(netLen), 0 );
if ( result == sizeof(netLen) ) {
result = send( socket, buf, buflen, 0 );
}
if ( result <= 0 ) {
XP_STATUSF( "closing non-functional socket" );
close( socket );
(*globals->socketChanged)( globals->socketChangedClosure,
socket, -1 );
globals->socket = -1;
}
XP_STATUSF( "linux_tcp_send: send returned %d of %d (err=%d)",
result, buflen, errno );
@ -512,6 +530,7 @@ main( int argc, char** argv )
mainParams.defaultListenPort = DEFAULT_LISTEN_PORT;
mainParams.defaultSendPort = DEFAULT_SEND_PORT;
mainParams.trayOverlaps = XP_FALSE;
mainParams.cookie = "COOKIE";
mainParams.gi.boardSize = 15;
mainParams.quitAfter = XP_FALSE;
mainParams.sleepOnAnchor = XP_FALSE;
@ -519,6 +538,7 @@ main( int argc, char** argv )
mainParams.undoWhenDone = XP_FALSE;
mainParams.gi.timerEnabled = XP_FALSE;
mainParams.gi.robotSmartness = SMART_ROBOT;
/* serverName = mainParams.info.clientInfo.serverName = "localhost"; */
#if defined PLATFORM_GTK
@ -540,7 +560,7 @@ main( int argc, char** argv )
#if defined PLATFORM_GTK
"o"
#endif
"kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:Umvc" );
"kKf:l:n:Nsd:a:p:e:r:b:qw:Sit:UmvcC:" );
switch( opt ) {
case 'h':
case '?':
@ -549,6 +569,9 @@ main( int argc, char** argv )
case 'c':
mainParams.showRobotScores = XP_TRUE;
break;
case 'C':
mainParams.cookie = optarg;
break;
case 'd':
mainParams.gi.dictName = copyString( MPPARM(mainParams.util->mpool)
optarg );

View file

@ -43,6 +43,7 @@ typedef struct LaunchParams {
DictionaryCtxt* dict;
CurGameInfo gi;
char* fileName;
char* cookie;
VTableMgr* vtMgr;
XP_U16 nLocalPlayers;
XP_Bool trayOverlaps; /* probably only interesting for GTK case */
@ -69,6 +70,8 @@ typedef struct LaunchParams {
} LaunchParams;
typedef void (*SocketChangedFunc)(void* closure, int oldsock, int newsock );
typedef struct CommonGlobals {
LaunchParams* params;
@ -77,6 +80,8 @@ typedef struct CommonGlobals {
/* UDP comms stuff */
char* defaultServerName;
int socket;
SocketChangedFunc socketChanged;
void* socketChangedClosure;
} CommonGlobals;
#endif