Fix bug #3, sid allocation overflow. May lead to double SIDs being given out.

This commit is contained in:
Jan Vidar Krey 2009-08-02 21:04:10 +02:00
parent b78d48795b
commit 9bd0286c01
7 changed files with 92 additions and 84 deletions

View File

@ -59,3 +59,72 @@ sid_t string_to_sid(const char* sid)
return nsid;
}
/*
* Session IDs are heavily reused, since they are a fairly scarce
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
* value and 'AAAA' (0) is reserved for the hub.
*
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
*
* When allocating a session ID:
* - If 'count' is less than the pool size (max-min), then allocate within the pool
* - Increase the pool size (see below)
* - If unable to do that, hub is really full - don't let anyone in!
*
* When freeing a session ID:
* - If the session ID being freed is 'max', then decrease the pool size by one.
*
*/
struct sid_pool
{
sid_t min;
sid_t max;
sid_t count;
struct hub_user** map;
};
struct sid_pool* sid_pool_create(sid_t max)
{
struct sid_pool* pool = hub_malloc(sizeof(struct sid_pool));
pool->min = 1;
pool->max = max + 1;
pool->count = 0;
pool->map = hub_malloc_zero(sizeof(struct hub_user*) * pool->max);
pool->map[0] = (struct hub_user*) pool; /* hack to reserve the first sid. */
LOG_DUMP("SID_POOL: max=%d", (int) pool->max);
return pool;
}
void sid_pool_destroy(struct sid_pool* pool)
{
LOG_DUMP("SID_POOL: destroying, current allocs=%d", (int) pool->count);
hub_free(pool->map);
hub_free(pool);
}
sid_t sid_alloc(struct sid_pool* pool, struct hub_user* user)
{
sid_t n = (++pool->count);
for (; (pool->map[n % pool->max]); n++) ;
LOG_DUMP("SID_ALLOC: %d, user=%p", (int) n, user);
pool->map[n] = user;
return n;
}
void sid_free(struct sid_pool* pool, sid_t sid)
{
LOG_DUMP("SID_FREE: %d", (int) sid);
pool->map[sid] = 0;
pool->count--;
}
struct hub_user* sid_lookup(struct sid_pool* pool, sid_t sid)
{
if (!sid || (sid > pool->max))
return 0;
return pool->map[sid];
}

View File

@ -22,44 +22,19 @@
#define SID_MAX 1048576
struct sid_pool;
struct hub_user;
extern const char* BASE32_ALPHABET;
extern char* sid_to_string(sid_t sid_);
extern sid_t string_to_sid(const char* sid);
struct sid_map
{
struct hub_user* ptr;
struct sid_map* next;
};
extern struct sid_pool* sid_pool_create(sid_t max);
extern void sid_pool_destroy(struct sid_pool*);
/**
* Session IDs are heavily reused, since they are a fairly scarce
* resource. Only one (2^10)-1 exist, since it is a four byte base32-encoded
* value and 'AAAA' (0) is reserved for the hub.
*
* Initialize with sid_initialize(), which sets min and max to one, and count to 0.
*
* When allocating a session ID:
* - If 'count' is less than the pool size (max-min), then allocate within the pool
* - Increase the pool size (see below)
* - If unable to do that, hub is really full - don't let anyone in!
*
* When freeing a session ID:
* - If the session ID being freed is 'max', then decrease the pool size by one.
*
*/
struct sid_pool
{
sid_t min;
sid_t max;
sid_t count;
struct sid_map* map;
};
extern void sid_initialize(struct sid_pool*);
extern sid_t sid_alloc(struct sid_pool*, struct hub_user*);
extern void sid_free(struct sid_pool*, sid_t);
extern struct hub_user* sid_lookup(struct sid_pool*, sid_t);

View File

@ -238,12 +238,13 @@ void hub_send_support(struct hub_info* hub, struct hub_user* u)
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
{
sid_t sid;
struct adc_message* command;
if (user_is_connecting(u))
{
command = adc_msg_construct(ADC_CMD_ISID, 10);
u->id.sid = uman_get_free_sid(hub);
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
sid = uman_get_free_sid(hub, u);
adc_msg_add_argument(command, (const char*) sid_to_string(sid));
route_to_user(hub, u, command);
adc_msg_free(command);
}
@ -958,6 +959,11 @@ void hub_schedule_destroy_user(struct hub_info* hub, struct hub_user* user)
post.id = UHUB_EVENT_USER_DESTROY;
post.ptr = user;
event_queue_post(hub->queue, &post);
if (user->id.sid)
{
sid_free(hub->users->sids, user->id.sid);
}
}
void hub_disconnect_user(struct hub_info* hub, struct hub_user* user, int reason)

