diff --git a/src/adc/sid.c b/src/adc/sid.c index 135891f..2da560e 100644 --- a/src/adc/sid.c +++ b/src/adc/sid.c @@ -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]; +} diff --git a/src/adc/sid.h b/src/adc/sid.h index 9d4fa11..e2e30d6 100644 --- a/src/adc/sid.h +++ b/src/adc/sid.h @@ -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); diff --git a/src/core/hub.c b/src/core/hub.c index 168c883..4e82132 100644 --- a/src/core/hub.c +++ b/src/core/hub.c @@ -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) diff --git a/src/core/user.c b/src/core/user.c index 4036811..7686276 100644 --- a/src/core/user.c +++ b/src/core/user.c @@ -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); diff --git a/src/core/user.h b/src/core/user.h index a3e90ff..a423294 100644 --- a/src/core/user.h +++ b/src/core/user.h @@ -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 diff --git a/src/core/usermanager.c b/src/core/usermanager.c index 8f850b4..4c7fa91 100644 --- a/src/core/usermanager.c +++ b/src/core/usermanager.c @@ -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; } diff --git a/src/core/usermanager.h b/src/core/usermanager.h index 8832270..77f6d4b 100644 --- a/src/core/usermanager.h +++ b/src/core/usermanager.h @@ -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).