Clientset enhancements

Issue #85 resolved
Joris created an issue

This patch contains 3 enhancements for clientset: * Provides GetArenaOverride and GetPlayerOverride in the interface * The checksum returned by GetChecksum is based on the last settings packet sent instead of the current arena settings + override values. Aka no security warnings if you decide to set overrides and delay calling SendClientSettings() * Provides the global config settings clientset:DetectConfigChange. This disables sending settings packets after a ?quickfix.

Diff bases on clientset.c r1117: {{{ #!C

38,40d37 < < unsigned char lastSettingsPacket_hasData; < struct ClientSettings lastSettingsPacket; 313d309 <
350,395d345 < int get_override(overridedata od, override_key_t key, i32 val) < { < int len = (key >> 16) & 0xffffu; < int offset = key & 0xffffu; < < val = 0; < < / don't override type byte / < if (offset < 8) < return 0; < < if (len <= 32 && ((offset & 31) + len) <= 32) < { < / easier case: a bunch of bits that fit within a word boundary / < int wordoff = offset >> 5; < int bitoff = offset & 31; < u32 mask = (0xffffffffu >> (32 - len)) << bitoff; < < if ((((u32)od->mask)[wordoff] & mask) == mask) < { < val = ((u32)od->bits)[wordoff]; < val &= mask; < val = val >> bitoff; < < < return 1; < } < else < { < return 0; < } < < } < #if 0 < else if (len <= 32 && ((offset & 31) + len) <= 64) < { < #error "Not implemented" < } < #endif < else < { < lm->Log(L_WARN, "<clientset> illegal override key: %x", key); < return 0; < } < } < 433,461d382 < local int GetArenaOverride(Arena arena, override_key_t key, i32 value) < { < int ret; < adata ad = P_ARENA_DATA(arena, adkey); < LOCK(); < ret = get_override(&ad->od, key, value); < UNLOCK(); < return ret; < < } < < local int GetPlayerOverride(Player p, override_key_t key, i32 value) < { < int ret; < pdata data = PPDATA(p, pdkey); < LOCK(); < if (data->od) < { < ret = get_override(data->od, key, value); < } < else < { < value = 0; < ret = 0; < } < UNLOCK(); < return ret; < } < 464d384 < / call with lock held / 495a416

struct ClientSettings tosend; 497,500c418,420 < do_mask(&data->lastSettingsPacket, &ad->cs, &ad->od, data->od); < data->lastSettingsPacket_hasData = 1; < if (data->lastSettingsPacket.bit_set.type == S2C_SETTINGS) < net->SendToOne(p, (byte*)&data->lastSettingsPacket, sizeof(data->lastSettingsPacket), NET_RELIABLE);


do_mask(&tosend, &ad->cs, &ad->od, data->od); if (tosend.bit_set.type == S2C_SETTINGS) net->SendToOne(p, (byte*)&tosend, sizeof(tosend), NET_RELIABLE); 512c432 < else if (action == AA_CONFCHANGED && cfg->GetInt(GLOBAL, "clientset", "DetectConfigChange", 1))


else if (action == AA_CONFCHANGED) 565c485,486 < u32 bits = (u32)&data->lastSettingsPacket;


struct ClientSettings tochecksum; u32 bits = (u32)&tochecksum; 573,577c494 < if (!data->lastSettingsPacket_hasData) < { < do_mask(&data->lastSettingsPacket, &ad->cs, &ad->od, data->od); < data->lastSettingsPacket_hasData = 1; < }


do_mask(&tochecksum, &ad->cs, &ad->od, data->od);

}}}

clientset.h: {{{ #!C

/ dist: public /

#ifndef __CLIENTSET_H #define __CLIENTSET_H

/ Iclientset * * this is the interface to the module that manages the client-side * settings. it loads them from disk when the arena is loaded and when * the config files change change. arenaman calls SendClientSettings as * part of the arena response procedure. /

typedef u32 override_key_t;

#define I_CLIENTSET "clientset-6"

typedef struct Iclientset { INTERFACE_HEAD_DECL

void (*SendClientSettings)(Player *p);

u32 (*GetChecksum)(Player *p, u32 key);

int (*GetRandomPrize)(Arena *arena);

override_key_t (*GetOverrideKey)(const char *section, const char *key);
/* zero return means failure */

void (*ArenaOverride)(Arena *arena, override_key_t key, i32 val);
void (*ArenaUnoverride)(Arena *arena, override_key_t key);
int  (*GetArenaOverride)(Arena *arena, override_key_t key, i32 *value); // returns 1 if set

void (*PlayerOverride)(Player *p, override_key_t key, i32 val);
void (*PlayerUnoverride)(Player *p, override_key_t key);
int  (*GetPlayerOverride)(Player *p, override_key_t key, i32 *value);

} Iclientset;

#endif

}}}

Comments (8)

  1. Joris reporter

    Revised my patch, to fix two things:

    • Existing issue in clientset (override_work) with values that overflow and negative 16/8 bit values. This *may* be the reason why tunnel runner does not work properly in hyperspace.
    • Negative values did not read properly in get_override

    Note that this changes how override keys are built, override keys now also store a boolean to indicate if the value is signed.

    37a36,38
    > 
    > 	unsigned char lastSettingsPacket_hasData;
    > 	struct ClientSettings lastSettingsPacket;
    175c176,177
    < #define MAKE_KEY(field, len) ((offsetof(struct ClientSettings, field)) << 3 | ((len) << 16))
    ---
    > #define MAKE_UKEY(field, len) ((offsetof(struct ClientSettings, field)) << 3 | ((len) << 16))
    > #define MAKE_KEY(field, len) (MAKE_UKEY(field, len) | 0x80000000u)
    186c188
    < 				return MAKE_KEY(prizeweight_set[i], 8);
    ---
    > 				return MAKE_UKEY(prizeweight_set[i], 8);
    277a280
    > #undef MAKE_UKEY
    282,284c285,288
    < /* override keys are two small integers stuffed into an unsigned 32-bit
    <  * integer. the upper 16 bits are the length in bits, and the lower 16
    <  * are the offset in bits */
    ---
    > /* override keys are three small integers stuffed into an unsigned 32-bit
    >  * integer. the upper bit is set when the value is a signed value
    >  * then next 15 bits are the length in bits, and the lower 16 are the
    >  * offset in bits */
    288c292
    < 	int len = (key >> 16) & 0xffffu;
    ---
    > 	int len = (key >> 16) & 0x7fffu;
    305c309,311
    < 			((u32*)od->bits)[wordoff] |= val << bitoff;
    ---
    > 			((u32*)od->bits)[wordoff] |=
    > 			                             (((u32)val) & (0xffffffffu >> (32 - len))) // prevent overflow
    > 			                             << bitoff;
    308a315
    > 		{
    310a318
    > 	}
    345a354,405
    > int get_override(overridedata *od, override_key_t key, i32 *val)
    > {
    > 	int issigned = !!(key & 0x80000000u);
    > 	int len = (key >> 16) & 0x7fffu;
    > 	int offset = key & 0xffffu;
    > 	u32 value;
    > 
    > 	*val = 0;
    > 
    > 	/* don't override type byte */
    > 	if (offset < 8)
    > 		return 0;
    > 
    > 	if (len <= 32 && ((offset & 31) + len) <= 32)
    > 	{
    > 		/* easier case: a bunch of bits that fit within a word boundary */
    > 		int wordoff = offset >> 5;
    > 		int bitoff = offset & 31;
    > 		u32 mask = (0xffffffffu >> (32 - len)) << bitoff;
    > 
    > 		if ((((u32*)od->mask)[wordoff] & mask) == mask)
    > 		{
    > 			value = ((u32*)od->bits)[wordoff];
    > 			value &= mask;
    > 			value = value >> bitoff;
    > 
    > 			if (issigned && (value & (1 << (len-1)))) // sign bit set?
    > 				value |= (0xffffffffu >> (32-len)) << (32-len); // add 32 bit sign bit and the invert for 2's complement
    > 
    > 			*val = value;
    > 
    > 			return 1;
    > 		}
    > 		else
    > 		{
    > 			return 0;
    > 		}
    > 
    > 	}
    > #if 0
    > 	else if (len <= 32 && ((offset & 31) + len) <= 64)
    > 	{
    > 		#error "Not implemented"
    > 	}
    > #endif
    > 	else
    > 	{
    > 		lm->Log(L_WARN, "<clientset> illegal override key: %x", key);
    > 		return 0;
    > 	}
    > }
    > 
    382a443,471
    > local int GetArenaOverride(Arena *arena, override_key_t key, i32 *value)
    > {
    > 	int ret;
    > 	adata *ad = P_ARENA_DATA(arena, adkey);
    > 	LOCK();
    > 	ret = get_override(&ad->od, key, value);
    > 	UNLOCK();
    > 	return ret;
    > 
    > }
    > 
    > local int GetPlayerOverride(Player *p, override_key_t key, i32 *value)
    > {
    > 	int ret;
    > 	pdata *data = PPDATA(p, pdkey);
    > 	LOCK();
    > 	if (data->od)
    > 	{
    > 		ret = get_override(data->od, key, value);
    > 	}
    > 	else
    > 	{
    > 		*value = 0;
    > 		ret = 0;
    > 	}
    > 	UNLOCK();
    > 	return ret;
    > }
    > 
    384a474
    > /* call with lock held */
    416d505
    < 	struct ClientSettings tosend;
    418,420c507,511
    < 	do_mask(&tosend, &ad->cs, &ad->od, data->od);
    < 	if (tosend.bit_set.type == S2C_SETTINGS)
    < 		net->SendToOne(p, (byte*)&tosend, sizeof(tosend), NET_RELIABLE);
    ---
    > 	do_mask(&data->lastSettingsPacket, &ad->cs, &ad->od, data->od);
    > 	data->lastSettingsPacket_hasData = 1;
    > 
    > 	if (data->lastSettingsPacket.bit_set.type == S2C_SETTINGS)
    > 		net->SendToOne(p, (byte*)&data->lastSettingsPacket, sizeof(data->lastSettingsPacket), NET_RELIABLE);
    432c523
    < 	else if (action == AA_CONFCHANGED)
    ---
    > 	else if (action == AA_CONFCHANGED && cfg->GetInt(GLOBAL, "clientset", "DetectConfigChange", 1))
    485,486c576
    < 	struct ClientSettings tochecksum;
    < 	u32 *bits = (u32*)&tochecksum;
    ---
    > 	u32 *bits = (u32*)&data->lastSettingsPacket;
    494c584,588
    < 	do_mask(&tochecksum, &ad->cs, &ad->od, data->od);
    ---
    > 	if (!data->lastSettingsPacket_hasData)
    > 	{
    > 		do_mask(&data->lastSettingsPacket, &ad->cs, &ad->od, data->od);
    > 		data->lastSettingsPacket_hasData = 1;
    > 	}
    533,534c626,627
    < 	ArenaOverride, ArenaUnoverride,
    < 	PlayerOverride, PlayerUnoverride,
    ---
    > 	ArenaOverride, ArenaUnoverride, GetArenaOverride,
    > 	PlayerOverride, PlayerUnoverride, GetPlayerOverride
    
  2. Justin Schwartz

    I'd be curious to know if it does fix All:GravityTopSpeed. Another known issue is that you cannot override both Flag:FlaggerSpeedAdjustment and Flag:FlaggerThrustAdjustment for a player--one of them will lose the override if you attempt both.

  3. Joris reporter

    The issue with Flag:FlaggerSpeedAdjustment and Flag:FlaggerThrustAdjustment is why I spotted this error. The issue only occurs if Flag:FlaggerSpeedAdjustment (or the thrust one, i forgot) is overridden negative (due to 2's complement). It could occur with half of the 16 bit settings, but most of them do not make sense if negative. This is indeed fixed in the patch, overflow is also prevented (like passing 2,000,000,000 for a 16 bit value)

  4. Former user Account Deleted

    Jowie's proposed changes were added in Wiki macro error: Changeset f9238c5a064a not found.. Some of the function prototypes are different, but the functionality is all there.

  5. Joris reporter
    • changed status to new

    Small bugfix, all byte settings are supposed to be unsigned:

    205c205
    < 					return MAKE_SIGNED_KEY(ships[i].byte_set[j], 8);
    ---
    > 					return MAKE_UNSIGNED_KEY(ships[i].byte_set[j], 8);
    263c263
    < 			return MAKE_SIGNED_KEY(byte_set[i], 8);
    ---
    > 			return MAKE_UNSIGNED_KEY(byte_set[i], 8);
    
  6. Log in to comment