void (*free_value)(void*);
};
+struct cookie
+{
+ struct cookie *next;
+ const void *key;
+ void *value;
+ void (*free_value)(void*);
+};
+
struct AFB_clientCtx
{
unsigned refcount;
unsigned loa;
+ int timeout;
time_t expiration; // expiration time of the token
time_t access;
char uuid[37]; // long term authentication of remote client
char token[37]; // short term authentication of remote client
struct client_value *values;
+ struct cookie *cookies;
};
// Session UUID are store in a simple array [for 10 sessions this should be enough]
static void ctxUuidFreeCB (struct AFB_clientCtx *client)
{
int idx;
+ struct cookie *cookie;
// If application add a handle let's free it now
assert (client->values != NULL);
// Free client handle with a standard Free function, with app callback or ignore it
for (idx=0; idx < sessions.apicount; idx ++)
ctxClientValueSet(client, idx, NULL, NULL);
+
+ // free cookies
+ cookie = client->cookies;
+ while (cookie != NULL) {
+ client->cookies = cookie->next;
+ if (cookie->value != NULL && cookie->free_value != NULL)
+ cookie->free_value(cookie->value);
+ free(cookie);
+ cookie = client->cookies;
+ }
}
// Create a new store in RAM, not that is too small it will be automatically extended
}
}
-// This function will return exiting client context or newly created client context
-struct AFB_clientCtx *ctxClientGetSession (const char *uuid, int *created)
+static struct AFB_clientCtx *new_context (const char *uuid, int timeout, time_t now)
{
struct AFB_clientCtx *clientCtx;
- time_t now;
- /* cleaning */
- now = NOW;
- ctxStoreCleanUp (now);
-
- /* search for an existing one not too old */
- if (uuid != NULL) {
- if (strlen(uuid) >= sizeof clientCtx->uuid) {
- errno = EINVAL;
- goto error;
- }
- clientCtx = ctxStoreSearch(uuid);
- if (clientCtx != NULL) {
- *created = 0;
- goto found;
- }
- }
-
- /* returns a new one */
+ /* allocates a new one */
clientCtx = calloc(1, sizeof(struct AFB_clientCtx) + ((unsigned)sessions.apicount * sizeof(*clientCtx->values)));
if (clientCtx == NULL) {
errno = ENOMEM;
if (uuid == NULL) {
new_uuid(clientCtx->uuid);
} else {
+ if (strlen(uuid) >= sizeof clientCtx->uuid) {
+ errno = EINVAL;
+ goto error2;
+ }
strcpy(clientCtx->uuid, uuid);
}
/* init the token */
strcpy(clientCtx->token, sessions.initok);
- clientCtx->expiration = now + sessions.timeout;
+ clientCtx->timeout = timeout;
+ if (timeout != 0)
+ clientCtx->expiration = now + timeout;
+ else {
+ clientCtx->expiration = (time_t)(~(time_t)0);
+ if (clientCtx->expiration < 0)
+ clientCtx->expiration = (time_t)(((unsigned long long)clientCtx->expiration) >> 1);
+ }
if (!ctxStoreAdd (clientCtx)) {
errno = ENOMEM;
goto error2;
}
- *created = 1;
-found:
clientCtx->access = now;
- clientCtx->refcount++;
+ clientCtx->refcount = 1;
return clientCtx;
error2:
return NULL;
}
+struct AFB_clientCtx *ctxClientCreate (const char *uuid, int timeout)
+{
+ time_t now;
+
+ /* cleaning */
+ now = NOW;
+ ctxStoreCleanUp (now);
+
+ /* search for an existing one not too old */
+ if (uuid != NULL && ctxStoreSearch(uuid) != NULL) {
+ errno = EEXIST;
+ return NULL;
+ }
+
+ return new_context(uuid, timeout, now);
+}
+
+// This function will return exiting client context or newly created client context
+struct AFB_clientCtx *ctxClientGetSession (const char *uuid, int *created)
+{
+ struct AFB_clientCtx *clientCtx;
+ time_t now;
+
+ /* cleaning */
+ now = NOW;
+ ctxStoreCleanUp (now);
+
+ /* search for an existing one not too old */
+ if (uuid != NULL) {
+ clientCtx = ctxStoreSearch(uuid);
+ if (clientCtx != NULL) {
+ *created = 0;
+ clientCtx->access = now;
+ clientCtx->refcount++;
+ return clientCtx;
+ }
+ }
+
+ *created = 1;
+ return new_context(uuid, sessions.timeout, now);
+}
+
struct AFB_clientCtx *ctxClientAddRef(struct AFB_clientCtx *clientCtx)
{
if (clientCtx != NULL)
new_uuid(clientCtx->token);
// keep track of time for session timeout and further clean up
- clientCtx->expiration = NOW + sessions.timeout;
+ if (clientCtx->timeout != 0)
+ clientCtx->expiration = NOW + clientCtx->timeout;
}
const char *ctxClientGetUuid (struct AFB_clientCtx *clientCtx)
if (prev.value != NULL && prev.value != value && prev.free_value != NULL)
prev.free_value(prev.value);
}
+
+void *ctxClientCookieGet(struct AFB_clientCtx *clientCtx, const void *key)
+{
+ struct cookie *cookie;
+
+ cookie = clientCtx->cookies;
+ while(cookie != NULL) {
+ if (cookie->key == key)
+ return cookie->value;
+ cookie = cookie->next;
+ }
+ return NULL;
+}
+
+int ctxClientCookieSet(struct AFB_clientCtx *clientCtx, const void *key, void *value, void (*free_value)(void*))
+{
+ struct cookie *cookie;
+
+ /* search for a replacement */
+ cookie = clientCtx->cookies;
+ while(cookie != NULL) {
+ if (cookie->key == key) {
+ if (cookie->value != NULL && cookie->value != value && cookie->free_value != NULL)
+ cookie->free_value(cookie->value);
+ cookie->value = value;
+ cookie->free_value = free_value;
+ return 0;
+ }
+ cookie = cookie->next;
+ }
+
+ /* allocates */
+ cookie = malloc(sizeof *cookie);
+ if (cookie == NULL) {
+ errno = ENOMEM;
+ return -1;
+ }
+
+ cookie->key = key;
+ cookie->value = value;
+ cookie->free_value = free_value;
+ cookie->next = clientCtx->cookies;
+ clientCtx->cookies = cookie;
+ return 0;
+}
+