Allow detection of session closure
[src/app-framework-binder.git] / src / afb-session.c
index db81457..bc1c1c5 100644 (file)
 #include "afb-session.h"
 #include "verbose.h"
 
-#define NOW (time(NULL))
+#define COOKEYCOUNT  8
+#define COOKEYMASK   (COOKEYCOUNT - 1)
 
-struct value
-{
-       void *value;
-       void (*freecb)(void*);
-};
+#define NOW (time(NULL))
 
 struct cookie
 {
@@ -56,8 +53,7 @@ struct afb_session
        time_t access;
        char uuid[37];        // long term authentication of remote client
        char token[37];       // short term authentication of remote client
-       struct value *values;
-       struct cookie *cookies;
+       struct cookie *cookies[COOKEYCOUNT];
 };
 
 // Session UUID are store in a simple array [for 10 sessions this should be enough]
@@ -67,10 +63,21 @@ static struct {
        int count;                      // current number of sessions
        int max;
        int timeout;
-       int apicount;
        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])
 {
@@ -83,34 +90,29 @@ static void new_uuid(char uuid[37])
 static void free_data (struct afb_session *session)
 {
        int idx;
-       struct cookie *cookie;
-
-       // If application add a handle let's free it now
-       assert (session->values != NULL);
-
-       // Free session handle with a standard Free function, with app callback or ignore it
-       for (idx=0; idx < sessions.apicount; idx ++)
-               afb_session_set_value(session, idx, NULL, NULL);
+       struct cookie *cookie, *next;
 
        // free cookies
-       cookie = session->cookies;
-       while (cookie != NULL) {
-               session->cookies = cookie->next;
-               if (cookie->value != NULL && cookie->freecb != NULL)
-                       cookie->freecb(cookie->value);
-               free(cookie);
-               cookie = session->cookies;
+       for (idx = 0 ; idx < COOKEYCOUNT ; idx++) {
+               cookie = session->cookies[idx];
+               session->cookies[idx] = NULL;
+               while (cookie != NULL) {
+                       next = cookie->next;
+                       if (cookie->freecb != NULL)
+                               cookie->freecb(cookie->value);
+                       free(cookie);
+                       cookie = next;
+               }
        }
 }
 
 // Create a new store in RAM, not that is too small it will be automatically extended
-void afb_session_init (int max_session_count, int timeout, const char *initok, int context_count)
+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.max = max_session_count;
        sessions.timeout = timeout;
-       sessions.apicount = context_count;
        if (initok == NULL)
                /* without token, a secret is made to forbid creation of sessions */
                new_uuid(sessions.initok);
@@ -223,12 +225,11 @@ 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) + ((unsigned)sessions.apicount * sizeof(*session->values)));
+       session = calloc(1, sizeof(struct afb_session));
        if (session == NULL) {
                errno = ENOMEM;
                goto error;
        }
-       session->values = (void*)(session + 1);
 
        /* generate the uuid */
        if (uuid == NULL) {
@@ -394,31 +395,13 @@ void afb_session_set_LOA (struct afb_session *session, unsigned loa)
        session->loa = loa;
 }
 
-void *afb_session_get_value(struct afb_session *session, int index)
-{
-       assert(session != NULL);
-       assert(index >= 0);
-       assert(index < sessions.apicount);
-       return session->values[index].value;
-}
-
-void afb_session_set_value(struct afb_session *session, int index, void *value, void (*freecb)(void*))
-{
-       struct value prev;
-       assert(session != NULL);
-       assert(index >= 0);
-       assert(index < sessions.apicount);
-       prev = session->values[index];
-       session->values[index] = (struct value){.value = value, .freecb = freecb};
-       if (prev.value != NULL && prev.value != value && prev.freecb != NULL)
-               prev.freecb(prev.value);
-}
-
 void *afb_session_get_cookie(struct afb_session *session, const void *key)
 {
        struct cookie *cookie;
+       int idx;
 
-       cookie = session->cookies;
+       idx = cookeyidx(key);
+       cookie = session->cookies[idx];
        while(cookie != NULL) {
                if (cookie->key == key)
                        return cookie->value;
@@ -430,12 +413,14 @@ void *afb_session_get_cookie(struct afb_session *session, const void *key)
 int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*))
 {
        struct cookie *cookie;
+       int idx;
 
        /* search for a replacement */
-       cookie = session->cookies;
+       idx = cookeyidx(key);
+       cookie = session->cookies[idx];
        while(cookie != NULL) {
                if (cookie->key == key) {
-                       if (cookie->value != NULL && cookie->value != value && cookie->freecb != NULL)
+                       if (cookie->value != value && cookie->freecb)
                                cookie->freecb(cookie->value);
                        cookie->value = value;
                        cookie->freecb = freecb;
@@ -454,8 +439,8 @@ int afb_session_set_cookie(struct afb_session *session, const void *key, void *v
        cookie->key = key;
        cookie->value = value;
        cookie->freecb = freecb;
-       cookie->next = session->cookies;
-       session->cookies = cookie;
+       cookie->next = session->cookies[idx];
+       session->cookies[idx] = cookie;
        return 0;
 }