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;
|
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
|
#define SID_MAX 1048576
|
||||||
|
|
||||||
|
struct sid_pool;
|
||||||
|
struct hub_user;
|
||||||
|
|
||||||
extern const char* BASE32_ALPHABET;
|
extern const char* BASE32_ALPHABET;
|
||||||
extern char* sid_to_string(sid_t sid_);
|
extern char* sid_to_string(sid_t sid_);
|
||||||
extern sid_t string_to_sid(const char* sid);
|
extern sid_t string_to_sid(const char* sid);
|
||||||
|
|
||||||
struct sid_map
|
extern struct sid_pool* sid_pool_create(sid_t max);
|
||||||
{
|
extern void sid_pool_destroy(struct sid_pool*);
|
||||||
struct hub_user* ptr;
|
|
||||||
struct sid_map* next;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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 sid_t sid_alloc(struct sid_pool*, struct hub_user*);
|
||||||
extern void sid_free(struct sid_pool*, sid_t);
|
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)
|
void hub_send_sid(struct hub_info* hub, struct hub_user* u)
|
||||||
{
|
{
|
||||||
|
sid_t sid;
|
||||||
struct adc_message* command;
|
struct adc_message* command;
|
||||||
if (user_is_connecting(u))
|
if (user_is_connecting(u))
|
||||||
{
|
{
|
||||||
command = adc_msg_construct(ADC_CMD_ISID, 10);
|
command = adc_msg_construct(ADC_CMD_ISID, 10);
|
||||||
u->id.sid = uman_get_free_sid(hub);
|
sid = uman_get_free_sid(hub, u);
|
||||||
adc_msg_add_argument(command, (const char*) sid_to_string(u->id.sid));
|
adc_msg_add_argument(command, (const char*) sid_to_string(sid));
|
||||||
route_to_user(hub, u, command);
|
route_to_user(hub, u, command);
|
||||||
adc_msg_free(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.id = UHUB_EVENT_USER_DESTROY;
|
||||||
post.ptr = user;
|
post.ptr = user;
|
||||||
event_queue_post(hub->queue, &post);
|
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)
|
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);
|
evtimer_set(&user->net.timeout, net_event, user);
|
||||||
event_base_set(hub->evbase, &user->net.timeout);
|
event_base_set(hub->evbase, &user->net.timeout);
|
||||||
|
|
||||||
|
|
||||||
user_set_timeout(user, TIMEOUT_CONNECTED);
|
user_set_timeout(user, TIMEOUT_CONNECTED);
|
||||||
|
|
||||||
@ -215,12 +214,6 @@ void user_support_remove(struct hub_user* user, int fourcc)
|
|||||||
user->flags &= ~feature_mask;
|
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])
|
int user_have_feature_cast_support(struct hub_user* user, char feature[4])
|
||||||
{
|
{
|
||||||
char* tmp = list_get_first(user->feature_cast);
|
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);
|
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.
|
* This associates a INF message to the user.
|
||||||
* If the user already has a INF message associated, then this is
|
* 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;
|
return -1;
|
||||||
|
|
||||||
users->list = list_create();
|
users->list = list_create();
|
||||||
users->free_sid = 1;
|
users->sids = sid_pool_create(MAX(1024, (hub->config->max_users + 24)));
|
||||||
|
|
||||||
if (!users->list)
|
if (!users->list)
|
||||||
{
|
{
|
||||||
@ -134,6 +134,7 @@ int uman_shutdown(struct hub_info* hub)
|
|||||||
list_clear(hub->users->list, &clear_user_list_callback);
|
list_clear(hub->users->list, &clear_user_list_callback);
|
||||||
list_destroy(hub->users->list);
|
list_destroy(hub->users->list);
|
||||||
}
|
}
|
||||||
|
sid_pool_destroy(hub->users->sids);
|
||||||
hub_free(hub->users);
|
hub_free(hub->users);
|
||||||
hub->users = 0;
|
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* 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 */
|
return sid_lookup(hub->users->sids, sid);
|
||||||
while (user)
|
|
||||||
{
|
|
||||||
if (user->id.sid == sid)
|
|
||||||
return user;
|
|
||||||
user = (struct hub_user*) list_get_next(hub->users->list);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -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);
|
adc_msg_add_argument(command, ADC_QUI_FLAG_DISCONNECT);
|
||||||
}
|
}
|
||||||
|
|
||||||
route_to_all(hub, command);
|
route_to_all(hub, command);
|
||||||
adc_msg_free(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
|
sid_t sid = sid_alloc(hub->users->sids, user);
|
||||||
struct hub_user* user;
|
user->id.sid = sid;
|
||||||
user = (struct hub_user*) list_get_first(hub->users->list); /* iterate normal users */
|
return sid;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ struct hub_user_manager
|
|||||||
{
|
{
|
||||||
size_t count; /**<< "Number of all fully connected and logged in users" */
|
size_t count; /**<< "Number of all fully connected and logged in users" */
|
||||||
size_t count_peak; /**<< "Peak number of 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_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." */
|
uint64_t shared_files; /**<< "The total number of shared files among fully connected users." */
|
||||||
struct linked_list* list; /**<< "Contains all 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).
|
* 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).
|
* Lookup a user based on the session ID (SID).
|
||||||
|
Loading…
Reference in New Issue
Block a user