View File

@ -58,7 +58,6 @@ struct hub_user* user_create(struct hub_info* hub, int sd)
evtimer_set(&user->net.timeout, net_event, user);
event_base_set(hub->evbase, &user->net.timeout);
user_set_timeout(user, TIMEOUT_CONNECTED);
user_set_state(user, state_protocol);
@ -215,12 +214,6 @@ void user_support_remove(struct hub_user* user, int fourcc)
user->flags &= ~feature_mask;
}
void user_disconnect(struct hub_user* user, int reason)
{
}
int user_have_feature_cast_support(struct hub_user* user, char feature[4])
{
char* tmp = list_get_first(user->feature_cast);

View File

@ -147,22 +147,6 @@ extern struct hub_user* user_create(struct hub_info* hub, int sd);
*/
extern void user_destroy(struct hub_user* user);
/**
* Disconnect a user.
* This will mark the user connection ready for being terminated.
* A reason can be given using the enum user_quit_reason.
*
* Things to be done when calling this:
* - Mark the user with state_cleanup
*
* If the user is logged in to the hub:
* - post message: UHUB_EVENT_USER_QUIT
*
* @param user User to disconnect
* @param reason See enum user_quit_reason
*/
extern void user_disconnect(struct hub_user* user, int reason);
/**
* This associates a INF message to the user.
* If the user already has a INF message associated, then this is

View File

@ -97,7 +97,7 @@ int uman_init(struct hub_info* hub)
return -1;
users->list = list_create();
users->free_sid = 1;
users->sids = sid_pool_create(MAX(1024, (hub->config->max_users + 24)));
if (!users->list)
{
@ -134,6 +134,7 @@ int uman_shutdown(struct hub_info* hub)
list_clear(hub->users->list, &clear_user_list_callback);
list_destroy(hub->users->list);
}
sid_pool_destroy(hub->users->sids);
hub_free(hub->users);
hub->users = 0;
@ -187,14 +188,7 @@ int uman_remove(struct hub_info* hub, struct hub_user* user)
struct hub_user* uman_get_user_by_sid(struct hub_info* hub, sid_t sid)
{
struct hub_user* user = (struct hub_user*) list_get_first(hub->users->list); /* iterate users */
while (user)
{
if (user->id.sid == sid)
return user;
user = (struct hub_user*) list_get_next(hub->users->list);
}
return NULL;
return sid_lookup(hub->users->sids, sid);
}
@ -275,28 +269,15 @@ void uman_send_quit_message(struct hub_info* hub, struct hub_user* leaving)
{
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
}
route_to_all(hub, command);
adc_msg_free(command);
}
sid_t uman_get_free_sid(struct hub_info* hub)
sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user)
{
#if 0
struct hub_user* user;
user = (struct hub_user*) list_get_first(hub->users->list); /* iterate normal users */
while (user)
{
if (user->sid == hub->users->free_sid)
{
hub->users->free_sid++;
if (hub->users->free_sid >= SID_MAX) hub->users->free_sid = 1;
break;
}
user = (struct hub_user*) list_get_next(hub->users->list);
}
#endif
return hub->users->free_sid++;
sid_t sid = sid_alloc(hub->users->sids, user);
user->id.sid = sid;
return sid;
}

View File

@ -24,7 +24,7 @@ struct hub_user_manager
{
size_t count; /**<< "Number of all fully connected and logged in users" */
size_t count_peak; /**<< "Peak number of users" */
sid_t free_sid; /**<< "The next available SID." */
struct sid_pool* sids;
uint64_t shared_size; /**<< "The total number of shared bytes among fully connected users." */
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
struct linked_list* list; /**<< "Contains all users" */
@ -70,7 +70,7 @@ extern int uman_remove(struct hub_info* hub, struct hub_user* user);
/**
* Returns and allocates an unused session ID (SID).
*/
extern sid_t uman_get_free_sid(struct hub_info* hub);
extern sid_t uman_get_free_sid(struct hub_info* hub, struct hub_user* user);
/**
* Lookup a user based on the session ID (SID).