first set of networking changes testing per-device communication with

relay on behalf of a number of games.  Works as long as all the games
are open.
This commit is contained in:
Eric House 2013-01-16 06:46:33 -08:00
parent f6e7ece578
commit a6784464ff
12 changed files with 498 additions and 65 deletions

View file

@ -204,6 +204,7 @@ OBJ = \
$(BUILD_PLAT_DIR)/linuxdict.o \
$(BUILD_PLAT_DIR)/linuxutl.o \
$(BUILD_PLAT_DIR)/gamesdb.o \
$(BUILD_PLAT_DIR)/relaycon.o \
$(CURSES_OBJS) $(GTK_OBJS) $(MAIN_OBJS)
LIBS = -lm -luuid $(GPROFFLAG)

View file

@ -94,13 +94,6 @@ struct CursesAppGlobals {
#endif
};
#ifdef USE_GLIBLOOP
typedef struct _SourceData {
GIOChannel* channel;
gint watch;
} SourceData;
#endif
DrawCtx* cursesDrawCtxtMake( WINDOW* boardWin );
/* Ports: Client and server pick a port at startup on which they'll listen.

View file

@ -32,7 +32,7 @@ openGamesDB( const char* dbName )
int result = sqlite3_open( dbName, &pDb );
XP_ASSERT( SQLITE_OK == result );
const char* createStr =
const char* createGamesStr =
"CREATE TABLE games ( "
"game BLOB"
",room VARCHAR(32)"
@ -41,10 +41,12 @@ openGamesDB( const char* dbName )
",nmoves INT"
",nmissing INT(2)"
")";
result = sqlite3_exec( pDb, createGamesStr, NULL, NULL, NULL );
result = sqlite3_exec( pDb, createStr, NULL, NULL, NULL );
const char* createValuesStr =
"CREATE TABLE pairs ( key TEXT UNIQUE,value TEXT )";
result = sqlite3_exec( pDb, createValuesStr, NULL, NULL, NULL );
XP_LOGF( "sqlite3_exec=>%d", result );
// XP_ASSERT( SQLITE_OK == result );
return pDb;
}
@ -214,6 +216,39 @@ loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
return XP_TRUE;
}
void
store( sqlite3* pDb, const gchar* key, const gchar* value )
{
char buf[256];
snprintf( buf, sizeof(buf),
"INSERT OR REPLACE INTO pairs (key, value) VALUES ('%s', '%s')",
key, value );
sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result );
result = sqlite3_step( ppStmt );
XP_ASSERT( SQLITE_DONE == result );
sqlite3_finalize( ppStmt );
}
void
fetch( sqlite3* pDb, const gchar* key, gchar* buf, gint buflen )
{
char query[256];
snprintf( query, sizeof(query),
"SELECT value from pairs where key = '%s'", key );
sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result );
result = sqlite3_step( ppStmt );
if ( SQLITE_ROW == result ) {
getColumnText( ppStmt, 0, buf, buflen );
} else {
buf[0] = '\0';
}
sqlite3_finalize( ppStmt );
}
static void
getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf, int len )
{

View file

@ -48,4 +48,9 @@ GSList* listGames( GtkAppGlobals* apg );
XP_Bool getGameInfo( GtkAppGlobals* apg, sqlite3_int64 rowid, GameInfo* gib );
XP_Bool loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid );
#define KEY_RDEVID "RDEVID"
void store( sqlite3* dbp, const gchar* key, const gchar* value );
void fetch( sqlite3* dbp, const gchar* key, gchar* buf, gint buflen );
#endif

View file

@ -1,6 +1,7 @@
/* -*-mode: C; fill-column: 78; c-basic-offset: 4; compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2000-2009 by Eric House (xwords@eehouse.org). All rights reserved.
* Copyright 2000-2013 by Eric House (xwords@eehouse.org). All rights
* reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@ -498,6 +499,9 @@ createOrLoadObjects( GtkGameGlobals* globals )
#endif
}
/* Need to save in order to have a valid selRow for the first send */
saveGame( cGlobals );
#ifndef XWFEATURE_STANDALONE_ONLY
/* This may trigger network activity */
if ( !!cGlobals->game.comms ) {
@ -530,6 +534,12 @@ createOrLoadObjects( GtkGameGlobals* globals )
}
}
if ( !params->fileName ) {
XP_UCHAR buf[64];
snprintf( buf, sizeof(buf), "clientToken: %lld", cGlobals->selRow );
gtk_window_set_title( GTK_WINDOW(globals->window), buf );
}
#ifndef XWFEATURE_STANDALONE_ONLY
if ( !!globals->cGlobals.game.comms ) {
comms_start( globals->cGlobals.game.comms );
@ -693,6 +703,7 @@ destroy_window( GtkWidget* XP_UNUSED(widget), gpointer data )
{
LOG_FUNC();
GtkGameGlobals* globals = (GtkGameGlobals*)data;
comms_stop( globals->cGlobals.game.comms );
saveGame( &globals->cGlobals );
windowDestroyed( globals );
// gtk_main_quit();
@ -2219,7 +2230,7 @@ newConnectionInput( GIOChannel *source,
return keepSource; /* FALSE means to remove event source */
} /* newConnectionInput */
typedef struct SockInfo {
typedef struct _SockInfo {
GIOChannel* channel;
guint watch;
int socket;
@ -2547,4 +2558,37 @@ makeNewGame( GtkGameGlobals* globals )
return success;
}
void
gameGotBuf( GtkGameGlobals* globals, XP_U8* buf, XP_U16 len )
{
XP_Bool redraw = XP_FALSE;
XWStreamCtxt* stream = stream_from_msgbuf( &globals->cGlobals, buf, len );
if ( !!stream ) {
if ( comms_checkIncomingStream( globals->cGlobals.game.comms,
stream, NULL ) ) {
redraw =
server_receiveMessage( globals->cGlobals.game.server,
stream );
if ( redraw ) {
saveGame( &globals->cGlobals );
}
}
stream_destroy( stream );
}
/* if there's something to draw resulting from the message, we
need to give the main loop time to reflect that on the screen
before giving the server another shot. So just call the idle
proc. */
if ( redraw ) {
gtk_util_requestTime( globals->cGlobals.util );
} else {
redraw = server_do( globals->cGlobals.game.server );
}
if ( redraw ) {
board_draw( globals->cGlobals.game.board );
}
}
#endif /* PLATFORM_GTK */

View file

@ -169,7 +169,7 @@ typedef struct GtkGameGlobals {
void initGlobals( GtkGameGlobals* globals, LaunchParams* params );
void freeGlobals( GtkGameGlobals* globals );
XP_Bool makeNewGame( GtkGameGlobals* globals );
void gameGotBuf( GtkGameGlobals* globals, XP_U8* buf, XP_U16 len );
#endif /* PLATFORM_GTK */

View file

@ -515,7 +515,8 @@ gtk_draw_drawCell( DrawCtx* p_dctx, const XP_Rect* rect, const XP_UCHAR* letter,
{
GtkDrawCtx* dctx = (GtkDrawCtx*)p_dctx;
XP_Rect rectInset = *rect;
XP_Bool showGrid = dctx->globals->gridOn;
GtkGameGlobals* globals = dctx->globals;
XP_Bool showGrid = globals->gridOn;
XP_Bool highlight = (flags & CELL_HIGHLIGHT) != 0;
GdkColor* cursor =
((flags & CELL_ISCURSOR) != 0) ? &dctx->cursor : NULL;

View file

@ -20,11 +20,12 @@
#ifdef PLATFORM_GTK
#include "xptypes.h"
#include "main.h"
#include "gtkmain.h"
#include "gamesdb.h"
#include "gtkboard.h"
#include "linuxmain.h"
#include "relaycon.h"
static void onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid,
XP_Bool isNew );
@ -54,6 +55,22 @@ gameIsOpen( GtkAppGlobals* apg, sqlite3_int64 rowid )
return found;
}
static GtkGameGlobals*
findGame( const GtkAppGlobals* apg, XP_U32 clientToken )
{
GtkGameGlobals* result = NULL;
GSList* iter;
for ( iter = apg->globalsList; !!iter; iter = iter->next ) {
GtkGameGlobals* globals = (GtkGameGlobals*)iter->data;
CommonGlobals* cGlobals = &globals->cGlobals;
if ( cGlobals->selRow == clientToken ) {
result = globals;
break;
}
}
return result;
}
enum { CHECK_ITEM, ROW_ITEM, NAME_ITEM, ROOM_ITEM, OVER_ITEM, TURN_ITEM, NMOVES_ITEM, MISSING_ITEM,
N_ITEMS };
@ -279,6 +296,66 @@ onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid, XP_Bool isNew )
}
}
static gboolean
app_socket_proc( GIOChannel* source, GIOCondition condition, gpointer data )
{
if ( 0 != (G_IO_IN & condition) ) {
GtkAppGlobals* apg = (GtkAppGlobals*)data;
int socket = g_io_channel_unix_get_fd( source );
GList* iter;
for ( iter = apg->sources; !!iter; iter = iter->next ) {
SourceData* sd = (SourceData*)iter->data;
if ( sd->channel == source ) {
(*sd->proc)( sd->procClosure, socket );
break;
}
}
XP_ASSERT( !!iter ); /* didn't fail to find it */
}
return TRUE;
}
static void
socketChanged( void* closure, int newSock, int XP_UNUSED(oldSock), SockReceiver proc,
void* procClosure )
{
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
SourceData* sd = g_malloc( sizeof(*sd) );
sd->channel = g_io_channel_unix_new( newSock );
sd->watch = g_io_add_watch( sd->channel, G_IO_IN | G_IO_ERR, app_socket_proc, apg );
sd->proc = proc;
sd->procClosure = procClosure;
apg->sources = g_list_append( apg->sources, sd );
}
static void
gtkGotBuf( void* closure, XP_U8* buf, XP_U16 len )
{
LOG_FUNC();
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
XP_U32 gameToken;
XP_ASSERT( sizeof(gameToken) < len );
gameToken = ntohl(*(XP_U32*)&buf[0]);
buf += sizeof(gameToken);
len -= sizeof(gameToken);
GtkGameGlobals* globals = findGame( apg, gameToken );
if ( !!globals ) {
gameGotBuf( globals, buf, len );
} else {
XP_LOGF( "%s: game with token %lu not found; not open or deleted",
__func__, gameToken );
}
}
static void
gtkDevIDChanged( void* closure, const XP_UCHAR* devID )
{
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
XP_LOGF( "%s(devID=%s)", __func__, devID );
store( apg->pDb, KEY_RDEVID, devID );
}
void
onGameSaved( void* closure, sqlite3_int64 rowid,
XP_Bool firstTime )
@ -295,11 +372,39 @@ gtkmain( LaunchParams* params )
apg.selRow = -1;
apg.params = params;
apg.pDb = openGamesDB( params->dbName );
params->socketChanged = socketChanged;
params->socketChangedClosure = &apg;
RelayConnProcs procs = {
.msgReceived = gtkGotBuf,
.devIDChanged = gtkDevIDChanged,
};
XP_UCHAR devIDBuf[64] = {0};
XP_UCHAR* devID;
DevIDType typ = ID_TYPE_RELAY;
if ( !!params->rDevID ) {
devID = params->rDevID;
} else {
fetch( apg.pDb, KEY_RDEVID, devIDBuf, sizeof(devIDBuf) );
if ( '\0' != devIDBuf[0] ) {
devID = devIDBuf;
} else {
devID = params->devID;
typ = ID_TYPE_LINUX;
}
}
relaycon_init( params, &procs, &apg,
params->connInfo.relay.relayName,
params->connInfo.relay.defaultSendPort,
devID, typ );
(void)makeGamesWindow( &apg );
gtk_main();
closeGamesDB( apg.pDb );
relaycon_cleanup( params );
return 0;
} /* gtkmain */

