#include <pthread.h>
#include <stdlib.h>
#include <stdint.h>
+#include <limits.h>
#include <string.h>
#include <uuid/uuid.h>
#include <errno.h>
#include <json-c/json.h>
#include "afb-session.h"
+#include "afb-hook.h"
#include "verbose.h"
#define SIZEUUID 37
#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
.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])
{
/* 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;
/* destroy the 'session' */
static void session_destroy (struct afb_session *session)
{
+ afb_hook_session_destroy(session);
pthread_mutex_destroy(&session->mutex);
free(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;
return NULL;
}
+ afb_hook_session_create(session);
+
return session;
}
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
*/
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)
{
/* 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;
}
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) {
/* 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' */