mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2024-12-29 10:26:36 +01:00
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:
parent
f6e7ece578
commit
a6784464ff
12 changed files with 498 additions and 65 deletions
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 )
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
193
xwords4/linux/relaycon.c
Normal 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, ¶ms->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
36
xwords4/linux/relaycon.h
Normal 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
|
Loading…
Reference in a new issue