afb-session: Verbs for timeout and remining time
[src/app-framework-binder.git] / src / afb-session.c
index 88d5b0d..c63c6c4 100644 (file)
@@ -22,6 +22,7 @@
 #include <pthread.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <limits.h>
 #include <string.h>
 #include <uuid/uuid.h>
 #include <errno.h>
@@ -29,6 +30,7 @@
 #include <json-c/json.h>
 
 #include "afb-session.h"
+#include "afb-hook.h"
 #include "verbose.h"
 
 #define SIZEUUID       37
@@ -39,7 +41,7 @@
 #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))
+#define NOW            (time_now())
 
 /* structure for a cookie added to sessions */
 struct cookie
@@ -85,6 +87,14 @@ static struct {
        .mutex = PTHREAD_MUTEX_INITIALIZER
 };
 
+/* Get the actual raw time */
+static inline time_t time_now()
+{
+       struct timespec ts;
+       clock_gettime(CLOCK_MONOTONIC_RAW, &ts);
+       return ts.tv_sec;
+}
+
 /* generate a new fresh 'uuid' */
 static void new_uuid(char uuid[SIZEUUID])
 {
@@ -189,9 +199,13 @@ static void session_close(struct afb_session *session)
 
        /* close only one time */
        if (!session->closed) {
+               /* close it now */
                session->closed = 1;
 
-               /* free cookies */
+               /* emit the hook */
+               afb_hook_session_close(session);
+
+               /* release cookies */
                for (idx = 0 ; idx < COOKIECOUNT ; idx++) {
                        while ((cookie = session->cookies[idx])) {
                                session->cookies[idx] = cookie->next;
@@ -206,6 +220,7 @@ static void session_close(struct afb_session *session)
 /* destroy the 'session' */
 static void session_destroy (struct afb_session *session)
 {
+       afb_hook_session_destroy(session);
        pthread_mutex_destroy(&session->mutex);
        free(session);
 }
@@ -213,21 +228,12 @@ static void session_destroy (struct afb_session *session)
 /* update expiration of 'session' according to 'now' */
 static void session_update_expiration(struct afb_session *session, time_t now)
 {
-       int timeout;
        time_t expiration;
 
        /* compute expiration */
-       timeout = session->timeout;
-       if (timeout == AFB_SESSION_TIMEOUT_INFINITE)
+       expiration = now + afb_session_timeout(session);
+       if (expiration < 0)
                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 expiration */
        session->expiration = expiration;
@@ -271,6 +277,8 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now
                return NULL;
        }
 
+       afb_hook_session_create(session);
+
        return session;
 }
 
@@ -338,6 +346,28 @@ int afb_session_init (int max_session_count, int timeout, const char *initok)
        return 0;
 }
 
+/**
+ * Iterate the sessions and call 'callback' with
+ * the 'closure' for each session.
+ */
+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;
+               }
+       }
+       sessionset_unlock();
+}
+
 /**
  * Cleanup the sessionset of its closed or expired sessions
  */
@@ -378,6 +408,30 @@ struct afb_session *afb_session_create (int timeout)
        return afb_session_get(NULL, timeout, NULL);
 }
 
+/**
+ * Returns the timeout of 'session' in seconds
+ */
+int afb_session_timeout(struct afb_session *session)
+{
+       int timeout;
+
+       /* compute timeout */
+       timeout = session->timeout;
+       if (timeout == AFB_SESSION_TIMEOUT_DEFAULT)
+               timeout = sessions.timeout;
+       if (timeout < 0)
+               timeout = INT_MAX;
+       return timeout;
+}
+
+/**
+ * Returns the second remaining before expiration of 'session'
+ */
+int afb_session_what_remains(struct afb_session *session)
+{
+       return (int)(session->expiration - NOW);
+}
+
 /* This function will return exiting session or newly created session */
 struct afb_session *afb_session_get (const char *uuid, int timeout, int *created)
 {
@@ -419,8 +473,11 @@ end:
 /* increase the use count on 'session' (can be NULL) */
 struct afb_session *afb_session_addref(struct afb_session *session)
 {
-       if (session != NULL)
-               __atomic_add_fetch(&session->refcount, 1, __ATOMIC_RELAXED);
+       if (session != NULL) {
+               afb_hook_session_addref(session);
+               session->refcount++;
+               session_unlock(session);
+       }
        return session;
 }
 
@@ -431,7 +488,8 @@ void afb_session_unref(struct afb_session *session)
                return;
 
        session_lock(session);
-       if (!__atomic_sub_fetch(&session->refcount, 1, __ATOMIC_RELAXED)) {
+       afb_hook_session_unref(session);
+       if (--session->refcount) {
                if (session->autoclose)
                        session_close(session);
                if (session->notinset) {
@@ -489,11 +547,11 @@ int afb_session_check_token (struct afb_session *session, const char *token)
 /* generate a new token and update client context */
 void afb_session_new_token (struct afb_session *session)
 {
-       /* Old token was valid let's regenerate a new one */
+       session_unlock(session);
        new_uuid(session->token);
-
-       /* keep track of time for session timeout and further clean up */
        session_update_expiration(session, NOW);
+       afb_hook_session_renew(session);
+       session_unlock(session);
 }
 
 /* Returns the uuid of 'session' */