Trying to deal with old- and new-proto devices interacting. Fix

clients to append their stream version to their inital connect
message.  (The format can't change, so detecting additional length was
the only option.  comm.c on existing clients won't allow more than one
connect message per channel, so adding a new to be used in addition
didn't work.)  New servers detect this; old will ignore.  Track the
version (implicit or not) of all clients, and use the lowest any
supports, so that new server and all new clients will use newer proto.
This commit is contained in:
Andy2 2011-11-16 06:47:55 -08:00
parent bdb8e6f03c
commit fab39a5f87
4 changed files with 155 additions and 43 deletions

View file

@ -426,16 +426,18 @@ gi_readFromStream( MPFORMAL XWStreamCtxt* stream, CurGameInfo* gi )
XP_U16 ii;
XP_UCHAR* str;
XP_U16 strVersion = stream_getVersion( stream );
#ifdef STREAM_VERS_BIGBOARD
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > strVersion ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
str = stringFromStream( mpool, stream );
replaceStringIfDifferent( mpool, &gi->dictName, str );
XP_FREEP( mpool, &str );
gi->nPlayers = (XP_U8)stream_getBits( stream, NPLAYERS_NBITS );
gi->boardSize =
(XP_U8)stream_getBits( stream,
strVersion < STREAM_VERS_BIGBOARD? 4 :
NUMCOLS_NBITS );
gi->boardSize = (XP_U8)stream_getBits( stream, nColsNBits );
gi->serverRole = (DeviceRole)stream_getBits( stream, 2 );
gi->hintsNotAllowed = stream_getBits( stream, 1 );
if ( strVersion < STREAM_VERS_ROBOTIQ ) {

View file

@ -33,8 +33,6 @@ extern "C" {
#if MAX_COLS > 16
# define STREAM_VERS_BIGBOARD 0x12
#else
# define STREAM_VERS_BIGBOARD 0x11
#endif
#define STREAM_SAVE_PREVWORDS 0x11
#define STREAM_VERS_SERVER_SAVES_TOSHOW 0x10
@ -58,7 +56,11 @@ extern "C" {
#define STREAM_VERS_41B4 0x02
#define STREAM_VERS_405 0x01
#define CUR_STREAM_VERS STREAM_VERS_BIGBOARD
#if MAX_COLS > 16
# define CUR_STREAM_VERS STREAM_VERS_BIGBOARD
#else
# define CUR_STREAM_VERS STREAM_SAVE_PREVWORDS
#endif
typedef struct LocalPlayer {
XP_UCHAR* name;

View file

@ -118,10 +118,13 @@ model_makeFromStream( MPFORMAL XWStreamCtxt* stream, DictionaryCtxt* dict,
short i;
XP_Bool hasDict;
XP_U16 nPlayers;
XP_U16 nColsNBits;
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits =
STREAM_VERS_BIGBOARD > version ? 4 :
NUMCOLS_NBITS;
#ifdef STREAM_VERS_BIGBOARD
nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
nColsNBits = NUMCOLS_NBITS;
#endif
XP_ASSERT( !!dict || !!dicts );
@ -818,6 +821,12 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
{
PlayerCtxt* player;
XP_S16 numTiles;
#ifdef STREAM_VERS_BIGBOARD
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
XP_ASSERT( turn >= 0 );
player = &model->players[turn];
@ -834,8 +843,8 @@ model_currentMoveToStream( ModelCtxt* model, XP_S16 turn,
&col, &row, &isBlank );
XP_ASSERT( numTiles >= 0 );
stream_putBits( stream, TILE_NBITS, tile );
stream_putBits( stream, NUMCOLS_NBITS, col );
stream_putBits( stream, NUMCOLS_NBITS, row );
stream_putBits( stream, nColsNBits, col );
stream_putBits( stream, nColsNBits, row );
stream_putBits( stream, 1, isBlank );
}
} /* model_currentMoveToStream */
@ -852,8 +861,13 @@ model_makeTurnFromStream( ModelCtxt* model, XP_U16 playerNum,
{
XP_U16 numTiles, ii;
Tile blank = dict_getBlankTile( model_getDictionary(model) );
#ifdef STREAM_VERS_BIGBOARD
XP_U16 version = stream_getVersion( stream );
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
model_resetCurrentTurn( model, playerNum );
@ -2220,9 +2234,11 @@ loadPlayerCtxt( XWStreamCtxt* stream, XP_U16 version, PlayerCtxt* pc )
{
PendingTile* pt;
XP_U16 nTiles;
XP_U16 nColsNBits =
STREAM_VERS_BIGBOARD > stream_getVersion( stream ) ? 4 :
NUMCOLS_NBITS;
#ifdef STREAM_VERS_BIGBOARD
XP_U16 nColsNBits = STREAM_VERS_BIGBOARD > version ? 4 : NUMCOLS_NBITS;
#else
XP_U16 nColsNBits = NUMCOLS_NBITS;
#endif
pc->curMoveValid = stream_getBits( stream, 1 );

View file

@ -60,6 +60,9 @@ typedef struct ServerPlayer {
typedef struct RemoteAddress {
XP_PlayerAddr channelNo;
#ifdef STREAM_VERS_BIGBOARD
XP_U8 streamVersion;
#endif
} RemoteAddress;
/* These are the parts of the server's state that needs to be preserved
@ -84,6 +87,9 @@ typedef struct ServerNonvolatiles {
XP_U8 pendingRegistrations;
XP_Bool showRobotScores;
XP_Bool sortNewTiles;
#ifdef STREAM_VERS_BIGBOARD
XP_U8 streamVersion;
#endif
#ifdef XWFEATURE_SLOW_ROBOT
XP_U16 robotThinkMin, robotThinkMax; /* not saved (yet) */
#endif
@ -139,13 +145,14 @@ static XWStreamCtxt* messageStreamWithHeader( ServerCtxt* server,
XP_U16 devIndex, XW_Proto code );
static XP_Bool handleRegistrationMsg( ServerCtxt* server,
XWStreamCtxt* stream );
static void registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream );
static XP_S8 registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream );
static void server_sendInitialMessage( ServerCtxt* server );
static void sendBadWordMsgs( ServerCtxt* server );
static XP_Bool handleIllegalWord( ServerCtxt* server,
XWStreamCtxt* incoming );
static void tellMoveWasLegal( ServerCtxt* server );
static void writeProto( XWStreamCtxt* stream, XW_Proto proto );
static void writeProto( const ServerCtxt* server, XWStreamCtxt* stream,
XW_Proto proto );
#endif
#define PICK_NEXT -1
@ -231,6 +238,9 @@ initServer( ServerCtxt* server )
syncPlayers( server );
server->nv.nDevices = 1; /* local device (0) is always there */
#ifdef STREAM_VERS_BIGBOARD
server->nv.streamVersion = STREAM_SAVE_PREVWORDS; /* default to old */
#endif
} /* initServer */
ServerCtxt*
@ -281,7 +291,18 @@ getNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers )
for ( ii = 0; ii < nPlayers; ++ii ) {
nv->addresses[ii].channelNo =
(XP_PlayerAddr)stream_getBits( stream, 16 );
#ifdef STREAM_VERS_BIGBOARD
if ( STREAM_VERS_BIGBOARD <= version ) {
nv->addresses[ii].streamVersion = stream_getBits( stream, 8 );
}
#endif
}
#ifdef STREAM_VERS_BIGBOARD
if ( STREAM_SAVE_PREVWORDS < version ) {
nv->streamVersion = stream_getU8 ( stream );
}
XP_LOGF( "%s: read streamVersion: 0x%x", __func__, nv->streamVersion );
#endif
} /* getNV */
static void
@ -302,7 +323,14 @@ putNV( XWStreamCtxt* stream, ServerNonvolatiles* nv, XP_U16 nPlayers )
for ( ii = 0; ii < nPlayers; ++ii ) {
stream_putBits( stream, 16, nv->addresses[ii].channelNo );
#ifdef STREAM_VERS_BIGBOARD
stream_putBits( stream, 8, nv->addresses[ii].streamVersion );
#endif
}
#ifdef STREAM_VERS_BIGBOARD
stream_putU8( stream, nv->streamVersion );
XP_LOGF( "%s: wrote streamVersion: 0x%x", __func__, nv->streamVersion );
#endif
} /* putNV */
static XWStreamCtxt*
@ -516,7 +544,7 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
if ( server->nv.gameState == XWSTATE_NONE ) {
stream_open( stream );
writeProto( stream, XWPROTO_DEVICE_REGISTRATION );
writeProto( server, stream, XWPROTO_DEVICE_REGISTRATION );
nPlayers = gi->nPlayers;
XP_ASSERT( nPlayers > 0 );
@ -532,8 +560,8 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
continue;
}
stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to send this */
stream_putBits( stream, 1, LP_IS_ROBOT(lp) ); /* better not to
send this */
/* The first nPlayers players are the ones we'll use. The local flag
doesn't matter when for SERVER_ISCLIENT. */
name = emptyStringIfNull(lp->name);
@ -544,6 +572,10 @@ server_initClientConnection( ServerCtxt* server, XWStreamCtxt* stream )
stream_putBits( stream, NAME_LEN_NBITS, len );
stream_putBytes( stream, name, len );
}
#ifdef STREAM_VERS_BIGBOARD
stream_putU8( stream, CUR_STREAM_VERS );
#endif
} else {
XP_LOGF( "%s: wierd state %s; dropping message", __func__,
getStateStr(server->nv.gameState) );
@ -594,11 +626,32 @@ callTurnChangeListener( ServerCtxt* server )
} /* callTurnChangeListener */
#ifndef XWFEATURE_STANDALONE_ONLY
# ifdef STREAM_VERS_BIGBOARD
static void
setStreamVersion( ServerCtxt* server )
{
XP_U16 devIndex;
XP_U8 streamVersion = CUR_STREAM_VERS;
for ( devIndex = 1; devIndex < server->nv.nDevices; ++devIndex ) {
XP_U8 devVersion = server->nv.addresses[devIndex].streamVersion;
if ( devVersion < streamVersion ) {
streamVersion = devVersion;
}
}
XP_LOGF( "%s: setting streamVersion: %d", __func__, streamVersion );
server->nv.streamVersion = streamVersion;
}
# else
# define setStreamVersion(s)
# endif
static XP_Bool
handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_Bool success = XP_TRUE;
XP_U16 playersInMsg, i;
XP_U16 playersInMsg;
XP_S8 clientIndex;
XP_U16 ii = 0;
LOG_FUNC();
/* code will have already been consumed */
@ -609,21 +662,41 @@ handleRegistrationMsg( ServerCtxt* server, XWStreamCtxt* stream )
util_userError( server->vol.util, ERR_REG_UNEXPECTED_USER );
success = XP_FALSE;
} else {
for ( i = 0; i < playersInMsg; ++i ) {
registerRemotePlayer( server, stream );
XP_S8 prevIndex = -1;
for ( ; ii < playersInMsg; ++ii ) {
clientIndex = registerRemotePlayer( server, stream );
/* This is abusing the semantics of turn change -- at least in the
case where there is another device yet to register -- but we
need to let the board know to redraw the scoreboard with more
players there. */
callTurnChangeListener( server );
XP_ASSERT( ii == 0 || prevIndex == clientIndex );
prevIndex = clientIndex;
}
if ( server->nv.pendingRegistrations == 0 ) {
assignTilesToAll( server );
SETSTATE( server, XWSTATE_RECEIVED_ALL_REG );
}
#ifdef STREAM_VERS_BIGBOARD
if ( 0 < stream_getSize(stream) ) {
XP_U8 streamVersion = stream_getU8( stream );
if ( streamVersion >= STREAM_VERS_BIGBOARD ) {
XP_LOGF( "%s: upping device %d streamVersion to %d",
__func__, clientIndex, streamVersion );
server->nv.addresses[clientIndex].streamVersion = streamVersion;
}
}
#endif
if ( server->nv.pendingRegistrations == 0 ) {
XP_ASSERT( ii == playersInMsg ); /* otherwise malformed */
setStreamVersion( server );
assignTilesToAll( server );
SETSTATE( server, XWSTATE_RECEIVED_ALL_REG );
}
/* now set server's streamVersion if all remote players have the higher one. */
/* But first need to pass it in the strramx */
return success;
} /* handleRegistrationMsg */
#endif
@ -1000,7 +1073,7 @@ findFirstPending( ServerCtxt* server, ServerPlayer** playerP )
return lp;
} /* findFirstPending */
static void
static XP_S8
registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_S8 deviceIndex;
@ -1040,10 +1113,13 @@ registerRemotePlayer( ServerCtxt* server, XWStreamCtxt* stream )
XP_ASSERT( channelNo != 0 );
addr->channelNo = channelNo;
#ifdef STREAM_VERS_BIGBOARD
addr->streamVersion = STREAM_SAVE_PREVWORDS;
#endif
}
player->deviceIndex = deviceIndex;
return deviceIndex;
} /* registerRemotePlayer */
static void
@ -1096,10 +1172,9 @@ client_readInitialMessage( ServerCtxt* server, XWStreamCtxt* stream )
PoolContext* pool;
/* version; any dependencies here? */
if ( STREAM_SAVE_PREVWORDS >= stream_getVersion( stream ) ) {
XP_U8 streamVersion = stream_getU8( stream );
stream_setVersion( stream, streamVersion );
}
XP_U8 streamVersion = stream_getU8( stream );
XP_LOGF( "%s: set streamVersion to %d", __func__, streamVersion );
stream_setVersion( stream, streamVersion );
gameID = stream_getU32( stream );
XP_LOGF( "read gameID of %lx; calling comms_setConnID", gameID );
@ -1237,7 +1312,9 @@ server_sendInitialMessage( ServerCtxt* server )
DictionaryCtxt* dict = model_getDictionary(model);
XP_ASSERT( !!stream );
stream_open( stream );
writeProto( stream, XWPROTO_CLIENT_SETUP );
writeProto( server, stream, XWPROTO_CLIENT_SETUP );
stream_putU8( stream, CUR_STREAM_VERS );
XP_LOGF( "putting gameID %lx into msg", gameID );
stream_putU32( stream, gameID );
@ -1341,9 +1418,11 @@ messageStreamWithHeader( ServerCtxt* server, XP_U16 devIndex, XW_Proto code )
printCode("making", code);
stream = util_makeStreamFromAddr( server->vol.util, channelNo );
#ifdef STREAM_VERS_BIGBOARD
stream_setVersion( stream, server->nv.streamVersion );
#endif
stream_open( stream );
writeProto( stream, code );
writeProto( server, stream, code );
return stream;
} /* messageStreamWithHeader */
@ -2441,22 +2520,34 @@ server_handleUndo( ServerCtxt* server )
#ifndef XWFEATURE_STANDALONE_ONLY
static void
writeProto( XWStreamCtxt* stream, XW_Proto proto )
writeProto( const ServerCtxt* server, XWStreamCtxt* stream, XW_Proto proto )
{
stream_putBits( stream, XWPROTO_NBITS, XWPROTO_NEW_PROTO );
#ifdef STREAM_VERS_BIGBOARD
XP_ASSERT( server->nv.streamVersion > 0 );
if ( STREAM_SAVE_PREVWORDS < server->nv.streamVersion ) {
stream_putBits( stream, XWPROTO_NBITS, XWPROTO_NEW_PROTO );
stream_putBits( stream, 8, CUR_STREAM_VERS );
}
#else
XP_USE(server);
#endif
stream_putBits( stream, XWPROTO_NBITS, proto );
stream_putU8( stream, CUR_STREAM_VERS );
}
static XW_Proto
readProto( XWStreamCtxt* stream )
readProto( ServerCtxt* server, XWStreamCtxt* stream )
{
XP_U8 version = STREAM_SAVE_PREVWORDS; /* version prior to fmt change */
XW_Proto proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS );
XP_U8 version = STREAM_SAVE_PREVWORDS; /* version prior to fmt change */
#ifdef STREAM_VERS_BIGBOARD
if ( XWPROTO_NEW_PROTO == proto ) {
version = stream_getBits( stream, 8 );
proto = (XW_Proto)stream_getBits( stream, XWPROTO_NBITS );
version = stream_getU8( stream );
}
server->nv.streamVersion = version;
#else
XP_USE(server);
#endif
stream_setVersion( stream, version );
return proto;
}
@ -2465,7 +2556,7 @@ XP_Bool
server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
{
XP_Bool accepted = XP_FALSE;
XW_Proto code = readProto( incoming );
XW_Proto code = readProto( server, incoming );
printCode( "Receiving", code );
@ -2554,7 +2645,8 @@ server_receiveMessage( ServerCtxt* server, XWStreamCtxt* incoming )
accepted = XP_TRUE;
break;
default:
XP_WARNF( "Unknown code on incoming message: %d\n", code );
XP_WARNF( "%s: Unknown code on incoming message: %d\n",
__func__, code );
break;
} /* switch */
}