Fix bug #3, sid allocation overflow. May lead to double SIDs being given out.
This commit is contained in:
parent
b78d48795b
commit
9bd0286c01
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -57,7 +57,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);
|
||||
|
||||
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
Loading…
Reference in New Issue