X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-session.c;h=6b6ad634170cc1c7820d301e11f64e3db0b83bc0;hb=0891ef4826e347d5554c630b5c0ce73c68f76c9c;hp=3befb92ec1c69ef63216876197aeab39431c4c69;hpb=5bffa91c6c719b828a317adfb913ce57dbb2c6f0;p=src%2Fapp-framework-binder.git diff --git a/src/afb-session.c b/src/afb-session.c index 3befb92e..6b6ad634 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -31,11 +31,15 @@ #include "afb-session.h" #include "verbose.h" -#define HEADCOUNT 16 -#define COOKEYCOUNT 8 -#define COOKEYMASK (COOKEYCOUNT - 1) +#define SIZEUUID 37 +#define HEADCOUNT 16 +#define COOKEYCOUNT 8 +#define COOKEYMASK (COOKEYCOUNT - 1) -#define NOW (time(NULL)) +#define _MAXEXP_ ((time_t)(~(time_t)0)) +#define _MAXEXP2_ ((time_t)((((unsigned long long)_MAXEXP_) >> 1))) +#define MAX_EXPIRATION (_MAXEXP_ >= 0 ? _MAXEXP_ : _MAXEXP2_) +#define NOW (time(NULL)) struct cookie { @@ -50,26 +54,27 @@ struct afb_session struct afb_session *next; /* link to the next */ unsigned refcount; int timeout; - time_t expiration; // expiration time of the token + time_t expiration; // expiration time of the token pthread_mutex_t mutex; - char idx; - char uuid[37]; // long term authentication of remote client - char token[37]; // short term authentication of remote client struct cookie *cookies[COOKEYCOUNT]; + char autoclose; + char idx; + char uuid[SIZEUUID]; // long term authentication of remote client + char token[SIZEUUID]; // short term authentication of remote client }; // Session UUID are store in a simple array [for 10 sessions this should be enough] static struct { - pthread_mutex_t mutex; // declare a mutex to protect hash table + pthread_mutex_t mutex; // declare a mutex to protect hash table struct afb_session *heads[HEADCOUNT]; // sessions - int count; // current number of sessions + int count; // current number of sessions int max; int timeout; - char initok[37]; + char initok[SIZEUUID]; } sessions; /* generate a uuid */ -static void new_uuid(char uuid[37]) +static void new_uuid(char uuid[SIZEUUID]) { uuid_t newuuid; uuid_generate(newuuid); @@ -87,21 +92,18 @@ static inline void unlock(struct afb_session *session) } // Free context [XXXX Should be protected again memory abort XXXX] -static void remove_all_cookies(struct afb_session *session) +static void close_session(struct afb_session *session) { int idx; - struct cookie *cookie, *next; + struct cookie *cookie; - // free cookies + /* free cookies */ for (idx = 0 ; idx < COOKEYCOUNT ; idx++) { - cookie = session->cookies[idx]; - session->cookies[idx] = NULL; - while (cookie != NULL) { - next = cookie->next; + while ((cookie = session->cookies[idx])) { + session->cookies[idx] = cookie->next; if (cookie->freecb != NULL) cookie->freecb(cookie->value); free(cookie); - cookie = next; } } } @@ -161,6 +163,7 @@ static void destroy (struct afb_session *session) assert (session != NULL); + close_session(session); pthread_mutex_lock(&sessions.mutex); prv = &sessions.heads[(int)session->idx]; while (*prv) @@ -176,20 +179,6 @@ static void destroy (struct afb_session *session) pthread_mutex_unlock(&sessions.mutex); } -// Check if context timeout or not -static int is_expired (struct afb_session *ctx, time_t now) -{ - assert (ctx != NULL); - return ctx->expiration < now; -} - -// Check if context is active or not -static int is_active (struct afb_session *ctx, time_t now) -{ - assert (ctx != NULL); - return ctx->uuid[0] != 0 && ctx->expiration >= now; -} - // Loop on every entry and remove old context sessions.hash static time_t cleanup () { @@ -203,7 +192,7 @@ static time_t cleanup () session = sessions.heads[idx]; while (session) { next = session->next; - if (is_expired(session, now)) + if (session->expiration < now) afb_session_close(session); session = next; } @@ -211,16 +200,44 @@ static time_t cleanup () return now; } +static void update_timeout(struct afb_session *session, time_t now, int timeout) +{ + time_t expiration; + + /* compute expiration */ + if (timeout == AFB_SESSION_TIMEOUT_INFINITE) + expiration = MAX_EXPIRATION; + else { + if (timeout == AFB_SESSION_TIMEOUT_DEFAULT) + expiration = now + sessions.timeout; + else + expiration = now + timeout; + if (expiration < 0) + expiration = MAX_EXPIRATION; + } + + /* record the values */ + session->timeout = timeout; + session->expiration = expiration; +} + +static void update_expiration(struct afb_session *session, time_t now) +{ + update_timeout(session, now, session->timeout); +} + static struct afb_session *add_session (const char *uuid, int timeout, time_t now, int idx) { struct afb_session *session; + /* check arguments */ if (!AFB_SESSION_TIMEOUT_IS_VALID(timeout) || (uuid && strlen(uuid) >= sizeof session->uuid)) { errno = EINVAL; return NULL; } + /* check session count */ if (sessions.count >= sessions.max) { errno = EBUSY; return NULL; @@ -233,22 +250,14 @@ static struct afb_session *add_session (const char *uuid, int timeout, time_t no return NULL; } + /* initialize */ pthread_mutex_init(&session->mutex, NULL); session->refcount = 1; strcpy(session->uuid, uuid); strcpy(session->token, sessions.initok); + update_timeout(session, now, timeout); - /* init timeout */ - if (timeout == AFB_SESSION_TIMEOUT_DEFAULT) - timeout = sessions.timeout; - session->timeout = timeout; - session->expiration = now + timeout; - if (timeout == AFB_SESSION_TIMEOUT_INFINITE || session->expiration < 0) { - session->expiration = (time_t)(~(time_t)0); - if (session->expiration < 0) - session->expiration = (time_t)(((unsigned long long)session->expiration) >> 1); - } - + /* link */ session->idx = (char)idx; session->next = sessions.heads[idx]; sessions.heads[idx] = session; @@ -257,10 +266,11 @@ static struct afb_session *add_session (const char *uuid, int timeout, time_t no return session; } +/* create a new session for the given timeout */ static struct afb_session *new_session (int timeout, time_t now) { int idx; - char uuid[37]; + char uuid[SIZEUUID]; do { new_uuid(uuid); @@ -293,6 +303,8 @@ struct afb_session *afb_session_search (const char *uuid) pthread_mutex_lock(&sessions.mutex); cleanup(); session = search(uuid, pearson4(uuid)); + if (session) + __atomic_add_fetch(&session->refcount, 1, __ATOMIC_RELAXED); pthread_mutex_unlock(&sessions.mutex); return session; @@ -315,7 +327,7 @@ struct afb_session *afb_session_get (const char *uuid, int timeout, int *created else { idx = pearson4(uuid); session = search(uuid, idx); - if (session != NULL) { + if (session) { __atomic_add_fetch(&session->refcount, 1, __ATOMIC_RELAXED); pthread_mutex_unlock(&sessions.mutex); if (created) @@ -346,22 +358,51 @@ void afb_session_unref(struct afb_session *session) if (session != NULL) { assert(session->refcount != 0); if (!__atomic_sub_fetch(&session->refcount, 1, __ATOMIC_RELAXED)) { - if (session->uuid[0] == 0) + pthread_mutex_lock(&session->mutex); + if (session->autoclose || session->uuid[0] == 0) destroy (session); + else + pthread_mutex_unlock(&session->mutex); } } } -// Free Client Session Context +// close Client Session Context void afb_session_close (struct afb_session *session) { assert(session != NULL); + pthread_mutex_lock(&session->mutex); if (session->uuid[0] != 0) { session->uuid[0] = 0; - remove_all_cookies(session); - if (session->refcount == 0) + if (session->refcount) + close_session(session); + else { destroy (session); + return; + } } + pthread_mutex_unlock(&session->mutex); +} + +/* set the autoclose flag */ +void afb_session_set_autoclose(struct afb_session *session, int autoclose) +{ + assert(session != NULL); + session->autoclose = (char)!!autoclose; +} + +// is the session active? +int afb_session_is_active (struct afb_session *session) +{ + assert(session != NULL); + return !!session->uuid[0]; +} + +// is the session closed? +int afb_session_is_closed (struct afb_session *session) +{ + assert(session != NULL); + return !session->uuid[0]; } // Sample Generic Ping Debug API @@ -370,8 +411,10 @@ int afb_session_check_token (struct afb_session *session, const char *token) assert(session != NULL); assert(token != NULL); - // compare current token with previous one - if (!is_active (session, NOW)) + if (!session->uuid[0]) + return 0; + + if (session->expiration < NOW) return 0; if (session->token[0] && strcmp (token, session->token) != 0) @@ -389,8 +432,7 @@ void afb_session_new_token (struct afb_session *session) new_uuid(session->token); // keep track of time for session timeout and further clean up - if (session->timeout != 0) - session->expiration = NOW + session->timeout; + update_expiration(session, NOW); } /* Returns the uuid of 'session' */ @@ -424,12 +466,12 @@ static int cookeyidx(const void *key) * * The behaviour of this function depends on its parameters: * - * @param session the session - * @param key the key of the cookie - * @param makecb the creation function - * @param freecb the release function - * @param closure an argument - * @param replace a boolean enforcing replecement of the previous value + * @param session the session + * @param key the key of the cookie + * @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 * * @return the value of the cookie *