mirror of
git://xwords.git.sourceforge.net/gitroot/xwords/xwords
synced 2025-01-13 08:01:33 +01:00
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:
parent
bdb8e6f03c
commit
fab39a5f87
4 changed files with 155 additions and 43 deletions
|
@ -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 ) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 );
|
||||
|
||||
|
|
|
@ -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 */
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue