From 59937b8514ea7f328bd28e206fe119b30cea49ba Mon Sep 17 00:00:00 2001 From: Eric House Date: Sat, 3 Nov 2012 10:58:01 -0700 Subject: [PATCH 1/9] modify how devids are handled on the relay and the protocol through which they're communicated to the device. Device is expected to have a platform-specific notion of ID which the relay stores in a new devices table and indexes with a 32-bit number which is returned to the device -- which is encouraged but not required to use it in lieu of the longer ID in future communications. Modify linux client and test script to use the relay-supplied id. Some of this is commented out for now. --- xwords4/common/comms.c | 10 +++ xwords4/common/comms.h | 6 -- xwords4/common/util.h | 3 + xwords4/linux/linuxmain.c | 5 ++ xwords4/linux/linuxutl.c | 21 +++++- xwords4/linux/main.h | 1 + xwords4/linux/scripts/discon_ok2.sh | 15 ++++ xwords4/relay/cref.cpp | 58 ++++++++++++--- xwords4/relay/cref.h | 15 ++-- xwords4/relay/dbmgr.cpp | 107 +++++++++++++++++++++++----- xwords4/relay/dbmgr.h | 15 +++- xwords4/relay/devid.h | 64 +++++++++++++++++ xwords4/relay/scripts/showinplay.sh | 9 ++- xwords4/relay/xwrelay.cpp | 2 +- xwords4/relay/xwrelay.h | 8 +++ xwords4/relay/xwrelay.sh | 15 ++-- 16 files changed, 300 insertions(+), 54 deletions(-) create mode 100644 xwords4/relay/devid.h diff --git a/xwords4/common/comms.c b/xwords4/common/comms.c index 3f4bd03fe..88a5363c6 100644 --- a/xwords4/common/comms.c +++ b/xwords4/common/comms.c @@ -1330,6 +1330,16 @@ got_connect_cmd( CommsCtxt* comms, XWStreamCtxt* stream, sizeof(comms->r.connName) ); #endif +#ifdef XWFEATURE_DEVID + if ( !reconnected ) { + XP_UCHAR devID[MAX_DEVID_LEN + 1]; + stringFromStreamHere( stream, devID, sizeof(devID) ); + if ( devID[0] != '\0' ) { + util_deviceRegistered( comms->util, devID ); + } + } +#endif + (*comms->procs.rconnd)( comms->procs.closure, comms->addr.u.ip_relay.invite, reconnected, comms->r.myHostID, XP_FALSE, nSought - nHere ); diff --git a/xwords4/common/comms.h b/xwords4/common/comms.h index 4585d21a8..7907be490 100644 --- a/xwords4/common/comms.h +++ b/xwords4/common/comms.h @@ -55,12 +55,6 @@ typedef enum { , COMMS_RELAYSTATE_ALLCONNECTED } CommsRelayState; -typedef enum { - ID_TYPE_NONE - ,ID_TYPE_LINUX - ,ID_TYPE_ANDROID_GCM -} DevIDType; - #ifdef XWFEATURE_BLUETOOTH # define XW_BT_UUID "7be0d084-ff89-4d6d-9c78-594773a6f963" diff --git a/xwords4/common/util.h b/xwords4/common/util.h index 46da6a5ea..b114efdc6 100644 --- a/xwords4/common/util.h +++ b/xwords4/common/util.h @@ -154,6 +154,7 @@ typedef struct UtilVtable { XP_U32 (*m_util_getCurSeconds)( XW_UtilCtxt* uc ); #ifdef XWFEATURE_DEVID const XP_UCHAR* (*m_util_getDevID)( XW_UtilCtxt* uc, DevIDType* typ ); + void (*m_util_deviceRegistered)( XW_UtilCtxt* uc, const XP_UCHAR* idRelay ); #endif DictionaryCtxt* (*m_util_makeEmptyDict)( XW_UtilCtxt* uc ); @@ -285,6 +286,8 @@ struct XW_UtilCtxt { #ifdef XWFEATURE_DEVID # define util_getDevID( uc, t ) \ (uc)->vtable->m_util_getDevID((uc),(t)) +# define util_deviceRegistered( uc, id ) \ + (uc)->vtable->m_util_deviceRegistered( (uc), (id) ) #endif #define util_makeEmptyDict( uc ) \ diff --git a/xwords4/linux/linuxmain.c b/xwords4/linux/linuxmain.c index 70bab7cf8..0b4b6d7e1 100644 --- a/xwords4/linux/linuxmain.c +++ b/xwords4/linux/linuxmain.c @@ -505,6 +505,7 @@ typedef enum { ,CMD_SEED #ifdef XWFEATURE_DEVID ,CMD_DEVID + ,CMD_RDEVID #endif ,CMD_GAMESEED ,CMD_GAMEFILE @@ -601,6 +602,7 @@ static CmdInfoRec CmdInfoRecs[] = { ,{ CMD_SEED, true, "seed", "random seed" } #ifdef XWFEATURE_DEVID ,{ CMD_DEVID, true, "devid", "device ID (for testing GCM stuff)" } + ,{ CMD_RDEVID, true, "rdevid", "relay's converted device ID (for testing GCM stuff)" } #endif ,{ CMD_GAMESEED, true, "game-seed", "game seed (for relay play)" } ,{ CMD_GAMEFILE, true, "file", "file to save to/read from" } @@ -1683,6 +1685,9 @@ main( int argc, char** argv ) case CMD_DEVID: mainParams.devID = optarg; break; + case CMD_RDEVID: + mainParams.rDevID = optarg; + break; #endif case CMD_GAMESEED: mainParams.gameSeed = atoi(optarg); diff --git a/xwords4/linux/linuxutl.c b/xwords4/linux/linuxutl.c index 12a997f7e..196551219 100644 --- a/xwords4/linux/linuxutl.c +++ b/xwords4/linux/linuxutl.c @@ -348,9 +348,25 @@ linux_util_getUserString( XW_UtilCtxt* XP_UNUSED(uc), XP_U16 code ) static const XP_UCHAR* linux_util_getDevID( XW_UtilCtxt* uc, DevIDType* typ ) { + XP_UCHAR* result; CommonGlobals* cGlobals = (CommonGlobals*)uc->closure; - *typ = ID_TYPE_LINUX; - return cGlobals->params->devID; + if ( !!cGlobals->params->rDevID ) { + *typ = ID_TYPE_RELAY; + result = cGlobals->params->rDevID; + } else { + *typ = ID_TYPE_LINUX; + result = cGlobals->params->devID; + } + return result; +} + +static void +linux_util_deviceRegistered( XW_UtilCtxt* XP_UNUSED(uc), + const XP_UCHAR* idRelay ) +{ + /* Script discon_ok2.sh is grepping for this in logs, so don't change + it! */ + XP_LOGF( "%s: new id: %s", __func__, idRelay ); } #endif @@ -365,6 +381,7 @@ linux_util_vt_init( MPFORMAL XW_UtilCtxt* util ) util->vtable->m_util_getUserString = linux_util_getUserString; #ifdef XWFEATURE_DEVID util->vtable->m_util_getDevID = linux_util_getDevID; + util->vtable->m_util_deviceRegistered = linux_util_deviceRegistered; #endif } diff --git a/xwords4/linux/main.h b/xwords4/linux/main.h index 985fd6f98..028ea0b0a 100644 --- a/xwords4/linux/main.h +++ b/xwords4/linux/main.h @@ -61,6 +61,7 @@ typedef struct LaunchParams { char* bonusFile; #ifdef XWFEATURE_DEVID char* devID; + char* rDevID; #endif VTableMgr* vtMgr; XP_U16 nLocalPlayers; diff --git a/xwords4/linux/scripts/discon_ok2.sh b/xwords4/linux/scripts/discon_ok2.sh index df7466a5d..fbaa29f2d 100755 --- a/xwords4/linux/scripts/discon_ok2.sh +++ b/xwords4/linux/scripts/discon_ok2.sh @@ -190,6 +190,7 @@ build_cmds() { PARAMS="$PARAMS --drop-nth-packet $DROP_N $PLAT_PARMS" # PARAMS="$PARAMS --savefail-pct 10" [ -n "$SEED" ] && PARAMS="$PARAMS --seed $RANDOM" + # PARAMS="$PARAMS --devid LINUX_TEST_$(printf %.5d ${COUNTER})" PARAMS="$PARAMS $PUBLIC" ARGS[$COUNTER]=$PARAMS ROOMS[$COUNTER]=$ROOM @@ -380,6 +381,19 @@ increment_drop() { fi } +set_relay_devid() { + KEY=$1 + CMD=${ARGS[$KEY]} + if [ "$CMD" != "${CMD/--devid //}" ]; then + RELAY_ID=$(grep 'deviceRegistered: new id: ' ${LOGS[$KEY]} | tail -n 1) + if [ -n "$RELAY_ID" ]; then + RELAY_ID=$(echo $RELAY_ID | sed 's,^.*new id: ,,') + # turn --devid into --rdevid $RELAY_ID + ARGS[$KEY]=$(echo $CMD | sed 's,^\(.*\)--devid[ ]\+[^ ]\+\(.*\)$,\1--rdevid $RELAY_ID\2,') + fi + fi +} + run_cmds() { ENDTIME=$(($(date +%s) + TIMEOUT)) while :; do @@ -409,6 +423,7 @@ run_cmds() { PIDS[$KEY]=0 ROOM_PIDS[$ROOM]=0 [ "$DROP_N" -ge 0 ] && increment_drop $KEY + # set_relay_devid $KEY check_game $KEY fi done diff --git a/xwords4/relay/cref.cpp b/xwords4/relay/cref.cpp index e2c63287b..a825557b3 100644 --- a/xwords4/relay/cref.cpp +++ b/xwords4/relay/cref.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -641,9 +642,10 @@ CookieRef::handleEvents() case XWA_SEND_CONNRSP: { HostID hid; - if ( increasePlayerCounts( &evt, false, &hid ) ) { + DBMgr::DevIDRelay devID; + if ( increasePlayerCounts( &evt, false, &hid, &devID ) ) { setAllConnectedTimer(); - sendResponse( &evt, true ); + sendResponse( &evt, true, &devID ); setAckTimer( hid ); } } @@ -666,8 +668,8 @@ CookieRef::handleEvents() /* break; */ case XWA_SEND_RERSP: - increasePlayerCounts( &evt, true, NULL ); - sendResponse( &evt, false ); + increasePlayerCounts( &evt, true, NULL, NULL ); + sendResponse( &evt, false, NULL ); sendAnyStored( &evt ); postCheckAllHere(); break; @@ -855,8 +857,10 @@ CookieRef::send_stored_messages( HostID dest, int socket ) } /* send_stored_messages */ bool -CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp ) +CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp, + DBMgr::DevIDRelay* devIDp ) { + DBMgr::DevIDRelay devID = DBMgr::DEVID_NONE; int nPlayersH = evt->u.con.nPlayersH; int socket = evt->u.con.socket; int seed = evt->u.con.seed; @@ -883,10 +887,25 @@ CookieRef::increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp ) assert( m_nPlayersHere <= m_nPlayersSought ); } + if ( !!devIDp ) { + DevIDType devIDType = evt->u.con.devID->m_devIDType; + // does client support devID + if ( ID_TYPE_NONE != devIDType ) { + // have we not already converted it? + if ( ID_TYPE_RELAY == devIDType ) { + devID = (DBMgr::DevIDRelay)strtoul( evt->u.con.devID->m_devIDString.c_str(), + NULL, 16 ); + } else { + devID = DBMgr::Get()->RegisterDevice( evt->u.con.devID ); + } + } + *devIDp = devID; + } + evt->u.con.srcID = DBMgr::Get()->AddDevice( ConnName(), evt->u.con.srcID, evt->u.con.clientVersion, nPlayersH, seed, - evt->u.con.addr, evt->u.con.devID, reconn ); + evt->u.con.addr, devID, reconn ); HostID hostid = evt->u.con.srcID; if ( NULL != hidp ) { @@ -1016,7 +1035,8 @@ CookieRef::cancelAllConnectedTimer() } void -CookieRef::sendResponse( const CRefEvent* evt, bool initial ) +CookieRef::sendResponse( const CRefEvent* evt, bool initial, + const DBMgr::DevIDRelay* devID ) { int socket = evt->u.con.socket; @@ -1028,6 +1048,7 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial ) + sizeof(unsigned char) /* total here */ + sizeof(unsigned char) /* total expected */ + 1 + MAX_CONNNAME_LEN + + 1 + 1 + MAX_DEVID_LEN ]; unsigned char* bufp = buf; @@ -1043,12 +1064,33 @@ CookieRef::sendResponse( const CRefEvent* evt, bool initial ) const char* connName = ConnName(); assert( !!connName && connName[0] ); - int len = strlen( connName ); + size_t len = strlen( connName ); assert( len < MAX_CONNNAME_LEN ); *bufp++ = (char)len; memcpy( bufp, connName, len ); bufp += len; + if ( initial ) { + // we always write at least empty string + char idbuf[MAX_DEVID_LEN + 1] = {0}; + + // If client supports devid, and we have one (response case), write it as + // 8-byte hex string plus a length byte -- but only if we didn't already + // receive it. + if ( !!devID && ID_TYPE_RELAY < evt->u.con.devID->m_devIDType ) { + len = snprintf( idbuf, sizeof(idbuf), "%.8X", *devID ); + assert( len < sizeof(idbuf) ); + } + + len = strlen( idbuf ); + assert( len <= MAX_DEVID_LEN ); + *bufp++ = (char)len; + if ( 0 < len ) { + memcpy( bufp, idbuf, len ); + bufp += len; + } + } + send_with_length( socket, buf, bufp - buf, true ); logf( XW_LOGVERBOSE0, "sent %s", cmdToStr( XWRELAY_Cmd(buf[0]) ) ); } /* sendResponse */ diff --git a/xwords4/relay/cref.h b/xwords4/relay/cref.h index 4581249b6..2c5021cdf 100644 --- a/xwords4/relay/cref.h +++ b/xwords4/relay/cref.h @@ -30,6 +30,8 @@ #include #include "xwrelay_priv.h" #include "xwrelay.h" +#include "devid.h" +#include "dbmgr.h" #include "states.h" typedef vector MsgBuffer; @@ -63,13 +65,6 @@ public: class CookieRef* m_this; }; -class DevID { - public: - DevID() { m_devIDType = 0; } - string m_devIDString; - unsigned char m_devIDType; -}; - class CookieRef { public: set GetSockets(); @@ -224,10 +219,12 @@ class CookieRef { void handleEvents(); - void sendResponse( const CRefEvent* evt, bool initial ); + void sendResponse( const CRefEvent* evt, bool initial, + const DBMgr::DevIDRelay* devID ); void sendAnyStored( const CRefEvent* evt ); void initPlayerCounts( const CRefEvent* evt ); - bool increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp ); + bool increasePlayerCounts( CRefEvent* evt, bool reconn, HostID* hidp, + DBMgr::DevIDRelay* devID ); void updateAck( HostID hostID, bool keep ); void dropPending( int seed ); diff --git a/xwords4/relay/dbmgr.cpp b/xwords4/relay/dbmgr.cpp index 42c9806ff..7d16139ec 100644 --- a/xwords4/relay/dbmgr.cpp +++ b/xwords4/relay/dbmgr.cpp @@ -34,6 +34,7 @@ #define GAMES_TABLE "games" #define MSGS_TABLE "msgs" +#define DEVICES_TABLE "devices" #define ARRAYSUM "sum_array(nPerDevice)" @@ -243,10 +244,59 @@ DBMgr::AllDevsAckd( const char* const connName ) return full; } +// Return DevIDRelay for device, adding it to devices table IFF it's not +// already there. +DBMgr::DevIDRelay +DBMgr::RegisterDevice( const DevID* host ) +{ + DBMgr::DevIDRelay devID; + assert( host->m_devIDType != ID_TYPE_RELAY ); + int ii; + bool success; + + // if it's already present, just return + devID = getDevID( host ); + if ( DEVID_NONE == devID ) { + // loop until we're successful inserting the unique key. Ship with this + // coming from random, but test with increasing values initially to make + // sure duplicates are detected. + for ( success = false, ii = 0; !success; ++ii ) { + assert( 10 > ii ); // better to check that we're looping BECAUSE + // of uniqueness problem. + devID = (DBMgr::DevIDRelay)random(); + if ( DEVID_NONE == devID ) { + continue; + } + const char* command = "INSERT INTO " DEVICES_TABLE + " (id, devType, devid)" + " VALUES( $1, $2, $3 )"; + int nParams = 3; + char* paramValues[nParams]; + char buf[512]; + formatParams( paramValues, nParams, + "%d"DELIM"%d"DELIM"%s", + buf, sizeof(buf), devID, host->m_devIDType, + host->m_devIDString.c_str() ); + + PGresult* result = PQexecParams( getThreadConn(), command, + nParams, NULL, + paramValues, + NULL, NULL, 0 ); + success = PGRES_COMMAND_OK == PQresultStatus(result); + if ( !success ) { + logf( XW_LOGERROR, "PQexec=>%s;%s", PQresStatus(PQresultStatus(result)), + PQresultErrorMessage(result) ); + } + PQclear( result ); + } + } + return devID; +} + HostID DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion, int nToAdd, unsigned short seed, const in_addr& addr, - const DevID* devID, bool ackd ) + DevIDRelay devID, bool ackd ) { HostID newID = curID; @@ -262,11 +312,9 @@ DBMgr::AddDevice( const char* connName, HostID curID, int clientVersion, assert( newID <= 4 ); char devIDBuf[512] = {0}; - if ( !!devID ) { + if ( DEVID_NONE != devID ) { snprintf( devIDBuf, sizeof(devIDBuf), - "devids[%d] = \'%s\', devTypes[%d] = %d,", - newID, devID->m_devIDString.c_str(), - newID, devID->m_devIDType ); + "devids[%d] = %d, ", newID, devID ); } const char* fmt = "UPDATE " GAMES_TABLE " SET nPerDevice[%d] = %d," @@ -569,20 +617,45 @@ DBMgr::readArray( const char* const connName, int arr[] ) /* len 4 */ PQclear( result ); } -void -DBMgr::getDevID( const char* connName, int hid, DevID& devID ) +DBMgr::DevIDRelay +DBMgr::getDevID( const char* connName, int hid ) { - const char* fmt = "SELECT devids[%d], devTypes[%d] FROM " GAMES_TABLE " WHERE connName='%s'"; + DBMgr::DevIDRelay devID; + const char* fmt = "SELECT devids[%d] FROM " GAMES_TABLE " WHERE connName='%s'"; char query[256]; - snprintf( query, sizeof(query), fmt, hid, hid, connName ); + snprintf( query, sizeof(query), fmt, hid, connName ); logf( XW_LOGINFO, "%s: query: %s", __func__, query ); PGresult* result = PQexec( getThreadConn(), query ); assert( 1 == PQntuples( result ) ); - devID.m_devIDString = PQgetvalue( result, 0, 0 ); - devID.m_devIDType = (unsigned char)atoi( PQgetvalue( result, 0, 1 ) ); - assert( devID.m_devIDType <= 2 ); // for now!!! + devID = (DBMgr::DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 ); PQclear( result ); + return devID; +} + +DBMgr::DevIDRelay +DBMgr::getDevID( const DevID* devID ) +{ + DBMgr::DevIDRelay rDevID = DEVID_NONE; + DevIDType devIDType = devID->m_devIDType; + assert( ID_TYPE_NONE < devIDType ); + const char* asStr = devID->m_devIDString.c_str(); + if ( ID_TYPE_RELAY == devIDType ) { + rDevID = strtoul( asStr, NULL, 16 ); + } else { + const char* fmt = "SELECT id FROM " DEVICES_TABLE " WHERE devtype=%d and devid = '%s'"; + char query[512]; + snprintf( query, sizeof(query), fmt, devIDType, asStr ); + logf( XW_LOGINFO, "%s: query: %s", __func__, query ); + + PGresult* result = PQexec( getThreadConn(), query ); + assert( 1 >= PQntuples( result ) ); + if ( 1 == PQntuples( result ) ) { + rDevID = (DBMgr::DevIDRelay)strtoul( PQgetvalue( result, 0, 0 ), NULL, 10 ); + } + PQclear( result ); + } + return rDevID; } /* @@ -625,13 +698,12 @@ void DBMgr::StoreMessage( const char* const connName, int hid, const unsigned char* buf, int len ) { - DevID devID; - getDevID( connName, hid, devID ); + DevIDRelay devID = getDevID( connName, hid ); size_t newLen; const char* fmt = "INSERT INTO " MSGS_TABLE - " (connname, hid, devid, devType, msg, msglen)" - " VALUES( '%s', %d, '%s', %d, E'%s', %d)"; + " (connname, hid, devid, msg, msglen)" + " VALUES( '%s', %d, %d, E'%s', %d)"; unsigned char* bytes = PQescapeByteaConn( getThreadConn(), buf, len, &newLen ); @@ -639,8 +711,7 @@ DBMgr::StoreMessage( const char* const connName, int hid, char query[1024]; size_t siz = snprintf( query, sizeof(query), fmt, connName, hid, - devID.m_devIDString.c_str(), - devID.m_devIDType, bytes, len ); + devID, bytes, len ); PQfreemem( bytes ); diff --git a/xwords4/relay/dbmgr.h b/xwords4/relay/dbmgr.h index 035d150f3..46af13f02 100644 --- a/xwords4/relay/dbmgr.h +++ b/xwords4/relay/dbmgr.h @@ -26,13 +26,19 @@ #include "xwrelay.h" #include "xwrelay_priv.h" -#include "cref.h" +#include "devid.h" #include using namespace std; class DBMgr { public: + /* DevIDs on various platforms are stored in devices table. This is the + key, and used in msgs and games tables as a shorter way to refer to + them. */ + typedef unsigned int DevIDRelay; + static const DevIDRelay DEVID_NONE = 0; + static DBMgr* Get(); ~DBMgr(); @@ -56,9 +62,11 @@ class DBMgr { char* connNameBuf, int bufLen, int* nPlayersHP ); bool AllDevsAckd( const char* const connName ); + DevIDRelay RegisterDevice( const DevID* hosts ); + HostID AddDevice( const char* const connName, HostID curID, int clientVersion, int nToAdd, unsigned short seed, const in_addr& addr, - const DevID* devID, bool unAckd ); + DevIDRelay devID, bool unAckd ); void NoteAckd( const char* const connName, HostID id ); HostID HIDForSeed( const char* const connName, unsigned short seed ); bool RmDeviceByHid( const char* const connName, HostID id ); @@ -99,7 +107,8 @@ class DBMgr { DBMgr(); bool execSql( const char* const query ); /* no-results query */ void readArray( const char* const connName, int arr[] ); - void getDevID( const char* connName, int hid, DevID& devID ); + DevIDRelay getDevID( const char* connName, int hid ); + DevIDRelay getDevID( const DevID* devID ); PGconn* getThreadConn( void ); diff --git a/xwords4/relay/devid.h b/xwords4/relay/devid.h new file mode 100644 index 000000000..a31744dd0 --- /dev/null +++ b/xwords4/relay/devid.h @@ -0,0 +1,64 @@ +/* -*-mode: C; fill-column: 78; c-basic-offset: 4; -*- */ +/* + * Copyright 2005-2012 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. + * + * 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 _DEVID_H_ +#define _DEVID_H_ + +#include +#include "xwrelay.h" + +/* DevID protocol. +* +* There are two types. The first, with a DevIDType greater than +* ID_TYPE_RELAY, is platform-specific and meaningless to the relay (though as +* with GCM-based IDs on Android there may be server code that uses it.) The +* second, with type of ID_TYPE_RELAY, is specific to the relay. When the +* relay sees one of the first type, it creates an entry in the devices table +* with a new random 32-bit index that is then used in the msgs and games +* tables. This index is the second type. +* +* A device always includes a DevID when creating a new game. It may be of +* either type, and generally should use the latter when possible. Since the +* latter comes from the relay, the first time a device connects (after +* whatever local event, e.g. registration with GCM, causes it to have an ID of +* the first type that it wants to share) it will have to send the first type. +* When replying to a registration message that included a DevID of the first +* type, the relay always sends the corresponding DevID of the second type, +* which it expects the device to remember. But when replying after receiving a +* DevID of the second type the relay does not echo that value (sends an empty +* string). +* +* Devices or platforms not providing a DevID will return ID_TYPE_NONE as the +* type via util_getDevID(). That single byte will be transmitted to the relay +* which will then skip the registration process and will return an empty +* string as the relay-type DevID in the connection response. +* +*/ + +using namespace std; + +class DevID { + public: + DevID() { m_devIDType = ID_TYPE_NONE; } + string m_devIDString; + DevIDType m_devIDType; +}; + +#endif diff --git a/xwords4/relay/scripts/showinplay.sh b/xwords4/relay/scripts/showinplay.sh index fcd926934..ee0c5e19a 100755 --- a/xwords4/relay/scripts/showinplay.sh +++ b/xwords4/relay/scripts/showinplay.sh @@ -26,12 +26,15 @@ QUERY="WHERE NOT -NTOTAL = sum_array(nperdevice)" echo "Device (pid) count: $(pidof xwords | wc | awk '{print $2}')" echo "Row count:" $(psql -t xwgames -c "select count(*) FROM games $QUERY;") -echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,devTypes,devids,ack,nsent "\ +echo "SELECT dead,connname,cid,room,lang,clntVers,ntotal,nperdevice,seeds,devids,ack,nsent "\ "FROM games $QUERY ORDER BY NOT dead, connname LIMIT $LIMIT;" \ | psql xwgames -echo "SELECT connname, hid, devType, devid, count(*), sum(msglen) "\ +echo "SELECT connname, hid, devid, count(*), sum(msglen) "\ "FROM msgs where connname in (SELECT connname from games where not games.dead group by connname)" \ - "GROUP BY connname, hid, devType, devid ORDER BY connname;" \ + "GROUP BY connname, hid, devid ORDER BY connname;" \ + | psql xwgames + +echo "SELECT * from devices;" \ | psql xwgames diff --git a/xwords4/relay/xwrelay.cpp b/xwords4/relay/xwrelay.cpp index fb6ceac40..87c44badb 100644 --- a/xwords4/relay/xwrelay.cpp +++ b/xwords4/relay/xwrelay.cpp @@ -386,7 +386,7 @@ processConnect( unsigned char* bufp, int bufLen, int socket, in_addr& addr ) if ( getNetByte( &bufp, end, &devIDType ) && 0 != devIDType ) { getNetString( &bufp, end, devID.m_devIDString ); - devID.m_devIDType = devIDType; + devID.m_devIDType = (DevIDType)devIDType; } } diff --git a/xwords4/relay/xwrelay.h b/xwords4/relay/xwrelay.h index cdda995dd..d848008f2 100644 --- a/xwords4/relay/xwrelay.h +++ b/xwords4/relay/xwrelay.h @@ -105,6 +105,13 @@ enum { XWRELAY_NONE /* 0 is an illegal value */ #endif ; +typedef enum { + ID_TYPE_NONE + ,ID_TYPE_RELAY /* assigned by relay as replacement for one of the below */ + ,ID_TYPE_LINUX + ,ID_TYPE_ANDROID_GCM +} DevIDType; + #ifndef CANT_DO_TYPEDEF typedef unsigned char XWRELAY_Cmd; #endif @@ -115,6 +122,7 @@ typedef unsigned char XWRELAY_Cmd; #define MAX_INVITE_LEN 31 #define MAX_MSG_LEN 1024 /* Used for proxy too! */ #define MAX_CONNNAME_LEN 48 /* host ID, boot time, and seeds as hex? */ +#define MAX_DEVID_LEN 8 /* 32-bit number as hex */ #define XWRELAY_PROTO_VERSION_ORIG 0x01 #define XWRELAY_PROTO_VERSION_LATE_NAME 0x02 diff --git a/xwords4/relay/xwrelay.sh b/xwords4/relay/xwrelay.sh index e25b5ba90..91ae66d14 100755 --- a/xwords4/relay/xwrelay.sh +++ b/xwords4/relay/xwrelay.sh @@ -58,8 +58,7 @@ cid integer ,ctime TIMESTAMP (0) DEFAULT CURRENT_TIMESTAMP ,mtimes TIMESTAMP(0)[] ,addrs INET[] -,devTypes INTEGER[] -,devids TEXT[] +,devids INTEGER[] ); EOF @@ -69,12 +68,20 @@ id SERIAL ,connName VARCHAR(64) ,hid INTEGER ,ctime TIMESTAMP DEFAULT CURRENT_TIMESTAMP -,devType INTEGER -,devid TEXT +,devid INTEGER ,msg BYTEA ,msglen INTEGER ,UNIQUE ( connName, hid, msg ) ); +EOF + + cat | psql $DBNAME --file - < Date: Sat, 3 Nov 2012 17:26:43 -0700 Subject: [PATCH 2/9] if the download dir doesn't exist (and on my "Blaze 4G" the function getDownloadCacheDirectory() returns a path that doesn't) then don't offer to move things there. --- .../org/eehouse/android/xw4/DictUtils.java | 5 +++ .../eehouse/android/xw4/DictsActivity.java | 32 +++++++++++++------ 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java index 1d3c54bd2..581ea58e7 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictUtils.java @@ -560,6 +560,11 @@ public class DictUtils { return result; } + public static boolean haveDownloadDir() + { + return null != getDownloadDir(); + } + private static File getDownloadDir() { File result = null; diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java index 7d26123de..93aed406e 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictsActivity.java @@ -263,15 +263,6 @@ public class DictsActivity extends ExpandableListActivity message = Utils.format( this, R.string.move_dictf, m_adapter.getSelChildView().getText() ); - String[] items = new String[3]; - for ( int ii = 0; ii < 3; ++ii ) { - DictLoc loc = itemToRealLoc(ii); - if ( loc.equals( m_moveFromLoc ) ) { - m_moveFromItem = ii; - } - items[ii] = m_locNames[loc.ordinal()]; - } - OnClickListener newSelLstnr = new OnClickListener() { public void onClick( DialogInterface dlgi, int item ) { @@ -307,7 +298,8 @@ public class DictsActivity extends ExpandableListActivity dialog = new AlertDialog.Builder( this ) .setTitle( message ) - .setSingleChoiceItems( items, m_moveFromItem, newSelLstnr ) + .setSingleChoiceItems( makeDictDirItems(), m_moveFromItem, + newSelLstnr ) .setPositiveButton( R.string.button_move, lstnr ) .setNegativeButton( R.string.button_cancel, null ) .create(); @@ -716,6 +708,26 @@ public class DictsActivity extends ExpandableListActivity XWPrefs.setClosedLangs( this, asArray ); } + + private String[] makeDictDirItems() + { + boolean showDownload = DictUtils.haveDownloadDir(); + int nItems = showDownload ? 3 : 2; + int nextI = 0; + String[] items = new String[nItems]; + for ( int ii = 0; ii < 3; ++ii ) { + DictLoc loc = itemToRealLoc(ii); + if ( !showDownload && DictLoc.DOWNLOAD == loc ) { + continue; + } + if ( loc.equals( m_moveFromLoc ) ) { + m_moveFromItem = nextI; + } + items[nextI++] = m_locNames[loc.ordinal()]; + } + return items; + } + private static Intent mkDownloadIntent( Context context, String dict_url ) { Uri uri = Uri.parse( dict_url ); From 68d6e10ab7524ff2beecdc676495f092bb695601 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sat, 3 Nov 2012 17:27:46 -0700 Subject: [PATCH 3/9] up version strings for quick bugfix release. --- xwords4/android/XWords4/AndroidManifest.xml | 2 +- xwords4/android/XWords4/res/raw/changes | 29 ++----------------- .../android/XWords4/res/values/app_name.xml | 2 +- 3 files changed, 4 insertions(+), 29 deletions(-) diff --git a/xwords4/android/XWords4/AndroidManifest.xml b/xwords4/android/XWords4/AndroidManifest.xml index f3ff684c0..c4082f3ac 100644 --- a/xwords4/android/XWords4/AndroidManifest.xml +++ b/xwords4/android/XWords4/AndroidManifest.xml @@ -22,7 +22,7 @@ to come from a domain that you own or have control over. --> diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes index 74f11d675..b3383b7e6 100644 --- a/xwords4/android/XWords4/res/raw/changes +++ b/xwords4/android/XWords4/res/raw/changes @@ -5,34 +5,9 @@ -Crosswords 4.4 beta 53 release +Crosswords 4.4 beta 54 release
    - -
  • Add a second way devices can play: via SMS. If you and your - friends have unlimited texting plans (ONLY IF!!) this is the way to - go: connecting is easier, moves get transmitted more quickly, and - less battery is required. See the FAQ
  • - -
  • In the main games-list screen, replace green highlighting of the - player whose turn it is with green transitioning to red over three - days. That way you can see how long it's been that person's turn. - Nothing happens -- yet -- when the three days is up. Maybe later - that'll force a resignation.
  • - -
  • Download wordlists without using the browser when possible
  • - -
  • Warn when you join a network game with a different wordlist from - the host's, and give a chance to download and switch.
  • - -
  • Don't allow networked games to have different wordlist for each - player. That feature is for local games only now.
  • - -
  • There's now a preference for where downloaded wordlists are - stored instead of a question asked each time.
  • - -
  • Recast game-over feature as "resigning".
  • - +
  • Don't try to access download directory when OS says it doesn't exist

Please remember that this is beta software. Please let me know (at diff --git a/xwords4/android/XWords4/res/values/app_name.xml b/xwords4/android/XWords4/res/values/app_name.xml index 264ebca81..1735f8137 100644 --- a/xwords4/android/XWords4/res/values/app_name.xml +++ b/xwords4/android/XWords4/res/values/app_name.xml @@ -1,5 +1,5 @@ - 4.4 beta 53 + 4.4 beta 54 From 90480aca4c4b6d053f1fd58183f1a7bb7dbf4bb2 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 4 Nov 2012 07:40:24 -0800 Subject: [PATCH 4/9] don't put up toast when checking SMS DB --- xwords4/android/XWords4/res/values/strings.xml | 2 -- .../android/XWords4/src/org/eehouse/android/xw4/SMSService.java | 1 - 2 files changed, 3 deletions(-) diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index c7a6ac89d..c4e6dbd28 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -2140,6 +2140,4 @@ Store wordlists internally (Not in external/sdcard memory) - - Searching SMS messages... diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java index 2e755c701..0bdd0727c 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/SMSService.java @@ -232,7 +232,6 @@ public class SMSService extends Service { switch( cmd ) { case CHECK_MSGDB: if ( ! XWPrefs.getHaveCheckedSMS( this ) ) { - Utils.showToast( this, R.string.sms_searching_toast ); XWPrefs.setHaveCheckedSMS( this, true ); new Thread( new Runnable() { public void run() { From 30675cfd3eed0a56cb3857f7473f075d8e6c5f88 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 4 Nov 2012 17:21:37 -0800 Subject: [PATCH 5/9] remove logging --- .../android/XWords4/src/org/eehouse/android/xw4/GameUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java index 0ea8cc3ac..f89c3a99b 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/GameUtils.java @@ -730,7 +730,6 @@ public class GameUtils { } lock.unlock(); } - DbgUtils.logf( "feedMessages=>%b", draw ); return draw; } // feedMessages From 69108fd8a107e4a60526ce7adf5045d6dcb49af1 Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 4 Nov 2012 17:33:07 -0800 Subject: [PATCH 6/9] cleanup: import class to make declarations shorter. --- .../XWords4/src/org/eehouse/android/xw4/DictLangCache.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java index 12400f661..7e32af7a9 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DictLangCache.java @@ -33,6 +33,7 @@ import java.util.Comparator; import junit.framework.Assert; import org.eehouse.android.xw4.DictUtils.DictAndLoc; +import org.eehouse.android.xw4.DictUtils.DictLoc; import org.eehouse.android.xw4.jni.JNIUtilsImpl; import org.eehouse.android.xw4.jni.XwJNI; import org.eehouse.android.xw4.jni.DictInfo; @@ -244,7 +245,7 @@ public class DictLangCache { // May be called from background thread public static void inval( final Context context, String name, - DictUtils.DictLoc loc, boolean added ) + DictLoc loc, boolean added ) { DictAndLoc dal = new DictAndLoc( name, loc ); DBUtils.dictsRemoveInfo( context, dal ); @@ -372,7 +373,7 @@ public class DictLangCache { { DictInfo result = DBUtils.dictsGetInfo( context, name ); if ( null == result ) { - DictUtils.DictLoc loc = DictUtils.getDictLoc( context, name ); + DictLoc loc = DictUtils.getDictLoc( context, name ); result = getInfo( context, new DictAndLoc( name, loc ) ); } return result; @@ -397,7 +398,7 @@ public class DictLangCache { if ( XwJNI.dict_getInfo( pairs.m_bytes[0], dal.name, pairs.m_paths[0], JNIUtilsImpl.get( context ), - DictUtils.DictLoc.DOWNLOAD == dal.loc, + DictLoc.DOWNLOAD == dal.loc, info ) ) { info.name = dal.name; From 3942a49cacaf577250647d32a0a443a5a9f4291b Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 4 Nov 2012 17:47:30 -0800 Subject: [PATCH 7/9] Add a debug preference allowing to provide, or override, the download dir. This will let users work around bugs on devices like my Blaze 4G where the OS gives the wrong path, and also allows testing. Inval DictUtil's dict cache eash time this is changed, so in effect adding a wrong path pref hides all dicts in the Downloads dir. --- .../XWords4/res/values/common_rsrc.xml | 1 + .../android/XWords4/res/values/strings.xml | 2 ++ xwords4/android/XWords4/res/xml/xwprefs.xml | 4 +++ .../org/eehouse/android/xw4/DictUtils.java | 35 +++++++++++-------- .../eehouse/android/xw4/DictsActivity.java | 2 +- .../eehouse/android/xw4/PrefsActivity.java | 20 +++++++++++ .../src/org/eehouse/android/xw4/XWPrefs.java | 5 +++ 7 files changed, 54 insertions(+), 15 deletions(-) diff --git a/xwords4/android/XWords4/res/values/common_rsrc.xml b/xwords4/android/XWords4/res/values/common_rsrc.xml index 584c61039..f2b3051a7 100644 --- a/xwords4/android/XWords4/res/values/common_rsrc.xml +++ b/xwords4/android/XWords4/res/values/common_rsrc.xml @@ -92,6 +92,7 @@ key_na_browse key_na_values key_enable_debug + key_download_path xwords@eehouse.org diff --git a/xwords4/android/XWords4/res/values/strings.xml b/xwords4/android/XWords4/res/values/strings.xml index c4e6dbd28..47fe9f433 100644 --- a/xwords4/android/XWords4/res/values/strings.xml +++ b/xwords4/android/XWords4/res/values/strings.xml @@ -2140,4 +2140,6 @@ Store wordlists internally (Not in external/sdcard memory) + + Downloads Directory diff --git a/xwords4/android/XWords4/res/xml/xwprefs.xml b/xwords4/android/XWords4/res/xml/xwprefs.xml index f4d4e6459..9a5a3bf3c 100644 --- a/xwords4/android/XWords4/res/xml/xwprefs.xml +++ b/xwords4/android/XWords4/res/xml/xwprefs.xml @@ -299,6 +299,10 @@ android:summary="Menuitems etc." android:defaultValue="false" /> + Date: Sun, 4 Nov 2012 17:53:42 -0800 Subject: [PATCH 8/9] add link to changelog --- xwords4/android/XWords4/res/raw/changes | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/xwords4/android/XWords4/res/raw/changes b/xwords4/android/XWords4/res/raw/changes index b3383b7e6..509bcac36 100644 --- a/xwords4/android/XWords4/res/raw/changes +++ b/xwords4/android/XWords4/res/raw/changes @@ -7,9 +7,15 @@ Crosswords 4.4 beta 54 release

    -
  • Don't try to access download directory when OS says it doesn't exist
  • + +
  • Don't try to access directory OS says is for downloads when it + doesn't actually exist
  • +
+

(The full changelog +is here.)

+

Please remember that this is beta software. Please let me know (at eehouse@eehouse.org) what's broken and what features you'd most like to see.

From bb2e3ffdb103d3443ae81832cf29566f70f4d9ca Mon Sep 17 00:00:00 2001 From: Eric House Date: Sun, 4 Nov 2012 21:36:20 -0800 Subject: [PATCH 9/9] fix (by dropping second message) assert that there is no first message. This is a TEMPORARY fix. --- .../org/eehouse/android/xw4/DlgDelegate.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java index 5229861ae..b0e642bf1 100644 --- a/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java +++ b/xwords4/android/XWords4/src/org/eehouse/android/xw4/DlgDelegate.java @@ -208,12 +208,20 @@ public class DlgDelegate { public void showConfirmThen( String msg, int posButton, int callbackID ) { - m_msg = msg; - m_posButton = posButton; - Assert.assertTrue( 0 != callbackID ); - Assert.assertTrue( 0 == m_cbckID ); - m_cbckID = callbackID; - m_activity.showDialog( CONFIRM_THEN ); + // FIX ME!! Need to store data per message rather than have + // assertions failing or messages dropped. + + if ( 0 != m_cbckID ) { + DbgUtils.logf( "showConfirmThen: busy with another message; " + + "dropping \"%s\" in favor of \"%s\"", + msg, m_msg ); + } else { + m_msg = msg; + m_posButton = posButton; + Assert.assertTrue( 0 != callbackID ); + m_cbckID = callbackID; + m_activity.showDialog( CONFIRM_THEN ); + } } public void showEmailOrSMSThen( final int callbackID )