View file

@ -59,6 +59,7 @@
#include "main.h"
#include "gamesdb.h"
#include "linuxdict.h"
#include "relaycon.h"
#ifdef PLATFORM_NCURSES
# include "cursesmain.h"
#endif
@ -849,44 +850,49 @@ linux_init_relay_socket( CommonGlobals* cGlobals, const CommsAddrRec* addrRec )
} /* linux_init_relay_socket */
static XP_S16
linux_tcp_send( const XP_U8* buf, XP_U16 buflen,
CommonGlobals* globals, const CommsAddrRec* addrRec )
linux_tcp_send( CommonGlobals* cGlobals, const XP_U8* buf, XP_U16 buflen,
const CommsAddrRec* addrRec )
{
XP_S16 result = 0;
int sock = globals->socket;
if ( sock == -1 ) {
XP_LOGF( "%s: socket uninitialized", __func__ );
sock = linux_init_relay_socket( globals, addrRec );
if ( sock != -1 ) {
assert( globals->socket == sock );
(*globals->socketChanged)( globals->socketChangedClosure,
-1, sock, &globals->storage );
}
}
if ( sock != -1 ) {
XP_U16 netLen = htons( buflen );
errno = 0;
result = send( sock, &netLen, sizeof(netLen), 0 );
if ( result == sizeof(netLen) ) {
result = send( sock, buf, buflen, 0 );
}
if ( result <= 0 ) {
XP_STATUSF( "closing non-functional socket" );
close( sock );
(*globals->socketChanged)( globals->socketChangedClosure,
sock, -1, &globals->storage );
globals->socket = -1;
}
XP_STATUSF( "%s: send(sock=%d) returned %d of %d (err=%d)",
__func__, sock, result, buflen, errno );
if ( !!cGlobals->pDb ) {
XP_ASSERT( -1 != cGlobals->selRow );
result = relaycon_send( cGlobals->params, buf, buflen,
cGlobals->selRow, addrRec );
} else {
XP_LOGF( "%s: socket still -1", __func__ );
int sock = cGlobals->socket;
if ( sock == -1 ) {
XP_LOGF( "%s: socket uninitialized", __func__ );
sock = linux_init_relay_socket( cGlobals, addrRec );
if ( sock != -1 ) {
assert( cGlobals->socket == sock );
(*cGlobals->socketChanged)( cGlobals->socketChangedClosure,
-1, sock, &cGlobals->storage );
}
}
if ( sock != -1 ) {
XP_U16 netLen = htons( buflen );
errno = 0;
result = send( sock, &netLen, sizeof(netLen), 0 );
if ( result == sizeof(netLen) ) {
result = send( sock, buf, buflen, 0 );
}
if ( result <= 0 ) {
XP_STATUSF( "closing non-functional socket" );
close( sock );
(*cGlobals->socketChanged)( cGlobals->socketChangedClosure,
sock, -1, &cGlobals->storage );
cGlobals->socket = -1;
}
XP_STATUSF( "%s: send(sock=%d) returned %d of %d (err=%d)",
__func__, sock, result, buflen, errno );
} else {
XP_LOGF( "%s: socket still -1", __func__ );
}
}
return result;
} /* linux_tcp_send */
#endif /* XWFEATURE_RELAY */
@ -928,54 +934,53 @@ linux_reset( void* closure )
#endif
XP_S16
linux_send( const XP_U8* buf, XP_U16 buflen,
const CommsAddrRec* addrRec,
linux_send( const XP_U8* buf, XP_U16 buflen, const CommsAddrRec* addrRec,
XP_U32 XP_UNUSED(gameID), void* closure )
{
XP_S16 nSent = -1;
CommonGlobals* globals = (CommonGlobals*)closure;
CommonGlobals* cGlobals = (CommonGlobals*)closure;
CommsConnType conType;
if ( !!addrRec ) {
conType = addrRec->conType;
} else {
conType = globals->params->conType;
conType = cGlobals->params->conType;
}
if ( 0 ) {
#ifdef XWFEATURE_RELAY
} else if ( conType == COMMS_CONN_RELAY ) {
nSent = linux_tcp_send( buf, buflen, globals, addrRec );
if ( nSent == buflen && globals->params->duplicatePackets ) {
nSent = linux_tcp_send( cGlobals, buf, buflen, addrRec );
if ( nSent == buflen && cGlobals->params->duplicatePackets ) {
#ifdef DEBUG
XP_S16 sentAgain =
#endif
linux_tcp_send( buf, buflen, globals, addrRec );
linux_tcp_send( cGlobals, buf, buflen, addrRec );
XP_ASSERT( sentAgain == nSent );
}
#endif
#if defined XWFEATURE_BLUETOOTH
} else if ( conType == COMMS_CONN_BT ) {
XP_Bool isServer = comms_getIsServer( globals->game.comms );
linux_bt_open( globals, isServer );
nSent = linux_bt_send( buf, buflen, addrRec, globals );
XP_Bool isServer = comms_getIsServer( cGlobals->game.comms );
linux_bt_open( cGlobals, isServer );
nSent = linux_bt_send( buf, buflen, addrRec, cGlobals );
#endif
#if defined XWFEATURE_IP_DIRECT
} else if ( conType == COMMS_CONN_IP_DIRECT ) {
CommsAddrRec addr;
comms_getAddr( globals->game.comms, &addr );
linux_udp_open( globals, &addr );
nSent = linux_udp_send( buf, buflen, addrRec, globals );
comms_getAddr( cGlobals->game.comms, &addr );
linux_udp_open( cGlobals, &addr );
nSent = linux_udp_send( buf, buflen, addrRec, cGlobals );
#endif
#if defined XWFEATURE_SMS
} else if ( COMMS_CONN_SMS == conType ) {
CommsAddrRec addr;
if ( !addrRec ) {
comms_getAddr( globals->game.comms, &addr );
comms_getAddr( cGlobals->game.comms, &addr );
addrRec = &addr;
}
nSent = linux_sms_send( globals, buf, buflen,
nSent = linux_sms_send( cGlobals, buf, buflen,
addrRec->u.sms.phone, addrRec->u.sms.port );
#endif
} else {

View file

@ -44,6 +44,10 @@ typedef struct LinuxUtilCtxt {
UtilVtable* vtable;
} LinuxUtilCtxt;
typedef void (*SockReceiver)( void* closure, int socket );
typedef void (*NewSocketProc)( void* closure, int newSock, int oldSock,
SockReceiver proc, void* procClosure );
typedef struct LaunchParams {
/* CommPipeCtxt* pipe; */
CurGameInfo pgi;
@ -51,12 +55,15 @@ typedef struct LaunchParams {
GSList* dictDirs;
char* fileName;
char* dbName;
NewSocketProc socketChanged;
void* socketChangedClosure;
XP_U16 saveFailPct;
const XP_UCHAR* playerDictNames[MAX_NUM_PLAYERS];
#ifdef USE_SQLITE
char* dbFileName;
XP_U32 dbFileID;
#endif
void* relayConStorage; /* opaque outside of relaycon.c */
char* pipe;
char* nbs;
char* bonusFile;
@ -218,11 +225,19 @@ struct CommonGlobals {
XP_U16 curSaveToken;
};
typedef struct _SourceData {
GIOChannel* channel;
gint watch;
SockReceiver proc;
void* procClosure;
} SourceData;
typedef struct _GtkAppGlobals {
sqlite3* pDb;
sqlite3_int64 selRow;
LaunchParams* params;
GSList* globalsList;
GList* sources;
GtkWidget* listWidget;
} GtkAppGlobals;

193
xwords4/linux/relaycon.c Normal file
View file

@ -0,0 +1,193 @@
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2013 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <netdb.h>
#include <errno.h>
#include "relaycon.h"
#include "comtypes.h"
typedef struct _RelayConStorage {
int socket;
RelayConnProcs procs;
void* procsClosure;
} RelayConStorage;
static RelayConStorage* getStorage( LaunchParams* params );
static void addressToServer( struct sockaddr_in* to, const CommsAddrRec* addr );
static XP_U32 addrForHost( const CommsAddrRec* addr );
static XP_U32 hostNameToIP( const XP_UCHAR* name );
static void relaycon_receive( void* closure, int socket );
void
relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
void* procsClosure, const char* host, int port,
const XP_UCHAR* devID, DevIDType typ )
{
XP_ASSERT( !params->relayConStorage );
RelayConStorage* storage = getStorage( params );
XP_MEMCPY( &storage->procs, procs, sizeof(storage->procs) );
storage->procsClosure = procsClosure;
storage->socket = socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP );
(*params->socketChanged)( params, storage->socket, -1,
relaycon_receive, params );
XP_ASSERT( !!devID );
XP_U16 idLen = XP_STRLEN( devID );
XP_U16 lenNBO = XP_HTONS( idLen );
XP_U8 tmpbuf[1 + 1 + 1 + sizeof(lenNBO) + idLen];
tmpbuf[0] = XWREG_PROTO_VERSION;
tmpbuf[1] = XWRREG_REG;
tmpbuf[2] = typ;
XP_MEMCPY( &tmpbuf[3], &lenNBO, sizeof(lenNBO) );
XP_MEMCPY( &tmpbuf[5], devID, idLen );
struct sockaddr_in to = {0};
to.sin_family = PF_INET;
to.sin_addr.s_addr = htonl( hostNameToIP(host) );
to.sin_port = htons(port);
(void)sendto( storage->socket, tmpbuf, sizeof(tmpbuf), 0, /* flags */
(struct sockaddr*)&to, sizeof(to) );
}
XP_S16
relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
XP_U32 gameToken, const CommsAddrRec* addrRec )
{
ssize_t nSent = -1;
RelayConStorage* storage = getStorage( params );
struct sockaddr_in to = {0};
addressToServer( &to, addrRec );
XP_U8 tmpbuf[1 + 1 + sizeof(gameToken) + buflen];
tmpbuf[0] = XWREG_PROTO_VERSION;
tmpbuf[1] = XWRREG_MSG;
XP_U32 inNBO = htonl(gameToken);
XP_MEMCPY( &tmpbuf[2], &inNBO, sizeof(inNBO) );
XP_MEMCPY( &tmpbuf[1 + 1 + sizeof(gameToken)], buf, buflen );
nSent = sendto( storage->socket, tmpbuf, sizeof(tmpbuf), 0, /* flags */
(struct sockaddr*)&to, sizeof(to) );
if ( 1 + 1 + sizeof(gameToken) < nSent ) {
nSent -= 1 + 1 + sizeof(gameToken);
}
LOG_RETURNF( "%d", nSent );
return nSent;
}
static void
relaycon_receive( void* closure, int socket )
{
LaunchParams* params = (LaunchParams*)closure;
XP_ASSERT( !!params->relayConStorage );
RelayConStorage* storage = getStorage( params );
XP_U8 buf[512];
struct sockaddr_in from;
socklen_t fromlen = sizeof(from);
XP_LOGF( "%s: calling recvfrom on socket %d", __func__, socket );
ssize_t nRead = recvfrom( socket, buf, sizeof(buf), 0, /* flags */
(struct sockaddr*)&from, &fromlen );
XP_LOGF( "%s: read %d bytes", __func__, nRead );
if ( 0 <= nRead ) {
XP_U8* ptr = buf;
const XP_U8* end = buf + nRead;
XP_ASSERT( XWREG_PROTO_VERSION == *ptr++ );
XWRelayReg cmd = *ptr++;
switch( cmd ) {
case XWRREG_REGRSP: {
XP_U16 len;
XP_MEMCPY( &len, ptr, sizeof(len) );
len = ntohs( len );
ptr += sizeof( len );
XP_UCHAR devID[len+1];
XP_MEMCPY( devID, ptr, len );
devID[len] = '\0';
(*storage->procs.devIDChanged)( storage->procsClosure, devID );
}
break;
case XWRREG_MSG:
(*storage->procs.msgReceived)( storage->procsClosure,
ptr, end - ptr );
break;
default:
XP_LOGF( "%s: Unexpected cmd %d", __func__, cmd );
XP_ASSERT( 0 );
}
} else {
XP_LOGF( "%s: error reading udp socket: %d (%s)", __func__,
errno, strerror(errno) );
}
}
void
relaycon_cleanup( LaunchParams* params )
{
XP_FREEP( params->mpool, &params->relayConStorage );
}
static RelayConStorage*
getStorage( LaunchParams* params )
{
RelayConStorage* storage = (RelayConStorage*)params->relayConStorage;
if ( NULL == storage ) {
storage = XP_CALLOC( params->mpool, sizeof(*storage) );
storage->socket = -1;
params->relayConStorage = storage;
}
return storage;
}
static void
addressToServer( struct sockaddr_in* to, const CommsAddrRec* addr )
{
to->sin_family = PF_INET;
to->sin_addr.s_addr = htonl( addrForHost(addr) );
to->sin_port = htons(addr->u.ip_relay.port);
}
static XP_U32
addrForHost( const CommsAddrRec* addr )
{
XP_U32 ip = addr->u.ip_relay.ipAddr;
if ( 0L == ip ) {
ip = hostNameToIP( addr->u.ip_relay.hostName );
}
return ip;
} /* addrForHost */
static XP_U32
hostNameToIP( const XP_UCHAR* name )
{
XP_U32 ip;
struct hostent* host;
XP_LOGF( "%s: looking up %s", __func__, name );
host = gethostbyname( name );
if ( NULL == host ) {
XP_WARNF( "gethostbyname returned NULL\n" );
} else {
XP_MEMCPY( &ip, host->h_addr_list[0], sizeof(ip) );
ip = ntohl(ip);
}
XP_LOGF( "%s found %lx for %s", __func__, ip, name );
return ip;
}

36
xwords4/linux/relaycon.h Normal file
View file

@ -0,0 +1,36 @@
/* -*- compile-command: "make MEMDEBUG=TRUE -j3"; -*- */
/*
* Copyright 2013 by Eric House (xwords@eehouse.org). All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _RELAYCON_H_
#define _RELAYCON_H_
#include "main.h"
typedef struct _Procs {
void (*msgReceived)( void* closure, XP_U8* buf, XP_U16 len );
void (*devIDChanged)( void* closure, const XP_UCHAR* devID );
} RelayConnProcs;
void relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
void* procsClosure, const char* host, int port,
const XP_UCHAR* devID, DevIDType typ );
XP_S16 relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
XP_U32 gameID, const CommsAddrRec* addrRec );
void relaycon_cleanup( LaunchParams* params );
#endif