X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?p=src%2Fapp-framework-binder.git;a=blobdiff_plain;f=src%2Fafb-session.c;h=80bad1b27e358a882acb2ab201475de0af809d73;hp=16fc69bbccd574071c39a966c64fe7e52f3e8d25;hb=65353dce81a629e042800bb7b86fcd869a76727e;hpb=4521c1e7ae5371ab9d639adc617d17fb4e8ded0c diff --git a/src/afb-session.c b/src/afb-session.c index 16fc69bb..80bad1b2 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015-2018 "IoT.bzh" + * Copyright (C) 2015-2020 "IoT.bzh" * Author "Fulup Ar Foll" * Author: José Bollo * @@ -24,16 +24,23 @@ #include #include #include -#include #include #include "afb-session.h" #include "afb-hook.h" #include "verbose.h" #include "pearson.h" +#include "uuid.h" -#define SIZEUUID 37 -#define HEADCOUNT 16 +#define SESSION_COUNT_MIN 5 +#define SESSION_COUNT_MAX 1000 + +/* + * Handling of cookies. + * Cookies are stored by session. + * The cookie count COOKIECOUNT must be a power of 2, possible values: 1, 2, 4, 8, 16, 32, 64, ... + * For low memory profile, small values are better, 1 is possible. + */ #define COOKIECOUNT 8 #define COOKIEMASK (COOKIECOUNT - 1) @@ -59,34 +66,36 @@ struct cookie struct afb_session { struct afb_session *next; /**< link to the next */ - unsigned refcount; /**< external reference count of the session */ + uint16_t refcount; /**< count of reference to the session */ + uint16_t id; /**< local id of the session */ int timeout; /**< timeout of the session */ - time_t expiration; /**< expiration time of the token */ + time_t expiration; /**< expiration time of the session */ pthread_mutex_t mutex; /**< mutex of the session */ struct cookie *cookies[COOKIECOUNT]; /**< cookies of the session */ + char *lang; /**< current language setting for the session */ uint8_t closed: 1; /**< is the session closed ? */ uint8_t autoclose: 1; /**< close the session when unreferenced */ uint8_t notinset: 1; /**< session removed from the set of sessions */ - char uuid[SIZEUUID]; /**< long term authentication of remote client */ - char token[SIZEUUID]; /**< short term authentication of remote client */ + uint8_t hash; /**< hash value of the uuid */ + uuid_stringz_t uuid; /**< identification of client session */ }; /** * structure for managing sessions */ static struct { - int count; /**< current number of sessions */ - int max; /**< maximum count of sessions */ - int timeout; /**< common initial timeout */ - struct afb_session *heads[HEADCOUNT]; /**< sessions */ - char initok[SIZEUUID]; /**< common initial token */ - pthread_mutex_t mutex; /**< declare a mutex to protect hash table */ + uint16_t count; /**< current number of sessions */ + uint16_t max; /**< maximum count of sessions */ + uint16_t genid; /**< for generating ids */ + int timeout; /**< common initial timeout */ + struct afb_session *first; /**< sessions */ + pthread_mutex_t mutex; /**< declare a mutex to protect hash table */ } sessions = { .count = 0, .max = 10, + .genid = 1, .timeout = 3600, - .heads = { 0 }, - .initok = { 0 }, + .first = 0, .mutex = PTHREAD_MUTEX_INITIALIZER }; @@ -100,16 +109,6 @@ static inline time_t time_now() return ts.tv_sec; } -/** - * generate a new fresh 'uuid' - */ -static void new_uuid(char uuid[SIZEUUID]) -{ - uuid_t newuuid; - uuid_generate(newuuid); - uuid_unparse_lower(newuuid, uuid); -} - /* lock the set of sessions for exclusive access */ static inline void sessionset_lock() { @@ -131,8 +130,23 @@ static struct afb_session *sessionset_search(const char *uuid, uint8_t hashidx) { struct afb_session *session; - session = sessions.heads[hashidx]; - while (session && strcmp(uuid, session->uuid)) + session = sessions.first; + while (session && hashidx != session->hash && strcmp(uuid, session->uuid)) + session = session->next; + + return session; +} + +/* + * search within the set of sessions the session of 'id'. + * return the session or NULL + */ +static struct afb_session *sessionset_search_id(uint16_t id) +{ + struct afb_session *session; + + session = sessions.first; + while (session && id != session->id) session = session->next; return session; @@ -148,19 +162,19 @@ static int sessionset_add(struct afb_session *session, uint8_t hashidx) } /* add the session */ - session->next = sessions.heads[hashidx]; - sessions.heads[hashidx] = session; + session->next = sessions.first; + sessions.first = session; sessions.count++; return 0; } /* make a new uuid not used in the set of sessions */ -static uint8_t sessionset_make_uuid (char uuid[SIZEUUID]) +static uint8_t sessionset_make_uuid (uuid_stringz_t uuid) { uint8_t hashidx; do { - new_uuid(uuid); + uuid_new_stringz(uuid); hashidx = pearson4(uuid); } while(sessionset_search(uuid, hashidx)); return hashidx; @@ -189,8 +203,10 @@ static void session_close(struct afb_session *session) /* close it now */ session->closed = 1; +#if WITH_AFB_HOOK /* emit the hook */ afb_hook_session_close(session); +#endif /* release cookies */ for (idx = 0 ; idx < COOKIECOUNT ; idx++) { @@ -207,8 +223,11 @@ static void session_close(struct afb_session *session) /* destroy the 'session' */ static void session_destroy (struct afb_session *session) { +#if WITH_AFB_HOOK afb_hook_session_destroy(session); +#endif pthread_mutex_destroy(&session->mutex); + free(session->lang); free(session); } @@ -254,9 +273,11 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now pthread_mutex_init(&session->mutex, NULL); session->refcount = 1; strcpy(session->uuid, uuid); - strcpy(session->token, sessions.initok); session->timeout = timeout; session_update_expiration(session, now); + session->id = ++sessions.genid; + while (session->id == 0 || sessionset_search_id(session->id) != NULL) + session->id = ++sessions.genid; /* add */ if (sessionset_add(session, hashidx)) { @@ -264,7 +285,9 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now return NULL; } +#if WITH_AFB_HOOK afb_hook_session_create(session); +#endif return session; } @@ -273,29 +296,26 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now static time_t sessionset_cleanup (int force) { struct afb_session *session, **prv; - int idx; time_t now; /* Loop on Sessions Table and remove anything that is older than timeout */ now = NOW; - for (idx = 0 ; idx < HEADCOUNT; idx++) { - prv = &sessions.heads[idx]; - while ((session = *prv)) { - session_lock(session); - if (force || session->expiration < now) - session_close(session); - if (!session->closed) - prv = &session->next; - else { - *prv = session->next; - sessions.count--; - session->notinset = 1; - if ( !session->refcount) { - session_destroy(session); - continue; - } - } + prv = &sessions.first; + while ((session = *prv)) { + session_lock(session); + if (force || session->expiration < now) + session_close(session); + if (!session->closed) { + prv = &session->next; session_unlock(session); + } else { + *prv = session->next; + sessions.count--; + session->notinset = 1; + if (session->refcount) + session_unlock(session); + else + session_destroy(session); } } return now; @@ -303,32 +323,23 @@ static time_t sessionset_cleanup (int force) /** * Initialize the session manager with a 'max_session_count', - * an initial common 'timeout' and an initial common token 'initok'. + * an initial common 'timeout' * * @param max_session_count maximum allowed session count in the same time * @param timeout the initial default timeout of sessions - * @param initok the initial default token of sessions - * */ -int afb_session_init (int max_session_count, int timeout, const char *initok) +int afb_session_init (int max_session_count, int timeout) { - /* check parameters */ - if (initok && strlen(initok) >= sizeof sessions.initok) { - ERROR("initial token '%s' too long (max length %d)", - initok, ((int)(sizeof sessions.initok)) - 1); - errno = EINVAL; - return -1; - } - /* init the sessionset (after cleanup) */ sessionset_lock(); sessionset_cleanup(1); - sessions.max = max_session_count; - sessions.timeout = timeout; - if (initok == NULL) - new_uuid(sessions.initok); + if (max_session_count > SESSION_COUNT_MAX) + sessions.max = SESSION_COUNT_MAX; + else if (max_session_count < SESSION_COUNT_MIN) + sessions.max = SESSION_COUNT_MIN; else - strcpy(sessions.initok, initok); + sessions.max = (uint16_t)max_session_count; + sessions.timeout = timeout; sessionset_unlock(); return 0; } @@ -340,17 +351,14 @@ int afb_session_init (int max_session_count, int timeout, const char *initok) void afb_session_foreach(void (*callback)(void *closure, struct afb_session *session), void *closure) { struct afb_session *session; - int idx; /* Loop on Sessions Table and remove anything that is older than timeout */ sessionset_lock(); - for (idx = 0 ; idx < HEADCOUNT; idx++) { - session = sessions.heads[idx]; - while (session) { - if (!session->closed) - callback(closure, session); - session = session->next; - } + session = sessions.first; + while (session) { + if (!session->closed) + callback(closure, session); + session = session->next; } sessionset_unlock(); } @@ -365,14 +373,6 @@ void afb_session_purge() sessionset_unlock(); } -/** - * @return the initial token set at initialization - */ -const char *afb_session_initial_token() -{ - return sessions.initok; -} - /* Searchs the session of 'uuid' */ struct afb_session *afb_session_search (const char *uuid) { @@ -416,13 +416,14 @@ int afb_session_timeout(struct afb_session *session) */ int afb_session_what_remains(struct afb_session *session) { - return (int)(session->expiration - NOW); + int diff = (int)(session->expiration - NOW); + return diff < 0 ? 0 : diff; } /* This function will return exiting session or newly created session */ struct afb_session *afb_session_get (const char *uuid, int timeout, int *created) { - char _uuid_[SIZEUUID]; + uuid_stringz_t _uuid_; uint8_t hashidx; struct afb_session *session; time_t now; @@ -461,7 +462,9 @@ end: struct afb_session *afb_session_addref(struct afb_session *session) { if (session != NULL) { +#if WITH_AFB_HOOK afb_hook_session_addref(session); +#endif session_lock(session); session->refcount++; session_unlock(session); @@ -475,7 +478,9 @@ void afb_session_unref(struct afb_session *session) if (session == NULL) return; +#if WITH_AFB_HOOK afb_hook_session_unref(session); +#endif session_lock(session); if (!--session->refcount) { if (session->autoclose) @@ -516,42 +521,16 @@ int afb_session_is_closed (struct afb_session *session) return session->closed; } -/* - * check whether the token of 'session' is 'token' - * return 1 if true or 0 otherwise - */ -int afb_session_check_token (struct afb_session *session, const char *token) -{ - int r; - - session_unlock(session); - r = !session->closed - && session->expiration >= NOW - && !(session->token[0] && strcmp (token, session->token)); - session_unlock(session); - return r; -} - -/* generate a new token and update client context */ -void afb_session_new_token (struct afb_session *session) -{ - session_unlock(session); - new_uuid(session->token); - session_update_expiration(session, NOW); - afb_hook_session_renew(session); - session_unlock(session); -} - /* Returns the uuid of 'session' */ const char *afb_session_uuid (struct afb_session *session) { return session->uuid; } -/* Returns the token of 'session' */ -const char *afb_session_token (struct afb_session *session) +/* Returns the local id of 'session' */ +uint16_t afb_session_id (struct afb_session *session) { - return session->token; + return session->id; } /** @@ -559,12 +538,16 @@ const char *afb_session_token (struct afb_session *session) * @param key the key to scan * @return the index of the list for key within cookies */ +#if COOKIEMASK static int cookeyidx(const void *key) { intptr_t x = (intptr_t)key; unsigned r = (unsigned)((x >> 5) ^ (x >> 15)); return r & COOKIEMASK; } +#else +# define cookeyidx(key) 0 +#endif /** * Set, get, replace, remove a cookie of 'key' for the 'session' @@ -576,7 +559,7 @@ static int cookeyidx(const void *key) * @param makecb the creation function or NULL * @param freecb the release function or NULL * @param closure an argument for makecb or the value if makecb==NULL - * @param replace a boolean enforcing replecement of the previous value + * @param replace a boolean enforcing replacement of the previous value * * @return the value of the cookie * @@ -688,3 +671,37 @@ int afb_session_set_cookie(struct afb_session *session, const void *key, void *v return -(value != afb_session_cookie(session, key, NULL, freecb, value, 1)); } +/** + * Set the language attached to the session + * + * @param session the session to set + * @param lang the language specifiction to set to session + * + * @return 0 in case of success or -1 in case of error + */ +int afb_session_set_language(struct afb_session *session, const char *lang) +{ + char *oldl, *newl; + + newl = strdup(lang); + if (newl == NULL) + return -1; + + oldl = session->lang; + session->lang = newl; + free(oldl); + return 0; +} + +/** + * Get the language attached to the session + * + * @param session the session to query + * @param lang a default language specifiction + * + * @return the langauage specification to use for session + */ +const char *afb_session_get_language(struct afb_session *session, const char *lang) +{ + return session->lang ?: lang; +}