get rematch working on linux, at least for two-device games. (Handling

the case where one of several guests wants to rematch is a hard
problem for later.) Requires passing old-style relayIDs (connname plus
device index) when devIDs aren't available, which they may not always
be.
This commit is contained in:
Eric House 2015-07-06 20:28:16 -07:00
parent fd06bca151
commit 0f33228155
22 changed files with 484 additions and 185 deletions

View file

@ -560,6 +560,7 @@ comms_setConnID( CommsCtxt* comms, XP_U32 connID )
static void static void
addrFromStreamOne( CommsAddrRec* addrP, XWStreamCtxt* stream, CommsConnType typ ) addrFromStreamOne( CommsAddrRec* addrP, XWStreamCtxt* stream, CommsConnType typ )
{ {
XP_U16 version = stream_getVersion( stream );
switch( typ ) { switch( typ ) {
case COMMS_CONN_NONE: case COMMS_CONN_NONE:
break; break;
@ -584,8 +585,11 @@ addrFromStreamOne( CommsAddrRec* addrP, XWStreamCtxt* stream, CommsConnType typ
stringFromStreamHere( stream, addrP->u.ip_relay.hostName, stringFromStreamHere( stream, addrP->u.ip_relay.hostName,
sizeof(addrP->u.ip_relay.hostName) ); sizeof(addrP->u.ip_relay.hostName) );
addrP->u.ip_relay.ipAddr = stream_getU32( stream ); addrP->u.ip_relay.ipAddr = stream_getU32( stream );
if ( version >= STREAM_VERS_DEVIDS ) {
addrP->u.ip_relay.devID = stream_getU32( stream );
}
addrP->u.ip_relay.port = stream_getU16( stream ); addrP->u.ip_relay.port = stream_getU16( stream );
if ( stream_getVersion( stream ) >= STREAM_VERS_DICTLANG ) { if ( version >= STREAM_VERS_DICTLANG ) {
addrP->u.ip_relay.seeksPublicRoom = stream_getBits( stream, 1 ); addrP->u.ip_relay.seeksPublicRoom = stream_getBits( stream, 1 );
addrP->u.ip_relay.advertiseRoom = stream_getBits( stream, 1 ); addrP->u.ip_relay.advertiseRoom = stream_getBits( stream, 1 );
} }
@ -632,7 +636,8 @@ comms_makeFromStream( MPFORMAL XWStreamCtxt* stream, XW_UtilCtxt* util,
isServer = stream_getU8( stream ); isServer = stream_getU8( stream );
addrFromStream( &addr, stream ); addrFromStream( &addr, stream );
if ( addr_hasType( &addr, COMMS_CONN_RELAY ) ) { if ( version >= STREAM_VERS_DEVIDS
|| addr_hasType( &addr, COMMS_CONN_RELAY ) ) {
nPlayersHere = (XP_U16)stream_getBits( stream, 4 ); nPlayersHere = (XP_U16)stream_getBits( stream, 4 );
nPlayersTotal = (XP_U16)stream_getBits( stream, 4 ); nPlayersTotal = (XP_U16)stream_getBits( stream, 4 );
} else { } else {
@ -810,6 +815,7 @@ addrToStreamOne( XWStreamCtxt* stream, CommsConnType typ, const CommsAddrRec* ad
stringToStream( stream, addrP->u.ip_relay.invite ); stringToStream( stream, addrP->u.ip_relay.invite );
stringToStream( stream, addrP->u.ip_relay.hostName ); stringToStream( stream, addrP->u.ip_relay.hostName );
stream_putU32( stream, addrP->u.ip_relay.ipAddr ); stream_putU32( stream, addrP->u.ip_relay.ipAddr );
stream_putU32( stream, addrP->u.ip_relay.devID );
stream_putU16( stream, addrP->u.ip_relay.port ); stream_putU16( stream, addrP->u.ip_relay.port );
stream_putBits( stream, 1, addrP->u.ip_relay.seeksPublicRoom ); stream_putBits( stream, 1, addrP->u.ip_relay.seeksPublicRoom );
stream_putBits( stream, 1, addrP->u.ip_relay.advertiseRoom ); stream_putBits( stream, 1, addrP->u.ip_relay.advertiseRoom );
@ -827,6 +833,7 @@ addrToStreamOne( XWStreamCtxt* stream, CommsConnType typ, const CommsAddrRec* ad
void void
addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP ) addrToStream( XWStreamCtxt* stream, const CommsAddrRec* addrP )
{ {
stream_setVersion( stream, CUR_STREAM_VERS );
stream_putU8( stream, addrP->_conTypes ); stream_putU8( stream, addrP->_conTypes );
CommsConnType typ; CommsConnType typ;
@ -843,13 +850,13 @@ comms_writeToStream( CommsCtxt* comms, XWStreamCtxt* stream,
AddressRecord* rec; AddressRecord* rec;
MsgQueueElem* msg; MsgQueueElem* msg;
stream_setVersion( stream, CUR_STREAM_VERS );
stream_putU8( stream, (XP_U8)comms->isServer ); stream_putU8( stream, (XP_U8)comms->isServer );
logAddr( comms, &comms->addr, __func__ ); logAddr( comms, &comms->addr, __func__ );
addrToStream( stream, &comms->addr ); addrToStream( stream, &comms->addr );
if ( addr_hasType( &comms->addr, COMMS_CONN_RELAY ) ) { stream_putBits( stream, 4, comms->rr.nPlayersHere );
stream_putBits( stream, 4, comms->rr.nPlayersHere ); stream_putBits( stream, 4, comms->rr.nPlayersTotal );
stream_putBits( stream, 4, comms->rr.nPlayersTotal );
}
stream_putU32( stream, comms->connID ); stream_putU32( stream, comms->connID );
stream_putU16( stream, comms->nextChannelNo ); stream_putU16( stream, comms->nextChannelNo );
@ -982,6 +989,20 @@ formatRelayID( const CommsCtxt* comms, XWHostID hostID,
return XP_TRUE; return XP_TRUE;
} }
XP_Bool
comms_formatRelayID( const CommsCtxt* comms, XP_U16 indx,
XP_UCHAR* buf, XP_U16* lenp )
{
XP_LOGF( "%s(indx=%d)", __func__, indx );
XWHostID hostID = HOST_ID_SERVER;
if ( comms->isServer ) {
hostID += 1 + indx;
}
XP_Bool success = formatRelayID( comms, hostID, buf, lenp );
XP_LOGF( "%s(%d) => %s", __func__, indx, buf );
return success;
}
/* Get *my* "relayID", a combo of connname and host id */ /* Get *my* "relayID", a combo of connname and host id */
XP_Bool XP_Bool
comms_getRelayID( const CommsCtxt* comms, XP_UCHAR* buf, XP_U16* lenp ) comms_getRelayID( const CommsCtxt* comms, XP_UCHAR* buf, XP_U16* lenp )
@ -997,12 +1018,14 @@ comms_getInitialAddr( CommsAddrRec* addr
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
, const XP_UCHAR* relayName , const XP_UCHAR* relayName
, XP_U16 relayPort , XP_U16 relayPort
, XP_U32 devID
#endif #endif
) )
{ {
#if defined XWFEATURE_RELAY #if defined XWFEATURE_RELAY
addr_setType( addr, COMMS_CONN_RELAY ); /* for temporary ease in debugging */ addr_setType( addr, COMMS_CONN_RELAY ); /* for temporary ease in debugging */
addr->u.ip_relay.ipAddr = 0L; /* force 'em to set it */ addr->u.ip_relay.ipAddr = 0L; /* force 'em to set it */
addr->u.ip_relay.devID = devID;
addr->u.ip_relay.port = relayPort; addr->u.ip_relay.port = relayPort;
{ {
const char* name = relayName; const char* name = relayName;
@ -1051,7 +1074,7 @@ comms_getConTypes( const CommsCtxt* comms )
XP_LOGF( "%s: returning COMMS_CONN_NONE for null comms", __func__ ); XP_LOGF( "%s: returning COMMS_CONN_NONE for null comms", __func__ );
} }
return typ; return typ;
} /* comms_getConType */ } /* comms_getConTypes */
XP_Bool XP_Bool
comms_getIsServer( const CommsCtxt* comms ) comms_getIsServer( const CommsCtxt* comms )
@ -2629,14 +2652,8 @@ augmentChannelAddr( CommsCtxt* comms, AddressRecord * const rec,
switch( typ ) { switch( typ ) {
case COMMS_CONN_RELAY: case COMMS_CONN_RELAY:
dest = &rec->addr.u.ip_relay; dest = &rec->addr.u.ip_relay;
src = &addr->u.ip_relay;
siz = sizeof( rec->addr.u.ip_relay ); siz = sizeof( rec->addr.u.ip_relay );
/* Special case for relay: use comms' relay info if caller
didn't bother to fill it in */
if ( addr->u.ip_relay.invite[0] ) {
src = &addr->u.ip_relay;
} else {
src = &comms->addr.u.ip_relay;
}
if ( 0 != hostID ) { if ( 0 != hostID ) {
rec->rr.hostID = hostID; rec->rr.hostID = hostID;
XP_LOGF( "%s: set hostID for rec %p to %d", __func__, rec, hostID ); XP_LOGF( "%s: set hostID for rec %p to %d", __func__, rec, hostID );

View file

@ -90,6 +90,7 @@ typedef struct _CommsAddrRec {
XP_UCHAR invite[MAX_INVITE_LEN + 1]; XP_UCHAR invite[MAX_INVITE_LEN + 1];
XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1]; XP_UCHAR hostName[MAX_HOSTNAME_LEN + 1];
XP_U32 ipAddr; /* looked up from above */ XP_U32 ipAddr; /* looked up from above */
XP_U32 devID;
XP_U16 port; XP_U16 port;
XP_Bool seeksPublicRoom; XP_Bool seeksPublicRoom;
XP_Bool advertiseRoom; XP_Bool advertiseRoom;
@ -180,6 +181,7 @@ void comms_getInitialAddr( CommsAddrRec* addr
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
, const XP_UCHAR* relayName , const XP_UCHAR* relayName
, XP_U16 relayPort , XP_U16 relayPort
, XP_U32 devID
#endif #endif
); );
XP_Bool comms_checkAddr( DeviceRole role, const CommsAddrRec* addr, XP_Bool comms_checkAddr( DeviceRole role, const CommsAddrRec* addr,
@ -189,6 +191,9 @@ void comms_getAddr( const CommsCtxt* comms, CommsAddrRec* addr );
void comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr ); void comms_setAddr( CommsCtxt* comms, const CommsAddrRec* addr );
void comms_getAddrs( const CommsCtxt* comms, CommsAddrRec addr[], void comms_getAddrs( const CommsCtxt* comms, CommsAddrRec addr[],
XP_U16* nRecs ); XP_U16* nRecs );
XP_Bool comms_formatRelayID( const CommsCtxt* comms, XP_U16 indx,
XP_UCHAR* buf, XP_U16* lenp );
XP_U16 comms_countPendingPackets( const CommsCtxt* comms ); XP_U16 comms_countPendingPackets( const CommsCtxt* comms );

View file

@ -47,6 +47,7 @@
#endif #endif
#define MAX_COLS MAX_ROWS #define MAX_COLS MAX_ROWS
#define STREAM_VERS_DEVIDS 0x19
#define STREAM_VERS_MULTIADDR 0x18 #define STREAM_VERS_MULTIADDR 0x18
#define STREAM_VERS_MODELDIVIDER 0x17 #define STREAM_VERS_MODELDIVIDER 0x17
#define STREAM_VERS_COMMSBACKOFF 0x16 #define STREAM_VERS_COMMSBACKOFF 0x16
@ -86,7 +87,7 @@
#define STREAM_VERS_405 0x01 #define STREAM_VERS_405 0x01
/* search for FIX_NEXT_VERSION_CHANGE next time this is changed */ /* search for FIX_NEXT_VERSION_CHANGE next time this is changed */
#define CUR_STREAM_VERS STREAM_VERS_MULTIADDR #define CUR_STREAM_VERS STREAM_VERS_DEVIDS
typedef struct XP_Rect { typedef struct XP_Rect {
XP_S16 left; XP_S16 left;

View file

@ -49,7 +49,8 @@ static void gi_setDict( MPFORMAL CurGameInfo* gi, const DictionaryCtxt* dict );
#endif #endif
static void static void
checkServerRole( CurGameInfo* gi, XP_U16* nPlayersHere, XP_U16* nPlayersTotal ) checkServerRole( CurGameInfo* gi, XP_U16* nPlayersHere,
XP_U16* nPlayersTotal )
{ {
if ( !!gi ) { if ( !!gi ) {
XP_U16 ii, remoteCount = 0; XP_U16 ii, remoteCount = 0;
@ -87,7 +88,7 @@ makeGameID( XW_UtilCtxt* util )
void void
game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi, game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
XW_UtilCtxt* util, DrawCtx* draw, XW_UtilCtxt* util, DrawCtx* draw,
CommonPrefs* cp, const TransportProcs* procs const CommonPrefs* cp, const TransportProcs* procs
#ifdef SET_GAMESEED #ifdef SET_GAMESEED
,XP_U16 gameSeed ,XP_U16 gameSeed
#endif #endif
@ -280,6 +281,25 @@ game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
return success; return success;
} /* game_makeFromStream */ } /* game_makeFromStream */
void
game_saveNewGame( MPFORMAL const CurGameInfo* gi, XW_UtilCtxt* util,
const CommonPrefs* cp, XWStreamCtxt* out )
{
XWGame newGame = {0};
CurGameInfo newGI = {0};
gi_copy( MPPARM(mpool) &newGI, gi );
game_makeNewGame( MPPARM(mpool) &newGame, &newGI, util,
NULL, /* DrawCtx*, */
cp, NULL, /* TransportProcs* procs */
0 );
game_saveToStream( &newGame, &newGI, out, 1 );
game_saveSucceeded( &newGame, 1 );
game_dispose( &newGame );
gi_disposePlayerInfo( MPPARM(mpool) &newGI );
}
void void
game_saveToStream( const XWGame* game, const CurGameInfo* gi, game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream, XP_U16 saveToken ) XWStreamCtxt* stream, XP_U16 saveToken )

View file

@ -60,7 +60,7 @@ typedef struct XWGame {
void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi, void game_makeNewGame( MPFORMAL XWGame* game, CurGameInfo* gi,
XW_UtilCtxt* util, DrawCtx* draw, XW_UtilCtxt* util, DrawCtx* draw,
CommonPrefs* cp, const TransportProcs* procs const CommonPrefs* cp, const TransportProcs* procs
#ifdef SET_GAMESEED #ifdef SET_GAMESEED
,XP_U16 gameSeed ,XP_U16 gameSeed
#endif #endif
@ -76,6 +76,9 @@ XP_Bool game_makeFromStream( MPFORMAL XWStreamCtxt* stream, XWGame* game,
DrawCtx* draw, CommonPrefs* cp, DrawCtx* draw, CommonPrefs* cp,
const TransportProcs* procs ); const TransportProcs* procs );
void game_saveNewGame( MPFORMAL const CurGameInfo* gi, XW_UtilCtxt* util,
const CommonPrefs* cp, XWStreamCtxt* out );
void game_saveToStream( const XWGame* game, const CurGameInfo* gi, void game_saveToStream( const XWGame* game, const CurGameInfo* gi,
XWStreamCtxt* stream, XP_U16 saveToken ); XWStreamCtxt* stream, XP_U16 saveToken );
void game_saveSucceeded( const XWGame* game, XP_U16 saveToken ); void game_saveSucceeded( const XWGame* game, XP_U16 saveToken );

View file

@ -55,6 +55,7 @@ void
invit_setDevID( InviteInfo* invit, XP_U32 devID ) invit_setDevID( InviteInfo* invit, XP_U32 devID )
{ {
invit->devID = devID; invit->devID = devID;
types_addType( &invit->_conTypes, COMMS_CONN_RELAY );
} }
void void

View file

@ -30,6 +30,12 @@
typedef enum {OSType_NONE, OSType_LINUX, OSType_ANDROID, } XP_OSType; typedef enum {OSType_NONE, OSType_LINUX, OSType_ANDROID, } XP_OSType;
/* InviteInfo
*
* A representation of return addresses sent with an invitation so that the
* recipient has all it needs to create a game and connect back.
*/
typedef struct _InviteInfo { typedef struct _InviteInfo {
XP_U8 version; /* struct version for backward compatibility */ XP_U8 version; /* struct version for backward compatibility */
XP_U16 _conTypes; XP_U16 _conTypes;

View file

@ -25,6 +25,7 @@ static void getColumnText( sqlite3_stmt *ppStmt, int iCol, XP_UCHAR* buf,
int len ); int len );
#ifdef DEBUG #ifdef DEBUG
static char* sqliteErr2str( int err ); static char* sqliteErr2str( int err );
static void assertPrintResult( sqlite3* pDb, int result, int expect );
#endif #endif
sqlite3* sqlite3*
@ -41,6 +42,7 @@ openGamesDB( const char* dbName )
"CREATE TABLE games ( " "CREATE TABLE games ( "
"rowid INTEGER PRIMARY KEY AUTOINCREMENT" "rowid INTEGER PRIMARY KEY AUTOINCREMENT"
",game BLOB" ",game BLOB"
",inviteInfo BLOB"
",room VARCHAR(32)" ",room VARCHAR(32)"
",connvia VARCHAR(32)" ",connvia VARCHAR(32)"
",ended INT(1)" ",ended INT(1)"
@ -48,6 +50,7 @@ openGamesDB( const char* dbName )
",nmoves INT" ",nmoves INT"
",seed INT" ",seed INT"
",gameid INT" ",gameid INT"
",ntotal INT(2)"
",nmissing INT(2)" ",nmissing INT(2)"
")"; ")";
result = sqlite3_exec( pDb, createGamesStr, NULL, NULL, NULL ); result = sqlite3_exec( pDb, createGamesStr, NULL, NULL, NULL );
@ -68,31 +71,32 @@ closeGamesDB( sqlite3* pDb )
XP_LOGF( "%s finished", __func__ ); XP_LOGF( "%s finished", __func__ );
} }
void static sqlite3_int64
writeToDB( XWStreamCtxt* stream, void* closure ) writeBlobColumn( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 curRow,
const char* column )
{ {
int result; int result;
CommonGlobals* cGlobals = (CommonGlobals*)closure; /* size includes stream version as header */
sqlite3_int64 selRow = cGlobals->selRow;
sqlite3* pDb = cGlobals->pDb;
XP_U16 len = stream_getSize( stream ); XP_U16 len = stream_getSize( stream );
char buf[256]; char buf[256];
char* query; char* query;
sqlite3_stmt* stmt = NULL; sqlite3_stmt* stmt = NULL;
XP_Bool newGame = -1 == selRow; XP_Bool newGame = -1 == curRow;
if ( newGame ) { /* new row; need to insert blob first */ if ( newGame ) { /* new row; need to insert blob first */
query = "INSERT INTO games (game) VALUES (?)"; const char* fmt = "INSERT INTO games (%s) VALUES (?)";
snprintf( buf, sizeof(buf), fmt, column );
query = buf;
} else { } else {
const char* fmt = "UPDATE games SET game=? where rowid=%lld"; const char* fmt = "UPDATE games SET %s=? where rowid=%lld";
snprintf( buf, sizeof(buf), fmt, selRow ); snprintf( buf, sizeof(buf), fmt, column, curRow );
query = buf; query = buf;
} }
result = sqlite3_prepare_v2( pDb, query, -1, &stmt, NULL ); result = sqlite3_prepare_v2( pDb, query, -1, &stmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_bind_zeroblob( stmt, 1 /*col 0 ??*/, len ); result = sqlite3_bind_zeroblob( stmt, 1 /*col 0 ??*/, sizeof(XP_U16) + len );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( stmt ); result = sqlite3_step( stmt );
if ( SQLITE_DONE != result ) { if ( SQLITE_DONE != result ) {
XP_LOGF( "%s: sqlite3_step => %s", __func__, sqliteErr2str( result ) ); XP_LOGF( "%s: sqlite3_step => %s", __func__, sqliteErr2str( result ) );
@ -101,24 +105,51 @@ writeToDB( XWStreamCtxt* stream, void* closure )
XP_USE( result ); XP_USE( result );
if ( newGame ) { /* new row; need to insert blob first */ if ( newGame ) { /* new row; need to insert blob first */
selRow = sqlite3_last_insert_rowid( pDb ); curRow = sqlite3_last_insert_rowid( pDb );
XP_LOGF( "%s: new rowid: %lld", __func__, selRow ); XP_LOGF( "%s: new rowid: %lld", __func__, curRow );
cGlobals->selRow = selRow;
} }
sqlite3_blob* blob; sqlite3_blob* blob;
result = sqlite3_blob_open( pDb, "main", "games", "game", result = sqlite3_blob_open( pDb, "main", "games", column,
selRow, 1 /*flags: writeable*/, &blob ); curRow, 1 /*flags: writeable*/, &blob );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
XP_U16 strVersion = stream_getVersion( stream );
XP_ASSERT( strVersion <= CUR_STREAM_VERS );
result = sqlite3_blob_write( blob, &strVersion, sizeof(strVersion), 0 );
assertPrintResult( pDb, result, SQLITE_OK );
const XP_U8* ptr = stream_getPtr( stream ); const XP_U8* ptr = stream_getPtr( stream );
result = sqlite3_blob_write( blob, ptr, len, 0 ); result = sqlite3_blob_write( blob, ptr, len, sizeof(strVersion) );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_blob_close( blob ); result = sqlite3_blob_close( blob );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
if ( !!stmt ) { if ( !!stmt ) {
sqlite3_finalize( stmt ); sqlite3_finalize( stmt );
} }
return curRow;
}
sqlite3_int64
writeNewGameToDB( XWStreamCtxt* stream, sqlite3* pDb )
{
sqlite3_int64 newRow = writeBlobColumn( stream, pDb, -1, "game" );
return newRow;
}
void
writeToDB( XWStreamCtxt* stream, void* closure )
{
CommonGlobals* cGlobals = (CommonGlobals*)closure;
sqlite3_int64 selRow = cGlobals->selRow;
sqlite3* pDb = cGlobals->pDb;
XP_Bool newGame = -1 == selRow;
selRow = writeBlobColumn( stream, pDb, selRow, "game" );
if ( newGame ) { /* new row; need to insert blob first */
cGlobals->selRow = selRow;
}
(*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame ); (*cGlobals->onSave)( cGlobals->onSaveClosure, selRow, newGame );
} }
@ -130,6 +161,7 @@ summarize( CommonGlobals* cGlobals )
XP_S16 turn = server_getCurrentTurn( cGlobals->game.server ); XP_S16 turn = server_getCurrentTurn( cGlobals->game.server );
XP_U16 seed = 0; XP_U16 seed = 0;
XP_S16 nMissing = 0; XP_S16 nMissing = 0;
XP_U16 nTotal = cGlobals->gi->nPlayers;
XP_U32 gameID = cGlobals->gi->gameID; XP_U32 gameID = cGlobals->gi->gameID;
XP_ASSERT( 0 != gameID ); XP_ASSERT( 0 != gameID );
CommsAddrRec addr = {0}; CommsAddrRec addr = {0};
@ -171,15 +203,15 @@ summarize( CommonGlobals* cGlobals )
} }
const char* fmt = "UPDATE games " const char* fmt = "UPDATE games "
" SET room='%s', ended=%d, turn=%d, nmissing=%d, nmoves=%d, seed=%d, gameid=%d, connvia='%s'" " SET room='%s', ended=%d, turn=%d, ntotal=%d, nmissing=%d, nmoves=%d, seed=%d, gameid=%d, connvia='%s'"
" WHERE rowid=%lld"; " WHERE rowid=%lld";
XP_UCHAR buf[256]; XP_UCHAR buf[256];
snprintf( buf, sizeof(buf), fmt, room, gameOver?1:0, turn, nMissing, nMoves, snprintf( buf, sizeof(buf), fmt, room, gameOver?1:0, turn, nTotal, nMissing,
seed, gameID, connvia, cGlobals->selRow ); nMoves, seed, gameID, connvia, cGlobals->selRow );
XP_LOGF( "query: %s", buf ); XP_LOGF( "query: %s", buf );
sqlite3_stmt* stmt = NULL; sqlite3_stmt* stmt = NULL;
int result = sqlite3_prepare_v2( cGlobals->pDb, buf, -1, &stmt, NULL ); int result = sqlite3_prepare_v2( cGlobals->pDb, buf, -1, &stmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( cGlobals->pDb, result, SQLITE_OK );
result = sqlite3_step( stmt ); result = sqlite3_step( stmt );
if ( SQLITE_DONE != result ) { if ( SQLITE_DONE != result ) {
XP_LOGF( "sqlite3_step=>%s", sqliteErr2str( result ) ); XP_LOGF( "sqlite3_step=>%s", sqliteErr2str( result ) );
@ -198,7 +230,7 @@ listGames( sqlite3* pDb )
int result = sqlite3_prepare_v2( pDb, int result = sqlite3_prepare_v2( pDb,
"SELECT rowid FROM games ORDER BY rowid", "SELECT rowid FROM games ORDER BY rowid",
-1, &ppStmt, NULL ); -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
XP_USE( result ); XP_USE( result );
while ( NULL != ppStmt ) { while ( NULL != ppStmt ) {
switch( sqlite3_step( ppStmt ) ) { switch( sqlite3_step( ppStmt ) ) {
@ -226,14 +258,15 @@ XP_Bool
getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib ) getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
{ {
XP_Bool success = XP_FALSE; XP_Bool success = XP_FALSE;
const char* fmt = "SELECT room, ended, turn, nmoves, nmissing, seed, connvia, gameid " const char* fmt = "SELECT room, ended, turn, nmoves, ntotal, nmissing, "
"seed, connvia, gameid "
"FROM games WHERE rowid = %lld"; "FROM games WHERE rowid = %lld";
XP_UCHAR query[256]; XP_UCHAR query[256];
snprintf( query, sizeof(query), fmt, rowid ); snprintf( query, sizeof(query), fmt, rowid );
sqlite3_stmt* ppStmt; sqlite3_stmt* ppStmt;
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
if ( SQLITE_ROW == result ) { if ( SQLITE_ROW == result ) {
success = XP_TRUE; success = XP_TRUE;
@ -241,10 +274,11 @@ getGameInfo( sqlite3* pDb, sqlite3_int64 rowid, GameInfo* gib )
gib->gameOver = 1 == sqlite3_column_int( ppStmt, 1 ); gib->gameOver = 1 == sqlite3_column_int( ppStmt, 1 );
gib->turn = sqlite3_column_int( ppStmt, 2 ); gib->turn = sqlite3_column_int( ppStmt, 2 );
gib->nMoves = sqlite3_column_int( ppStmt, 3 ); gib->nMoves = sqlite3_column_int( ppStmt, 3 );
gib->nMissing = sqlite3_column_int( ppStmt, 4 ); gib->nTotal = sqlite3_column_int( ppStmt, 4 );
gib->seed = sqlite3_column_int( ppStmt, 5 ); gib->nMissing = sqlite3_column_int( ppStmt, 5 );
getColumnText( ppStmt, 6, gib->conn, sizeof(gib->conn) ); gib->seed = sqlite3_column_int( ppStmt, 6 );
gib->gameID = sqlite3_column_int( ppStmt, 7 ); getColumnText( ppStmt, 7, gib->conn, sizeof(gib->conn) );
gib->gameID = sqlite3_column_int( ppStmt, 8 );
snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid ); snprintf( gib->name, sizeof(gib->name), "Game %lld", rowid );
} }
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
@ -259,11 +293,11 @@ getRowsForGameID( sqlite3* pDb, XP_U32 gameID, sqlite3_int64* rowids,
*nRowIDs = 0; *nRowIDs = 0;
char buf[256]; char buf[256];
snprintf( buf, sizeof(buf), "SELECT rowid from games WHERE gameid = %d LIMIT %d", snprintf( buf, sizeof(buf), "SELECT rowid from games WHERE gameid = %d "
gameID, maxRowIDs ); "LIMIT %d", gameID, maxRowIDs );
sqlite3_stmt *ppStmt; sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
int ii; int ii;
for ( ii = 0; ii < maxRowIDs; ++ii ) { for ( ii = 0; ii < maxRowIDs; ++ii ) {
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
@ -276,26 +310,56 @@ getRowsForGameID( sqlite3* pDb, XP_U32 gameID, sqlite3_int64* rowids,
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
} }
XP_Bool static XP_Bool
loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid ) loadBlobColumn( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid,
const char* column )
{ {
char buf[256]; char buf[256];
snprintf( buf, sizeof(buf), "SELECT game from games WHERE rowid = %lld", rowid ); snprintf( buf, sizeof(buf), "SELECT %s from games WHERE rowid = %lld",
column, rowid );
sqlite3_stmt *ppStmt; sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
XP_Bool success = SQLITE_ROW == result; XP_Bool success = SQLITE_ROW == result;
if ( success ) { if ( success ) {
const void* ptr = sqlite3_column_blob( ppStmt, 0 ); const void* ptr = sqlite3_column_blob( ppStmt, 0 );
int size = sqlite3_column_bytes( ppStmt, 0 ); int size = sqlite3_column_bytes( ppStmt, 0 );
stream_putBytes( stream, ptr, size ); success = 0 < size;
if ( success ) {
XP_U16 strVersion;
XP_MEMCPY( &strVersion, ptr, sizeof(strVersion) );
XP_ASSERT( strVersion <= CUR_STREAM_VERS );
stream_setVersion( stream, strVersion );
XP_ASSERT( size >= sizeof(strVersion) );
stream_putBytes( stream, ptr + sizeof(strVersion),
size - sizeof(strVersion) );
}
} }
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
return success; return success;
} }
XP_Bool
loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
{
return loadBlobColumn( stream, pDb, rowid, "game" );
}
void
saveInviteAddrs( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
{
sqlite3_int64 row = writeBlobColumn( stream, pDb, rowid, "inviteInfo" );
assert( row == rowid );
}
XP_Bool
loadInviteAddrs( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid )
{
return loadBlobColumn( stream, pDb, rowid, "inviteInfo" );
}
void void
deleteGame( sqlite3* pDb, sqlite3_int64 rowid ) deleteGame( sqlite3* pDb, sqlite3_int64 rowid )
{ {
@ -303,9 +367,9 @@ deleteGame( sqlite3* pDb, sqlite3_int64 rowid )
snprintf( query, sizeof(query), "DELETE FROM games WHERE rowid = %lld", rowid ); snprintf( query, sizeof(query), "DELETE FROM games WHERE rowid = %lld", rowid );
sqlite3_stmt* ppStmt; sqlite3_stmt* ppStmt;
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
XP_ASSERT( SQLITE_DONE == result ); assertPrintResult( pDb, result, SQLITE_DONE );
XP_USE( result ); XP_USE( result );
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
} }
@ -319,9 +383,9 @@ db_store( sqlite3* pDb, const gchar* key, const gchar* value )
key, value ); key, value );
sqlite3_stmt *ppStmt; sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, buf, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
XP_ASSERT( SQLITE_DONE == result ); assertPrintResult( pDb, result, SQLITE_DONE );
XP_USE( result ); XP_USE( result );
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
} }
@ -355,9 +419,9 @@ db_remove( sqlite3* pDb, const gchar* key )
snprintf( query, sizeof(query), "DELETE FROM pairs WHERE key = '%s'", key ); snprintf( query, sizeof(query), "DELETE FROM pairs WHERE key = '%s'", key );
sqlite3_stmt *ppStmt; sqlite3_stmt *ppStmt;
int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL ); int result = sqlite3_prepare_v2( pDb, query, -1, &ppStmt, NULL );
XP_ASSERT( SQLITE_OK == result ); assertPrintResult( pDb, result, SQLITE_OK );
result = sqlite3_step( ppStmt ); result = sqlite3_step( ppStmt );
XP_ASSERT( SQLITE_DONE == result ); assertPrintResult( pDb, result, SQLITE_DONE );
XP_USE( result ); XP_USE( result );
sqlite3_finalize( ppStmt ); sqlite3_finalize( ppStmt );
} }
@ -413,4 +477,17 @@ sqliteErr2str( int err )
} }
return "<unknown>"; return "<unknown>";
} }
static void
assertPrintResult( sqlite3* pDb, int result, int expect )
{
int code = sqlite3_errcode( pDb );
XP_ASSERT( code == result ); /* do I need to pass it? */
if ( code != expect ) {
const char* msg = sqlite3_errmsg( pDb );
XP_LOGF( "sqlite3 error: %s", msg );
XP_ASSERT(0);
}
}
#endif #endif

View file

@ -35,6 +35,7 @@ typedef struct _GameInfo {
XP_S16 nMoves; XP_S16 nMoves;
XP_Bool gameOver; XP_Bool gameOver;
XP_S16 turn; XP_S16 turn;
XP_U16 nTotal;
XP_S16 nMissing; XP_S16 nMissing;
XP_U16 seed; XP_U16 seed;
} GameInfo; } GameInfo;
@ -44,6 +45,8 @@ sqlite3* openGamesDB( const char* dbName );
void closeGamesDB( sqlite3* dbp ); void closeGamesDB( sqlite3* dbp );
void writeToDB( XWStreamCtxt* stream, void* closure ); void writeToDB( XWStreamCtxt* stream, void* closure );
sqlite3_int64 writeNewGameToDB( XWStreamCtxt* stream, sqlite3* pDb );
void summarize( CommonGlobals* cGlobals ); void summarize( CommonGlobals* cGlobals );
/* Return GSList whose data is (ptrs to) rowids */ /* Return GSList whose data is (ptrs to) rowids */
@ -52,6 +55,10 @@ XP_Bool getGameInfo( sqlite3* dbp, sqlite3_int64 rowid, GameInfo* gib );
void getRowsForGameID( sqlite3* dbp, XP_U32 gameID, sqlite3_int64* rowids, void getRowsForGameID( sqlite3* dbp, XP_U32 gameID, sqlite3_int64* rowids,
int* nRowIDs ); int* nRowIDs );
XP_Bool loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid ); XP_Bool loadGame( XWStreamCtxt* stream, sqlite3* pDb, sqlite3_int64 rowid );
void saveInviteAddrs( XWStreamCtxt* stream, sqlite3* pDb,
sqlite3_int64 rowid );
XP_Bool loadInviteAddrs( XWStreamCtxt* stream, sqlite3* pDb,
sqlite3_int64 rowid );
void deleteGame( sqlite3* pDb, sqlite3_int64 rowid ); void deleteGame( sqlite3* pDb, sqlite3_int64 rowid );
#define KEY_RDEVID "RDEVID" #define KEY_RDEVID "RDEVID"

View file

@ -77,8 +77,8 @@ gtkaskm( const gchar* message, AskMInfo* infos, int nInfos )
for ( ii = 0; ii < nInfos; ++ii ) { for ( ii = 0; ii < nInfos; ++ii ) {
AskMInfo* info = &infos[ii]; AskMInfo* info = &infos[ii];
if ( !state.cancelled ) { if ( !state.cancelled ) {
const gchar* txt = gtk_entry_get_text( GTK_ENTRY(fields[ii]) ); XP_LOGF( "%s: got text %s", __func__,
XP_LOGF( "%s: got text %s", __func__, txt ); gtk_entry_get_text( GTK_ENTRY(fields[ii]) ) );
} else { } else {
*info->result = NULL; *info->result = NULL;
} }

View file

@ -54,6 +54,7 @@
#include "draw.h" #include "draw.h"
#include "game.h" #include "game.h"
#include "movestak.h" #include "movestak.h"
#include "strutils.h"
#include "gtkask.h" #include "gtkask.h"
#include "gtkinvit.h" #include "gtkinvit.h"
#include "gtkaskm.h" #include "gtkaskm.h"
@ -82,6 +83,10 @@ static GtkWidget* addButton( GtkWidget* hbox, gchar* label, GCallback func,
static void handle_invite_button( GtkWidget* widget, GtkGameGlobals* globals ); static void handle_invite_button( GtkWidget* widget, GtkGameGlobals* globals );
static void gtkShowFinalScores( const GtkGameGlobals* globals, static void gtkShowFinalScores( const GtkGameGlobals* globals,
XP_Bool ignoreTimeout ); XP_Bool ignoreTimeout );
static void send_invites( CommonGlobals* cGlobals,
const CommsAddrRec* inviteAddr,
const XP_UCHAR* relayID,
XP_U16 nPlayers );
#define GTK_TRAY_HT_ROWS 3 #define GTK_TRAY_HT_ROWS 3
@ -103,7 +108,7 @@ lookupClientStream( GtkGameGlobals* globals, int sock )
static void static void
rememberClient( GtkGameGlobals* globals, guint key, int sock, rememberClient( GtkGameGlobals* globals, guint key, int sock,
XWStreamCtxt* stream ) XWStreamCtxt* stream )
{ {
short i; short i;
for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) { for ( i = 0; i < MAX_NUM_PLAYERS; ++i ) {
@ -868,10 +873,39 @@ destroy_board_window( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
static void static void
on_board_window_shown( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals ) on_board_window_shown( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
{ {
if ( server_getGameIsOver( globals->cGlobals.game.server ) ) { LOG_FUNC();
CommonGlobals* cGlobals = &globals->cGlobals;
if ( server_getGameIsOver( cGlobals->game.server ) ) {
gtkShowFinalScores( globals, XP_TRUE ); gtkShowFinalScores( globals, XP_TRUE );
} }
}
CommsCtxt* comms = cGlobals->game.comms;
if ( !!comms /*&& COMMS_CONN_NONE == comms_getConTypes( comms )*/ ) {
/* If it has pending invite info, send the invitation! */
XWStreamCtxt* stream = mem_stream_make( MPPARM(cGlobals->util->mpool)
cGlobals->params->vtMgr,
cGlobals, CHANNEL_NONE, NULL );
if ( loadInviteAddrs( stream, cGlobals->pDb, cGlobals->selRow ) ) {
CommsAddrRec addr = {0};
addrFromStream( &addr, stream );
comms_setAddr( cGlobals->game.comms, &addr );
XP_U16 nRecs = stream_getU8( stream );
XP_LOGF( "%s: got invite info: %d records", __func__, nRecs );
for ( int ii = 0; ii < nRecs; ++ii ) {
XP_UCHAR relayID[32];
stringFromStreamHere( stream, relayID, sizeof(relayID) );
XP_LOGF( "%s: loaded relayID %s", __func__, relayID );
CommsAddrRec addr = {0};
addrFromStream( &addr, stream );
send_invites( cGlobals, &addr, relayID, 1 /*nPlayers*/ );
}
}
stream_destroy( stream );
}
} /* on_board_window_shown */
static void static void
cleanup( GtkGameGlobals* globals ) cleanup( GtkGameGlobals* globals )
@ -986,7 +1020,9 @@ new_game_impl( GtkGameGlobals* globals, XP_Bool fireConnDlg )
if ( !!cGlobals->game.comms ) { if ( !!cGlobals->game.comms ) {
comms_getAddr( cGlobals->game.comms, &addr ); comms_getAddr( cGlobals->game.comms, &addr );
} else { } else {
comms_getInitialAddr( &addr, RELAY_NAME_DEFAULT, RELAY_PORT_DEFAULT ); XP_U32 devID = linux_getDevIDRelay( cGlobals->params );
comms_getInitialAddr( &addr, RELAY_NAME_DEFAULT, RELAY_PORT_DEFAULT,
devID );
} }
CurGameInfo* gi = cGlobals->gi; CurGameInfo* gi = cGlobals->gi;
@ -1572,7 +1608,7 @@ static void
handle_invite_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals ) handle_invite_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
{ {
CommonGlobals* cGlobals = &globals->cGlobals; CommonGlobals* cGlobals = &globals->cGlobals;
const CurGameInfo* gi = cGlobals->gi; /* const CurGameInfo* gi = cGlobals->gi; */
/* gchar* countStr; */ /* gchar* countStr; */
/* gchar* phone = NULL; */ /* gchar* phone = NULL; */
@ -1595,46 +1631,52 @@ handle_invite_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
CommsAddrRec inviteAddr = {0}; CommsAddrRec inviteAddr = {0};
gint nPlayers = nMissing; gint nPlayers = nMissing;
XP_U32 devID; XP_Bool confirmed = gtkInviteDlg( globals, &inviteAddr, &nPlayers );
XP_Bool confirmed = gtkInviteDlg( globals, &inviteAddr, &nPlayers, &devID );
XP_LOGF( "%s: inviteDlg => %d", __func__, confirmed ); XP_LOGF( "%s: inviteDlg => %d", __func__, confirmed );
if ( confirmed ) { if ( confirmed ) {
gchar gameName[64]; send_invites( cGlobals, &inviteAddr, NULL, nPlayers );
snprintf( gameName, VSIZE(gameName), "Game %d", gi->gameID ); }
} /* handle_invite_button */
CommsAddrRec addr; static void
CommsCtxt* comms = cGlobals->game.comms; send_invites( CommonGlobals* cGlobals, const CommsAddrRec* inviteAddr,
XP_ASSERT( comms ); const XP_UCHAR* relayID, XP_U16 nPlayers )
comms_getAddr( comms, &addr ); {
CommsAddrRec addr = {0};
CommsCtxt* comms = cGlobals->game.comms;
XP_ASSERT( comms );
comms_getAddr( comms, &addr );
gint forceChannel = 0; /* PENDING */ gint forceChannel = 0; /* PENDING */
InviteInfo invit = {0}; InviteInfo invit = {0};
invit_init( &invit, gi, &addr, nPlayers, forceChannel ); invit_init( &invit, cGlobals->gi, &addr, nPlayers, forceChannel );
invit_setDevID( &invit, linux_getDevIDRelay( cGlobals->params ) ); invit_setDevID( &invit, linux_getDevIDRelay( cGlobals->params ) );
#ifdef DEBUG #ifdef DEBUG
{ {
XWStreamCtxt* stream = mem_stream_make( MPPARM(cGlobals->util->mpool) XWStreamCtxt* stream = mem_stream_make( MPPARM(cGlobals->util->mpool)
cGlobals->params->vtMgr, cGlobals->params->vtMgr,
NULL, CHANNEL_NONE, NULL ); NULL, CHANNEL_NONE, NULL );
invit_saveToStream( &invit, stream ); invit_saveToStream( &invit, stream );
InviteInfo tmp; InviteInfo tmp;
invit_makeFromStream( &tmp, stream ); invit_makeFromStream( &tmp, stream );
stream_destroy( stream ); stream_destroy( stream );
XP_ASSERT( 0 == memcmp( &invit, &tmp, sizeof(invit) ) ); XP_ASSERT( 0 == memcmp( &invit, &tmp, sizeof(invit) ) );
} }
#endif #endif
if ( addr_hasType( &inviteAddr, COMMS_CONN_SMS ) ) { if ( addr_hasType( inviteAddr, COMMS_CONN_SMS ) ) {
linux_sms_invite( cGlobals->params, gi, &addr, gameName, XP_ASSERT( 0 ); /* not implemented */
nPlayers, forceChannel, /* linux_sms_invite( cGlobals->params, gi, &addr, gameName, */
inviteAddr.u.sms.phone, inviteAddr.u.sms.port ); /* nPlayers, forceChannel, */
} /* inviteAddr.u.sms.phone, inviteAddr.u.sms.port ); */
if ( addr_hasType( &addr, COMMS_CONN_RELAY ) ) { }
relaycon_invite( cGlobals->params, devID, &invit ); if ( addr_hasType( inviteAddr, COMMS_CONN_RELAY ) ) {
} XP_U32 devID = inviteAddr->u.ip_relay.devID;
XP_ASSERT( 0 != devID || (!!relayID && !!relayID[0]) );
relaycon_invite( cGlobals->params, devID, relayID, &invit );
} }
/* while ( gtkaskm( "Invite how many and how?", infos, VSIZE(infos) ) ) { */ /* while ( gtkaskm( "Invite how many and how?", infos, VSIZE(infos) ) ) { */
@ -1673,7 +1715,7 @@ handle_invite_button( GtkWidget* XP_UNUSED(widget), GtkGameGlobals* globals )
/* for ( int ii = 0; ii < VSIZE(infos); ++ii ) { */ /* for ( int ii = 0; ii < VSIZE(infos); ++ii ) { */
/* g_free( *infos[ii].result ); */ /* g_free( *infos[ii].result ); */
/* } */ /* } */
} /* handle_invite_button */ }
static void static void
gtkUserError( GtkGameGlobals* globals, const char* format, ... ) gtkUserError( GtkGameGlobals* globals, const char* format, ... )
@ -1805,8 +1847,7 @@ gtkShowFinalScores( const GtkGameGlobals* globals, XP_Bool ignoreTimeout )
buttons, timeout ); buttons, timeout );
free( text ); free( text );
if ( 2 == chosen ) { if ( 2 == chosen ) {
XP_LOGF( "%s: rematch chosen!", __func__ ); make_rematch( globals->apg, cGlobals );
XP_ASSERT( 0 );
} }
} /* gtkShowFinalScores */ } /* gtkShowFinalScores */
@ -1847,7 +1888,7 @@ gtk_util_notifyGameOver( XW_UtilCtxt* uc, XP_S16 quitter )
server_handleUndo( cGlobals->game.server, 0 ); server_handleUndo( cGlobals->game.server, 0 );
board_draw( cGlobals->game.board ); board_draw( cGlobals->game.board );
} else if ( !cGlobals->params->skipGameOver ) { } else if ( !cGlobals->params->skipGameOver ) {
gtkShowFinalScores( globals, XP_FALSE ); gtkShowFinalScores( globals, XP_TRUE );
} }
} /* gtk_util_notifyGameOver */ } /* gtk_util_notifyGameOver */
@ -2785,7 +2826,8 @@ makeNewGame( GtkGameGlobals* globals )
if ( 0 == relayPort ) { if ( 0 == relayPort ) {
relayPort = RELAY_PORT_DEFAULT; relayPort = RELAY_PORT_DEFAULT;
} }
comms_getInitialAddr( &cGlobals->addr, relayName, relayPort ); comms_getInitialAddr( &cGlobals->addr, relayName, relayPort,
linux_getDevIDRelay( cGlobals->params ) );
} }
CurGameInfo* gi = cGlobals->gi; CurGameInfo* gi = cGlobals->gi;

View file

@ -36,7 +36,6 @@ typedef struct _GtkInviteState {
GtkGameGlobals* globals; GtkGameGlobals* globals;
CommsAddrRec* addr; CommsAddrRec* addr;
gint* nPlayersP; gint* nPlayersP;
XP_U32* devIDP;
gint maxPlayers; gint maxPlayers;
XP_UCHAR devIDBuf[32]; XP_UCHAR devIDBuf[32];
@ -94,7 +93,7 @@ handle_ok( GtkWidget* XP_UNUSED(widget), gpointer closure )
#ifdef XWFEATURE_RELAY #ifdef XWFEATURE_RELAY
case COMMS_CONN_RELAY: case COMMS_CONN_RELAY:
txt = gtk_entry_get_text( GTK_ENTRY(state->devID) ); txt = gtk_entry_get_text( GTK_ENTRY(state->devID) );
*(state->devIDP) = atoi( txt ); state->addr->u.ip_relay.devID = atoi( txt );
break; break;
#endif #endif
#ifdef XWFEATURE_BLUETOOTH #ifdef XWFEATURE_BLUETOOTH
@ -276,17 +275,15 @@ onPageChanged( GtkNotebook* XP_UNUSED(notebook), gpointer XP_UNUSED(arg1),
} }
XP_Bool XP_Bool
gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr, gint* nPlayers, gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr, gint* nPlayersP )
XP_U32* devIDP )
{ {
GtkInviteState state; GtkInviteState state;
XP_MEMSET( &state, 0, sizeof(state) ); XP_MEMSET( &state, 0, sizeof(state) );
state.globals = globals; state.globals = globals;
state.addr = addr; state.addr = addr;
state.nPlayersP = nPlayers; state.nPlayersP = nPlayersP;
state.maxPlayers = *nPlayers; state.maxPlayers = *nPlayersP;
state.devIDP = devIDP;
GtkWidget* dialog; GtkWidget* dialog;
GtkWidget* hbox; GtkWidget* hbox;

View file

@ -24,7 +24,7 @@
/* return true if not cancelled */ /* return true if not cancelled */
XP_Bool gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr, XP_Bool gtkInviteDlg( GtkGameGlobals* globals, CommsAddrRec* addr,
/*inout*/ gint* nPlayers, XP_U32* devID ); /*inout*/ gint* nPlayers );
#endif #endif

View file

@ -33,7 +33,6 @@
static void onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid, static void onNewData( GtkAppGlobals* apg, sqlite3_int64 rowid,
XP_Bool isNew ); XP_Bool isNew );
static void updateButtons( GtkAppGlobals* apg ); static void updateButtons( GtkAppGlobals* apg );
static void open_row( GtkAppGlobals* apg, sqlite3_int64 row );
static void static void
recordOpened( GtkAppGlobals* apg, GtkGameGlobals* globals ) recordOpened( GtkAppGlobals* apg, GtkGameGlobals* globals )
@ -77,7 +76,7 @@ findOpenGame( const GtkAppGlobals* apg, sqlite3_int64 rowid )
} }
enum { ROW_ITEM, NAME_ITEM, ROOM_ITEM, GAMEID_ITEM, SEED_ITEM, CONN_ITEM, OVER_ITEM, TURN_ITEM, enum { ROW_ITEM, NAME_ITEM, ROOM_ITEM, GAMEID_ITEM, SEED_ITEM, CONN_ITEM, OVER_ITEM, TURN_ITEM,
NMOVES_ITEM, MISSING_ITEM, N_ITEMS }; NMOVES_ITEM, NTOTAL_ITEM, MISSING_ITEM, N_ITEMS };
static void static void
foreachProc( GtkTreeModel* model, GtkTreePath* XP_UNUSED(path), foreachProc( GtkTreeModel* model, GtkTreePath* XP_UNUSED(path),
@ -111,7 +110,7 @@ row_activated_cb( GtkTreeView* tree_view, GtkTreePath* path,
if ( gtk_tree_model_get_iter( model, &iter, path ) ) { if ( gtk_tree_model_get_iter( model, &iter, path ) ) {
sqlite3_int64 rowid; sqlite3_int64 rowid;
gtk_tree_model_get( model, &iter, ROW_ITEM, &rowid, -1 ); gtk_tree_model_get( model, &iter, ROW_ITEM, &rowid, -1 );
open_row( apg, rowid ); open_row( apg, rowid, XP_FALSE );
} }
} }
@ -158,6 +157,7 @@ init_games_list( GtkAppGlobals* apg )
addTextColumn( list, "Ended", OVER_ITEM ); addTextColumn( list, "Ended", OVER_ITEM );
addTextColumn( list, "Turn", TURN_ITEM ); addTextColumn( list, "Turn", TURN_ITEM );
addTextColumn( list, "NMoves", NMOVES_ITEM ); addTextColumn( list, "NMoves", NMOVES_ITEM );
addTextColumn( list, "NTotal", NTOTAL_ITEM );
addTextColumn( list, "NMissing", MISSING_ITEM ); addTextColumn( list, "NMissing", MISSING_ITEM );
GtkListStore* store = gtk_list_store_new( N_ITEMS, GtkListStore* store = gtk_list_store_new( N_ITEMS,
@ -170,6 +170,7 @@ init_games_list( GtkAppGlobals* apg )
G_TYPE_BOOLEAN, /* OVER_ITEM */ G_TYPE_BOOLEAN, /* OVER_ITEM */
G_TYPE_INT, /* TURN_ITEM */ G_TYPE_INT, /* TURN_ITEM */
G_TYPE_INT, /* NMOVES_ITEM */ G_TYPE_INT, /* NMOVES_ITEM */
G_TYPE_INT, /* NTOTAL_ITEM */
G_TYPE_INT /* MISSING_ITEM */ G_TYPE_INT /* MISSING_ITEM */
); );
gtk_tree_view_set_model( GTK_TREE_VIEW(list), GTK_TREE_MODEL(store) ); gtk_tree_view_set_model( GTK_TREE_VIEW(list), GTK_TREE_MODEL(store) );
@ -217,6 +218,7 @@ add_to_list( GtkWidget* list, sqlite3_int64 rowid, XP_Bool isNew,
OVER_ITEM, gib->gameOver, OVER_ITEM, gib->gameOver,
TURN_ITEM, gib->turn, TURN_ITEM, gib->turn,
NMOVES_ITEM, gib->nMoves, NMOVES_ITEM, gib->nMoves,
NTOTAL_ITEM, gib->nTotal,
MISSING_ITEM, gib->nMissing, MISSING_ITEM, gib->nMissing,
-1 ); -1 );
XP_LOGF( "DONE adding" ); XP_LOGF( "DONE adding" );
@ -226,7 +228,8 @@ static void updateButtons( GtkAppGlobals* apg )
{ {
guint count = apg->selRows->len; guint count = apg->selRows->len;
gtk_widget_set_sensitive( apg->openButton, 1 == count ); gtk_widget_set_sensitive( apg->openButton, 1 <= count );
gtk_widget_set_sensitive( apg->rematchButton, 1 == count );
gtk_widget_set_sensitive( apg->deleteButton, 1 <= count ); gtk_widget_set_sensitive( apg->deleteButton, 1 <= count );
} }
@ -249,10 +252,14 @@ handle_newgame_button( GtkWidget* XP_UNUSED(widget), void* closure )
} }
} }
static void void
open_row( GtkAppGlobals* apg, sqlite3_int64 row ) open_row( GtkAppGlobals* apg, sqlite3_int64 row, XP_Bool isNew )
{ {
if ( -1 != row && !gameIsOpen( apg, row ) ) { if ( -1 != row && !gameIsOpen( apg, row ) ) {
if ( isNew ) {
onNewData( apg, row, XP_TRUE );
}
apg->params->needsNewGame = XP_FALSE; apg->params->needsNewGame = XP_FALSE;
GtkGameGlobals* globals = malloc( sizeof(*globals) ); GtkGameGlobals* globals = malloc( sizeof(*globals) );
initGlobals( globals, apg->params, NULL ); initGlobals( globals, apg->params, NULL );
@ -267,8 +274,82 @@ static void
handle_open_button( GtkWidget* XP_UNUSED(widget), void* closure ) handle_open_button( GtkWidget* XP_UNUSED(widget), void* closure )
{ {
GtkAppGlobals* apg = (GtkAppGlobals*)closure; GtkAppGlobals* apg = (GtkAppGlobals*)closure;
sqlite3_int64 selRow = getSelRow( apg );
open_row( apg, selRow ); GArray* selRows = apg->selRows;
for ( int ii = 0; ii < selRows->len; ++ii ) {
sqlite3_int64 row = g_array_index( selRows, sqlite3_int64, ii );
open_row( apg, row, XP_FALSE );
}
}
void
make_rematch( GtkAppGlobals* apg, const CommonGlobals* cGlobals )
{
// LaunchParams* params = apg->params;
XWStreamCtxt* stream = mem_stream_make( MPPARM(cGlobals->util->mpool)
cGlobals->params->vtMgr,
NULL, CHANNEL_NONE, NULL );
/* Create new game. But has no addressing info, so need to set that
aside for later. */
CurGameInfo gi = {0};
gi_copy( MPPARM(cGlobals->util->mpool) &gi, cGlobals->gi );
gi.gameID = 0; /* clear so will get generated */
game_saveNewGame( MPPARM(cGlobals->util->mpool) &gi,
cGlobals->util, &cGlobals->cp, stream );
sqlite3_int64 rowID = writeNewGameToDB( stream, cGlobals->pDb );
stream_destroy( stream );
gi_disposePlayerInfo( MPPARM(cGlobals->util->mpool) &gi );
/* If it's a multi-device game, save enough information with it than when
opened it can invite the other device[s] join the rematch. */
const CommsCtxt* comms = cGlobals->game.comms;
if ( !!comms ) {
XWStreamCtxt* stream = mem_stream_make( MPPARM(cGlobals->util->mpool)
cGlobals->params->vtMgr,
NULL, CHANNEL_NONE, NULL );
CommsAddrRec addr;
comms_getAddr( comms, &addr );
addrToStream( stream, &addr );
CommsAddrRec addrs[4];
XP_U16 nRecs = VSIZE(addrs);
comms_getAddrs( comms, addrs, &nRecs );
stream_putU8( stream, nRecs );
for ( int ii = 0; ii < nRecs; ++ii ) {
XP_UCHAR relayID[32];
XP_U16 len = sizeof(relayID);
comms_formatRelayID( comms, ii, relayID, &len );
XP_LOGF( "%s: adding relayID: %s", __func__, relayID );
stringToStream( stream, relayID );
if ( addr_hasType( &addrs[ii], COMMS_CONN_RELAY ) ) {
/* copy over room name */
XP_STRCAT( addrs[ii].u.ip_relay.invite, addr.u.ip_relay.invite );
}
addrToStream( stream, &addrs[ii] );
}
saveInviteAddrs( stream, cGlobals->pDb, rowID );
stream_destroy( stream );
}
open_row( apg, rowID, XP_TRUE );
}
static void
handle_rematch_button( GtkWidget* XP_UNUSED(widget), void* closure )
{
GtkAppGlobals* apg = (GtkAppGlobals*)closure;
GArray* selRows = apg->selRows;
for ( int ii = 0; ii < selRows->len; ++ii ) {
sqlite3_int64 rowid = g_array_index( selRows, sqlite3_int64, ii );
GtkGameGlobals tmpGlobals;
if ( loadGameNoDraw( &tmpGlobals, apg->params, rowid ) ) {
make_rematch( apg, &tmpGlobals.cGlobals );
}
freeGlobals( &tmpGlobals );
}
} }
static void static void
@ -396,6 +477,8 @@ makeGamesWindow( GtkAppGlobals* apg )
(void)addButton( "New game", hbox, G_CALLBACK(handle_newgame_button), apg ); (void)addButton( "New game", hbox, G_CALLBACK(handle_newgame_button), apg );
apg->openButton = addButton( "Open", hbox, apg->openButton = addButton( "Open", hbox,
G_CALLBACK(handle_open_button), apg ); G_CALLBACK(handle_open_button), apg );
apg->rematchButton = addButton( "Rematch", hbox,
G_CALLBACK(handle_rematch_button), apg );
apg->deleteButton = addButton( "Delete", hbox, apg->deleteButton = addButton( "Delete", hbox,
G_CALLBACK(handle_delete_button), apg ); G_CALLBACK(handle_delete_button), apg );
(void)addButton( "Quit", hbox, G_CALLBACK(handle_quit_button), apg ); (void)addButton( "Quit", hbox, G_CALLBACK(handle_quit_button), apg );
@ -479,29 +562,38 @@ relayInviteReceived( void* closure, InviteInfo* invite )
GtkAppGlobals* apg = (GtkAppGlobals*)closure; GtkAppGlobals* apg = (GtkAppGlobals*)closure;
LaunchParams* params = apg->params; LaunchParams* params = apg->params;
CurGameInfo gi = {0}; XP_U32 gameID = invite->gameID;
gi_copy( MPPARM(params->mpool) &gi, &params->pgi ); sqlite3_int64 rowids[1];
int nRowIDs = VSIZE(rowids);
getRowsForGameID( apg->params->pDb, gameID, rowids, &nRowIDs );
if ( 0 < nRowIDs ) {
gtktell( apg->window, "Duplicate invite rejected" );
} else {
CurGameInfo gi = {0};
gi_copy( MPPARM(params->mpool) &gi, &params->pgi );
gi_setNPlayers( &gi, invite->nPlayersT, invite->nPlayersH ); gi_setNPlayers( &gi, invite->nPlayersT, invite->nPlayersH );
gi.gameID = invite->gameID; gi.gameID = gameID;
gi.dictLang = invite->lang; gi.dictLang = invite->lang;
gi.forceChannel = invite->forceChannel; gi.forceChannel = invite->forceChannel;
replaceStringIfDifferent( params->mpool, &gi.dictName, invite->dict ); replaceStringIfDifferent( params->mpool, &gi.dictName, invite->dict );
GtkGameGlobals* globals = malloc( sizeof(*globals) ); GtkGameGlobals* globals = malloc( sizeof(*globals) );
params->needsNewGame = XP_FALSE; params->needsNewGame = XP_FALSE;
initGlobals( globals, params, &gi ); initGlobals( globals, params, &gi );
invit_makeAddrRec( invite, &globals->cGlobals.addr ); invit_makeAddrRec( invite, &globals->cGlobals.addr );
// globals->cGlobals.addr = *returnAddr; // globals->cGlobals.addr = *returnAddr;
GtkWidget* gameWindow = globals->window; GtkWidget* gameWindow = globals->window;
globals->cGlobals.pDb = apg->params->pDb; globals->cGlobals.pDb = apg->params->pDb;
globals->cGlobals.selRow = -1; globals->cGlobals.selRow = -1;
recordOpened( apg, globals ); recordOpened( apg, globals );
gtk_widget_show( gameWindow ); gtk_widget_show( gameWindow );
gi_disposePlayerInfo( MPPARM(params->mpool) &gi ); gi_disposePlayerInfo( MPPARM(params->mpool) &gi );
}
} }
static void static void
@ -646,17 +738,6 @@ onGameSaved( void* closure, sqlite3_int64 rowid,
} }
} }
sqlite3_int64
getSelRow( const GtkAppGlobals* apg )
{
sqlite3_int64 result = -1;
guint len = apg->selRows->len;
if ( 1 == len ) {
result = g_array_index( apg->selRows, sqlite3_int64, 0 );
}
return result;
}
static GtkAppGlobals* g_globals_for_signal = NULL; static GtkAppGlobals* g_globals_for_signal = NULL;
static void static void

View file

@ -26,5 +26,7 @@
int gtkmain( LaunchParams* params ); int gtkmain( LaunchParams* params );
void windowDestroyed( GtkGameGlobals* globals ); void windowDestroyed( GtkGameGlobals* globals );
void onGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime ); void onGameSaved( void* closure, sqlite3_int64 rowid, XP_Bool firstTime );
void open_row( GtkAppGlobals* apg, sqlite3_int64 row, XP_Bool isNew );
void make_rematch( GtkAppGlobals* apg, const CommonGlobals* cGlobals );
#endif #endif

View file

@ -918,6 +918,10 @@ linux_getDevID( LaunchParams* params, DevIDType* typ )
if ( !!params->lDevID ) { if ( !!params->lDevID ) {
result = params->lDevID; result = params->lDevID;
*typ = ID_TYPE_LINUX; *typ = ID_TYPE_LINUX;
} else if ( db_fetch( params->pDb, KEY_RDEVID, params->devIDStore,
sizeof(params->devIDStore) ) ) {
result = params->devIDStore;
*typ = '\0' == result[0] ? ID_TYPE_ANON : ID_TYPE_RELAY;
} else if ( db_fetch( params->pDb, KEY_LDEVID, params->devIDStore, } else if ( db_fetch( params->pDb, KEY_LDEVID, params->devIDStore,
sizeof(params->devIDStore) ) ) { sizeof(params->devIDStore) ) ) {
result = params->devIDStore; result = params->devIDStore;

View file

@ -247,9 +247,8 @@ typedef struct _GtkAppGlobals {
GtkWidget* window; GtkWidget* window;
GtkWidget* listWidget; GtkWidget* listWidget;
GtkWidget* openButton; GtkWidget* openButton;
GtkWidget* rematchButton;
GtkWidget* deleteButton; GtkWidget* deleteButton;
} GtkAppGlobals; } GtkAppGlobals;
sqlite3_int64 getSelRow( const GtkAppGlobals* apg );
#endif #endif

View file

@ -48,14 +48,14 @@ static ssize_t sendIt( RelayConStorage* storage, const XP_U8* msgbuf, XP_U16 len
static size_t addVLIStr( XP_U8* buf, size_t len, const XP_UCHAR* str ); static size_t addVLIStr( XP_U8* buf, size_t len, const XP_UCHAR* str );
static void getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf ); static void getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf );
static XP_U16 getNetShort( const XP_U8** ptr ); static XP_U16 getNetShort( const XP_U8** ptr );
#ifdef DEBUG
static XP_U32 getNetLong( const XP_U8** ptr ); static XP_U32 getNetLong( const XP_U8** ptr );
#endif
static int writeHeader( RelayConStorage* storage, XP_U8* dest, XWRelayReg cmd ); static int writeHeader( RelayConStorage* storage, XP_U8* dest, XWRelayReg cmd );
static bool readHeader( const XP_U8** buf, MsgHeader* header ); static bool readHeader( const XP_U8** buf, MsgHeader* header );
static size_t writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str ); static size_t writeDevID( XP_U8* buf, size_t len, const XP_UCHAR* str );
static size_t writeShort( XP_U8* buf, size_t len, XP_U16 shrt ); static size_t writeShort( XP_U8* buf, size_t len, XP_U16 shrt );
static size_t writeLong( XP_U8* buf, size_t len, XP_U32 lng ); static size_t writeLong( XP_U8* buf, size_t len, XP_U32 lng );
static size_t writeBytes( XP_U8* buf, size_t len, const XP_U8* bytes,
size_t nBytes );
static size_t writeVLI( XP_U8* out, uint32_t nn ); static size_t writeVLI( XP_U8* out, uint32_t nn );
static size_t un2vli( int nn, uint8_t* buf ); static size_t un2vli( int nn, uint8_t* buf );
static bool vli2un( const uint8_t** inp, uint32_t* outp ); static bool vli2un( const uint8_t** inp, uint32_t* outp );
@ -113,7 +113,8 @@ relaycon_reg( LaunchParams* params, const XP_UCHAR* rDevID,
} }
void void
relaycon_invite( LaunchParams* params, XP_U32 dest, InviteInfo* invit ) relaycon_invite( LaunchParams* params, XP_U32 destDevID,
const XP_UCHAR* relayID, InviteInfo* invit )
{ {
XP_U8 tmpbuf[256]; XP_U8 tmpbuf[256];
int indx = 0; int indx = 0;
@ -122,7 +123,17 @@ relaycon_invite( LaunchParams* params, XP_U32 dest, InviteInfo* invit )
indx += writeHeader( storage, tmpbuf, XWPDEV_INVITE ); indx += writeHeader( storage, tmpbuf, XWPDEV_INVITE );
XP_U32 me = linux_getDevIDRelay( params ); XP_U32 me = linux_getDevIDRelay( params );
indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, me ); indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, me );
indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, dest );
/* write relayID <connname>/<hid>, or if we have an actual devID write a
null byte plus it. */
if ( 0 == destDevID ) {
XP_ASSERT( '\0' != relayID[0] );
indx += writeBytes( &tmpbuf[indx], sizeof(tmpbuf) - indx,
(XP_U8*)relayID, 1 + XP_STRLEN( relayID ) );
} else {
tmpbuf[indx++] = '\0'; /* null byte: zero-len str */
indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, destDevID );
}
XWStreamCtxt* stream = mem_stream_make( MPPARM(params->mpool) XWStreamCtxt* stream = mem_stream_make( MPPARM(params->mpool)
params->vtMgr, params, params->vtMgr, params,
@ -132,8 +143,7 @@ relaycon_invite( LaunchParams* params, XP_U32 dest, InviteInfo* invit )
indx += writeShort( &tmpbuf[indx], sizeof(tmpbuf) - indx, len ); indx += writeShort( &tmpbuf[indx], sizeof(tmpbuf) - indx, len );
XP_ASSERT( indx + len < sizeof(tmpbuf) ); XP_ASSERT( indx + len < sizeof(tmpbuf) );
const XP_U8* ptr = stream_getPtr( stream ); const XP_U8* ptr = stream_getPtr( stream );
XP_MEMCPY( &tmpbuf[indx], ptr, len ); indx += writeBytes( &tmpbuf[indx], sizeof(tmpbuf) - indx, ptr, len );
indx += len;
stream_destroy( stream ); stream_destroy( stream );
sendIt( storage, tmpbuf, indx ); sendIt( storage, tmpbuf, indx );
@ -151,11 +161,8 @@ relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
XP_U8 tmpbuf[1 + 4 + 1 + sizeof(gameToken) + buflen]; XP_U8 tmpbuf[1 + 4 + 1 + sizeof(gameToken) + buflen];
int indx = 0; int indx = 0;
indx += writeHeader( storage, tmpbuf, XWPDEV_MSG ); indx += writeHeader( storage, tmpbuf, XWPDEV_MSG );
XP_U32 inNBO = htonl(gameToken); indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, gameToken );
XP_MEMCPY( &tmpbuf[indx], &inNBO, sizeof(inNBO) ); indx += writeBytes( &tmpbuf[indx], sizeof(tmpbuf) - indx, buf, buflen );
indx += sizeof(inNBO);
XP_MEMCPY( &tmpbuf[indx], buf, buflen );
indx += buflen;
nSent = sendIt( storage, tmpbuf, indx ); nSent = sendIt( storage, tmpbuf, indx );
if ( nSent > buflen ) { if ( nSent > buflen ) {
nSent = buflen; nSent = buflen;
@ -179,14 +186,12 @@ relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
1 + idLen + 1 + idLen +
sizeof(gameToken) + buflen]; sizeof(gameToken) + buflen];
indx += writeHeader( storage, tmpbuf, XWPDEV_MSGNOCONN ); indx += writeHeader( storage, tmpbuf, XWPDEV_MSGNOCONN );
gameToken = htonl( gameToken ); indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, gameToken );
XP_MEMCPY( &tmpbuf[indx], &gameToken, sizeof(gameToken) ); indx += writeBytes( &tmpbuf[indx], sizeof(tmpbuf) - indx,
indx += sizeof(gameToken); (const XP_U8*)relayID, idLen );
XP_MEMCPY( &tmpbuf[indx], relayID, idLen );
indx += idLen;
tmpbuf[indx++] = '\n'; tmpbuf[indx++] = '\n';
XP_MEMCPY( &tmpbuf[indx], buf, buflen ); indx += writeBytes( &tmpbuf[indx], sizeof(tmpbuf) - indx, buf, buflen );
nSent = sendIt( storage, tmpbuf, sizeof(tmpbuf) ); nSent = sendIt( storage, tmpbuf, indx );
if ( nSent > buflen ) { if ( nSent > buflen ) {
nSent = buflen; nSent = buflen;
} }
@ -218,9 +223,7 @@ relaycon_deleted( LaunchParams* params, const XP_UCHAR* devID,
int indx = 0; int indx = 0;
indx += writeHeader( storage, tmpbuf, XWPDEV_DELGAME ); indx += writeHeader( storage, tmpbuf, XWPDEV_DELGAME );
indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID ); indx += writeDevID( &tmpbuf[indx], sizeof(tmpbuf) - indx, devID );
gameToken = htonl( gameToken ); indx += writeLong( &tmpbuf[indx], sizeof(tmpbuf) - indx, gameToken );
memcpy( &tmpbuf[indx], &gameToken, sizeof(gameToken) );
indx += sizeof( gameToken );
sendIt( storage, tmpbuf, indx ); sendIt( storage, tmpbuf, indx );
} }
@ -330,7 +333,10 @@ relaycon_receive( GIOChannel* source, GIOCondition XP_UNUSED_DBG(condition), gpo
} }
case XWPDEV_GOTINVITE: { case XWPDEV_GOTINVITE: {
XP_LOGF( "%s(): got XWPDEV_GOTINVITE", __func__ ); XP_LOGF( "%s(): got XWPDEV_GOTINVITE", __func__ );
XP_U32 sender = getNetLong( &ptr ); #ifdef DEBUG
XP_U32 sender =
#endif
getNetLong( &ptr );
XP_U16 len = getNetShort( &ptr ); XP_U16 len = getNetShort( &ptr );
XWStreamCtxt* stream = mem_stream_make( MPPARM(storage->params->mpool) XWStreamCtxt* stream = mem_stream_make( MPPARM(storage->params->mpool)
storage->params->vtMgr, storage, storage->params->vtMgr, storage,
@ -438,7 +444,7 @@ writeShort( XP_U8* buf, size_t len, XP_U16 shrt )
{ {
shrt = htons( shrt ); shrt = htons( shrt );
assert( sizeof( shrt ) <= len ); assert( sizeof( shrt ) <= len );
memcpy( buf, &shrt, sizeof(shrt) ); XP_MEMCPY( buf, &shrt, sizeof(shrt) );
return sizeof(shrt); return sizeof(shrt);
} }
@ -451,6 +457,14 @@ writeLong( XP_U8* buf, size_t len, XP_U32 lng )
return sizeof(lng); return sizeof(lng);
} }
static size_t
writeBytes( XP_U8* buf, size_t len, const XP_U8* bytes, size_t nBytes )
{
assert( nBytes <= len );
XP_MEMCPY( buf, bytes, nBytes );
return nBytes;
}
static size_t static size_t
writeVLI( XP_U8* out, uint32_t nn ) writeVLI( XP_U8* out, uint32_t nn )
{ {
@ -469,7 +483,6 @@ getNetShort( const XP_U8** ptr )
return ntohs( result ); return ntohs( result );
} }
#ifdef DEBUG
static XP_U32 static XP_U32
getNetLong( const XP_U8** ptr ) getNetLong( const XP_U8** ptr )
{ {
@ -478,7 +491,6 @@ getNetLong( const XP_U8** ptr )
*ptr += sizeof(result); *ptr += sizeof(result);
return ntohl( result ); return ntohl( result );
} }
#endif
static void static void
getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf ) getNetString( const XP_U8** ptr, XP_U16 len, XP_UCHAR* buf )

View file

@ -39,7 +39,10 @@ void relaycon_init( LaunchParams* params, const RelayConnProcs* procs,
void* procsClosure, const char* host, int port ); void* procsClosure, const char* host, int port );
void relaycon_reg( LaunchParams* params, const XP_UCHAR* rDevID, void relaycon_reg( LaunchParams* params, const XP_UCHAR* rDevID,
DevIDType typ, const XP_UCHAR* devID ); DevIDType typ, const XP_UCHAR* devID );
void relaycon_invite( LaunchParams* params, XP_U32 dest, InviteInfo* invite ); /* Need one of dest or relayID, with dest preferred. pass 0 for dest to use
relayID (formatted per comms::formatRelayID()) */
void relaycon_invite( LaunchParams* params, XP_U32 dest,
const XP_UCHAR* relayID, InviteInfo* invite );
XP_S16 relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen, XP_S16 relaycon_send( LaunchParams* params, const XP_U8* buf, XP_U16 buflen,
XP_U32 gameToken, const CommsAddrRec* addrRec ); XP_U32 gameToken, const CommsAddrRec* addrRec );
XP_S16 relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf, XP_S16 relaycon_sendnoconn( LaunchParams* params, const XP_U8* buf,

View file

@ -873,6 +873,19 @@ DBMgr::readArray( const char* const connName, const char* column, int arr[] ) /
PQclear( result ); PQclear( result );
} }
// parse something created by comms.c's formatRelayID
DevIDRelay
DBMgr::getDevID( string& relayID )
{
size_t pos = relayID.find_first_of( '/' );
string connName = relayID.substr( 0, pos );
int hid = relayID[pos + 1] - '0';
DevIDRelay result = getDevID( connName.c_str(), hid );
// Not an error. Remove or downlog when confirm working
logf( XW_LOGERROR, "%s(%s) => %d", __func__, relayID.c_str(), result );
return result;
}
DevIDRelay DevIDRelay
DBMgr::getDevID( const char* connName, int hid ) DBMgr::getDevID( const char* connName, int hid )
{ {

View file

@ -146,6 +146,8 @@ class DBMgr {
void RemoveStoredMessage( const int msgID ); void RemoveStoredMessage( const int msgID );
void RemoveStoredMessages( vector<int>& ids ); void RemoveStoredMessages( vector<int>& ids );
DevIDRelay getDevID( string& relayID );
private: private:
DBMgr(); DBMgr();
bool execSql( const string& query ); bool execSql( const string& query );

View file

@ -1779,17 +1779,24 @@ handle_udp_packet( UdpThreadClosure* utc )
break; break;
} }
case XWPDEV_INVITE: case XWPDEV_INVITE: {
DevIDRelay sender; DevIDRelay sender;
DevIDRelay invitee; string relayID;
if ( getNetLong( &ptr, end, &sender ) if ( getNetLong( &ptr, end, &sender )
&& getNetLong( &ptr, end, &invitee) ) { && getNetString( &ptr, end, relayID ) ) {
DevIDRelay invitee;
if ( 0 < relayID.size() ) {
invitee = DBMgr::Get()->getDevID( relayID );
} else if ( !getNetLong( &ptr, end, &invitee ) ) {
break; // failure
}
logf( XW_LOGVERBOSE0, "got invite from %d for %d", logf( XW_LOGVERBOSE0, "got invite from %d for %d",
sender, invitee ); sender, invitee );
post_invite( sender, invitee, ptr, end - ptr ); post_invite( sender, invitee, ptr, end - ptr );
} }
break; break;
}
case XWPDEV_KEEPALIVE: case XWPDEV_KEEPALIVE:
case XWPDEV_RQSTMSGS: { case XWPDEV_RQSTMSGS: {
DevID devID( ID_TYPE_RELAY ); DevID devID( ID_TYPE_RELAY );