X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafb-session.c;h=63c9f595dd1c43b3472d848693b5f873fdc85476;hb=fafe08c7608f3950ed20b54d7e01e1beeb7306b7;hp=536cdbccd46d6faa1e2c31cbc2035dc816122c12;hpb=b192d4cc46d8bda166116432ee28042e95750052;p=src%2Fapp-framework-binder.git diff --git a/src/afb-session.c b/src/afb-session.c index 536cdbcc..63c9f595 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -49,7 +49,6 @@ struct afb_session unsigned refcount; int timeout; time_t expiration; // expiration time of the token - time_t access; pthread_mutex_t mutex; char uuid[37]; // long term authentication of remote client char token[37]; // short term authentication of remote client @@ -59,25 +58,13 @@ struct afb_session // 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 - struct afb_session **store; // sessions store + struct afb_session **store; // sessions store int count; // current number of sessions int max; int timeout; char initok[37]; } sessions; -/** - * Get the index of the 'key' in the cookies array. - * @param key the key to scan - * @return the index of the list for key within cookies - */ -static int cookeyidx(const void *key) -{ - intptr_t x = (intptr_t)key; - unsigned r = (unsigned)((x >> 5) ^ (x >> 15)); - return r & COOKEYMASK; -} - /* generate a uuid */ static void new_uuid(char uuid[37]) { @@ -97,7 +84,7 @@ static inline void unlock(struct afb_session *session) } // Free context [XXXX Should be protected again memory abort XXXX] -static void free_data (struct afb_session *session) +static void remove_all_cookies(struct afb_session *session) { int idx; struct cookie *cookie, *next; @@ -120,7 +107,7 @@ static void free_data (struct afb_session *session) void afb_session_init (int max_session_count, int timeout, const char *initok) { // let's create as store as hashtable does not have any - sessions.store = calloc (1 + (unsigned)max_session_count, sizeof(struct afb_session)); + sessions.store = calloc (1 + (unsigned)max_session_count, sizeof *sessions.store); pthread_mutex_init(&sessions.mutex, NULL); sessions.max = max_session_count; sessions.timeout = timeout; @@ -135,6 +122,11 @@ void afb_session_init (int max_session_count, int timeout, const char *initok) } } +const char *afb_session_initial_token() +{ + return sessions.initok; +} + static struct afb_session *search (const char* uuid) { int idx; @@ -235,6 +227,12 @@ static struct afb_session *make_session (const char *uuid, int timeout, time_t n { struct afb_session *session; + if (!AFB_SESSION_TIMEOUT_IS_VALID(timeout) + || (uuid && strlen(uuid) >= sizeof session->uuid)) { + errno = EINVAL; + goto error; + } + /* allocates a new one */ session = calloc(1, sizeof *session); if (session == NULL) { @@ -245,21 +243,20 @@ static struct afb_session *make_session (const char *uuid, int timeout, time_t n /* generate the uuid */ if (uuid == NULL) { - new_uuid(session->uuid); + do { new_uuid(session->uuid); } while(search(session->uuid)); } else { - if (strlen(uuid) >= sizeof session->uuid) { - errno = EINVAL; - goto error2; - } strcpy(session->uuid, uuid); } /* init the token */ strcpy(session->token, sessions.initok); + + /* init timeout */ + if (timeout == AFB_SESSION_TIMEOUT_DEFAULT) + timeout = sessions.timeout; session->timeout = timeout; - if (timeout != 0) - session->expiration = now + timeout; - else { + 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); @@ -269,7 +266,6 @@ static struct afb_session *make_session (const char *uuid, int timeout, time_t n goto error2; } - session->access = now; session->refcount = 1; return session; @@ -279,7 +275,8 @@ error: return NULL; } -struct afb_session *afb_session_create (const char *uuid, int timeout) +/* Creates a new session with 'timeout' */ +struct afb_session *afb_session_create (int timeout) { time_t now; @@ -287,17 +284,25 @@ struct afb_session *afb_session_create (const char *uuid, int timeout) now = NOW; cleanup (now); - /* search for an existing one not too old */ - if (uuid != NULL && search(uuid) != NULL) { - errno = EEXIST; - return NULL; - } + return make_session(NULL, timeout, now); +} + +/* Searchs the session of 'uuid' */ +struct afb_session *afb_session_search (const char *uuid) +{ + time_t now; + struct afb_session *session; + + /* cleaning */ + now = NOW; + cleanup (now); + session = search(uuid); + return session; - return make_session(uuid, timeout, now); } -// This function will return exiting session or newly created session -struct afb_session *afb_session_get (const char *uuid, int *created) +/* This function will return exiting session or newly created session */ +struct afb_session *afb_session_get (const char *uuid, int timeout, int *created) { struct afb_session *session; time_t now; @@ -310,15 +315,19 @@ struct afb_session *afb_session_get (const char *uuid, int *created) if (uuid != NULL) { session = search(uuid); if (session != NULL) { - *created = 0; - session->access = now; + if (created) + *created = 0; session->refcount++; return session; } } - *created = 1; - return make_session(uuid, sessions.timeout, now); + /* no existing session found, create it */ + session = make_session(uuid, timeout, now); + if (created) + *created = !!session; + + return session; } struct afb_session *afb_session_addref(struct afb_session *session) @@ -348,7 +357,7 @@ void afb_session_close (struct afb_session *session) assert(session != NULL); if (session->uuid[0] != 0) { session->uuid[0] = 0; - free_data (session); + remove_all_cookies(session); if (session->refcount == 0) { destroy (session); free(session); @@ -385,99 +394,132 @@ void afb_session_new_token (struct afb_session *session) session->expiration = NOW + session->timeout; } +/* Returns the uuid of 'session' */ const char *afb_session_uuid (struct afb_session *session) { assert(session != NULL); return session->uuid; } +/* Returns the token of 'session' */ const char *afb_session_token (struct afb_session *session) { assert(session != NULL); return session->token; } -static struct cookie *cookie_search(struct afb_session *session, const void *key, int *idx) -{ - struct cookie *cookie; - - cookie = session->cookies[*idx = cookeyidx(key)]; - while(cookie != NULL && cookie->key != key) - cookie = cookie->next; - return cookie; -} - -static struct cookie *cookie_add(struct afb_session *session, int idx, const void *key, void *value, void (*freecb)(void*)) +/** + * Get the index of the 'key' in the cookies array. + * @param key the key to scan + * @return the index of the list for key within cookies + */ +static int cookeyidx(const void *key) { - struct cookie *cookie; - - cookie = malloc(sizeof *cookie); - if (!cookie) - errno = ENOMEM; - else { - cookie->key = key; - cookie->value = value; - cookie->freecb = freecb; - cookie->next = session->cookies[idx]; - session->cookies[idx] = cookie; - } - return cookie; + intptr_t x = (intptr_t)key; + unsigned r = (unsigned)((x >> 5) ^ (x >> 15)); + return r & COOKEYMASK; } -void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void), void (*freecb)(void*)) +/** + * Set, get, replace, remove a cookie of 'key' for the 'session' + * + * 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 + * + * @return the value of the cookie + * + * The 'key' is a pointer and compared as pointers. + * + * For getting the current value of the cookie: + * + * afb_session_cookie(session, key, NULL, NULL, NULL, 0) + * + * For storing the value of the cookie + * + * afb_session_cookie(session, key, NULL, NULL, value, 1) + */ +void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void *closure), void (*freecb)(void *item), void *closure, int replace) { int idx; void *value; - struct cookie *cookie; + struct cookie *cookie, **prv; + /* get key hashed index */ + idx = cookeyidx(key); + + /* lock session and search for the cookie of 'key' */ lock(session); - cookie = cookie_search(session, key, &idx); - if (cookie) - value = cookie->value; - else { - value = makecb ? makecb() : NULL; - if (makecb || freecb) { - cookie = cookie_add(session, idx, key, value, freecb); - if (!cookie) { - if (makecb && freecb) - free(value); - value = NULL; + prv = &session->cookies[idx]; + for (;;) { + cookie = *prv; + if (!cookie) { + /* 'key' not found, create value using 'closure' and 'makecb' */ + value = makecb ? makecb(closure) : closure; + /* store the the only if it has some meaning */ + if (replace || makecb || freecb) { + cookie = malloc(sizeof *cookie); + if (!cookie) { + errno = ENOMEM; + /* calling freecb if there is no makecb may have issue */ + if (makecb && freecb) + freecb(value); + value = NULL; + } else { + cookie->key = key; + cookie->value = value; + cookie->freecb = freecb; + cookie->next = NULL; + *prv = cookie; + } } + break; + } else if (cookie->key == key) { + /* cookie of key found */ + if (!replace) + /* not replacing, get the value */ + value = cookie->value; + else { + /* create value using 'closure' and 'makecb' */ + value = makecb ? makecb(closure) : closure; + + /* free previous value is needed */ + if (cookie->value != value && cookie->freecb) + cookie->freecb(cookie->value); + + /* store the value and its releaser */ + cookie->value = value; + cookie->freecb = freecb; + + /* but if both are NULL drop the cookie */ + if (!value && !freecb) { + *prv = cookie->next; + free(cookie); + } + } + break; + } else { + prv = &(cookie->next); } } + + /* unlock the session and return the value */ unlock(session); return value; } void *afb_session_get_cookie(struct afb_session *session, const void *key) { - int idx; - void *value; - struct cookie *cookie; - - lock(session); - cookie = cookie_search(session, key, &idx); - value = cookie ? cookie->value : NULL; - unlock(session); - return value; + return afb_session_cookie(session, key, NULL, NULL, NULL, 0); } int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)) { - int idx; - struct cookie *cookie; - - lock(session); - cookie = cookie_search(session, key, &idx); - if (!cookie) - cookie = cookie_add(session, idx, key, value, freecb); - else { - if (cookie->value != value && cookie->freecb) - cookie->freecb(cookie->value); - cookie->value = value; - cookie->freecb = freecb; - } - unlock(session); - return -!cookie; + return -(value != afb_session_cookie(session, key, NULL, freecb, value, 1)); }