afb-session: redefine the function 'afb_session_create'
[src/app-framework-binder.git] / src / afb-session.c
index 17fddd5..2b649ef 100644 (file)
@@ -50,6 +50,7 @@ struct afb_session
        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
        struct cookie *cookies[COOKEYCOUNT];
@@ -85,6 +86,16 @@ static void new_uuid(char uuid[37])
        uuid_unparse_lower(newuuid, uuid);
 }
 
+static inline void lock(struct afb_session *session)
+{
+       pthread_mutex_lock(&session->mutex);
+}
+
+static inline void unlock(struct afb_session *session)
+{
+       pthread_mutex_unlock(&session->mutex);
+}
+
 // Free context [XXXX Should be protected again memory abort XXXX]
 static void free_data (struct afb_session *session)
 {
@@ -109,7 +120,8 @@ 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;
        if (initok == NULL)
@@ -123,6 +135,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;
@@ -224,15 +241,16 @@ static struct afb_session *make_session (const char *uuid, int timeout, time_t n
        struct afb_session *session;
 
        /* allocates a new one */
-       session = calloc(1, sizeof(struct afb_session));
+       session = calloc(1, sizeof *session);
        if (session == NULL) {
                errno = ENOMEM;
                goto error;
        }
+       pthread_mutex_init(&session->mutex, NULL);
 
        /* 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;
@@ -266,7 +284,7 @@ error:
        return NULL;
 }
 
-struct afb_session *afb_session_create (const char *uuid, int timeout)
+struct afb_session *afb_session_create (int timeout)
 {
        time_t now;
 
@@ -274,13 +292,7 @@ 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(uuid, timeout, now);
+       return make_session(NULL, timeout, now);
 }
 
 // This function will return exiting session or newly created session
@@ -296,6 +308,8 @@ struct afb_session *afb_session_get (const char *uuid, int *created)
        /* search for an existing one not too old */
        if (uuid != NULL) {
                session = search(uuid);
+               if (!created)
+                       return session;
                if (session != NULL) {
                        *created = 0;
                        session->access = now;
@@ -304,14 +318,16 @@ struct afb_session *afb_session_get (const char *uuid, int *created)
                }
        }
 
-       *created = 1;
+       if (created)
+               *created = 1;
+
        return make_session(uuid, sessions.timeout, now);
 }
 
 struct afb_session *afb_session_addref(struct afb_session *session)
 {
        if (session != NULL)
-               session->refcount++;
+               __atomic_add_fetch(&session->refcount, 1, __ATOMIC_RELAXED);
        return session;
 }
 
@@ -319,10 +335,12 @@ void afb_session_unref(struct afb_session *session)
 {
        if (session != NULL) {
                assert(session->refcount != 0);
-               --session->refcount;
-               if (session->refcount == 0 && session->uuid[0] == 0) {
-                       destroy (session);
-                       free(session);
+               if (!__atomic_sub_fetch(&session->refcount, 1, __ATOMIC_RELAXED)) {
+                       if (session->uuid[0] == 0) {
+                               destroy (session);
+                               pthread_mutex_destroy(&session->mutex);
+                               free(session);
+                       }
                }
        }
 }
@@ -382,52 +400,60 @@ const char *afb_session_token (struct afb_session *session)
        return session->token;
 }
 
-void *afb_session_get_cookie(struct afb_session *session, const void *key)
+void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void *closure), void (*freecb)(void *item), void *closure, int replace)
 {
-       struct cookie *cookie;
        int idx;
-
-       idx = cookeyidx(key);
-       cookie = session->cookies[idx];
-       while(cookie != NULL) {
-               if (cookie->key == key)
-                       return cookie->value;
-               cookie = cookie->next;
-       }
-       return NULL;
-}
-
-int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*))
-{
+       void *value;
        struct cookie *cookie;
-       int idx;
 
-       /* search for a replacement */
        idx = cookeyidx(key);
+       lock(session);
        cookie = session->cookies[idx];
-       while(cookie != NULL) {
-               if (cookie->key == key) {
-                       if (cookie->value != value && cookie->freecb)
-                               cookie->freecb(cookie->value);
-                       cookie->value = value;
-                       cookie->freecb = freecb;
-                       return 0;
+       for (;;) {
+               if (!cookie) {
+                       value = makecb ? makecb(closure) : closure;
+                       if (replace || makecb || freecb) {
+                               cookie = malloc(sizeof *cookie);
+                               if (!cookie) {
+                                       errno = ENOMEM;
+                                       if (freecb)
+                                               freecb(value);
+                                       value = NULL;
+                               } else {
+                                       cookie->key = key;
+                                       cookie->value = value;
+                                       cookie->freecb = freecb;
+                                       cookie->next = session->cookies[idx];
+                                       session->cookies[idx] = cookie;
+                               }
+                       }
+                       break;
+               } else if (cookie->key == key) {
+                       if (!replace)
+                               value = cookie->value;
+                       else {
+                               value = makecb ? makecb(closure) : closure;
+                               if (cookie->value != value && cookie->freecb)
+                                       cookie->freecb(cookie->value);
+                               cookie->value = value;
+                               cookie->freecb = freecb;
+                       }
+                       break;
+               } else {
+                       cookie = cookie->next;
                }
-               cookie = cookie->next;
        }
+       unlock(session);
+       return value;
+}
 
-       /* allocates */
-       cookie = malloc(sizeof *cookie);
-       if (cookie == NULL) {
-               errno = ENOMEM;
-               return -1;
-       }
+void *afb_session_get_cookie(struct afb_session *session, const void *key)
+{
+       return afb_session_cookie(session, key, NULL, NULL, NULL, 0);
+}
 
-       cookie->key = key;
-       cookie->value = value;
-       cookie->freecb = freecb;
-       cookie->next = session->cookies[idx];
-       session->cookies[idx] = cookie;
-       return 0;
+int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*))
+{
+       return -(value != afb_session_cookie(session, key, NULL, freecb, value, 1));
 }