grelminar / asss (http://asss.yi.org/asss/)

A Small Subspace Server - main repository

Clone this repository (size: 5.5 MB): HTTPS / SSH
$ hg clone http://bitbucket.org/grelminar/asss/
follow

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

Status: resolved Responsible: drbrain Type: enhancement
Milestone: 1.5.0 Component: none Version: 1.5.0rc1

Attachments

No attachments added for this issue yet.

Comments and changes

#1

jowie

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.

#!C

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

akd

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

jowie

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

drbrain

→ Changed milestone from nothing to 1.5.0.

#5

drbrain

→ Changed status from new to resolved.

Jowie's proposed changes were added in r1137:f9238c5a064a . Some of the function prototypes are different, but the functionality is all there.


Add comment / attachment

Show/hide preview

Verification: Please write the text from the image in the box (letters only)

captcha

Is that you, Humanoid? Is this me?