diff options
-rw-r--r-- | src/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/afb-api-dbus.c | 12 | ||||
-rw-r--r-- | src/afb-api-so.c | 2 | ||||
-rw-r--r-- | src/afb-api-ws.c | 4 | ||||
-rw-r--r-- | src/afb-apis.c | 2 | ||||
-rw-r--r-- | src/afb-config.h | 3 | ||||
-rw-r--r-- | src/afb-context.c | 34 | ||||
-rw-r--r-- | src/afb-context.h | 6 | ||||
-rw-r--r-- | src/afb-evt.h | 2 | ||||
-rw-r--r-- | src/afb-hook.c | 12 | ||||
-rw-r--r-- | src/afb-hook.h | 4 | ||||
-rw-r--r-- | src/afb-hreq.c | 2 | ||||
-rw-r--r-- | src/afb-hreq.h | 2 | ||||
-rw-r--r-- | src/afb-hswitch.c | 2 | ||||
-rw-r--r-- | src/afb-session.c | 461 | ||||
-rw-r--r-- | src/afb-session.h | 46 | ||||
-rw-r--r-- | src/afb-svc.c | 16 | ||||
-rw-r--r-- | src/afb-ws-json1.c | 10 | ||||
-rw-r--r-- | src/main.c | 4 | ||||
-rw-r--r-- | src/session.c | 460 | ||||
-rw-r--r-- | src/session.h | 44 |
21 files changed, 565 insertions, 565 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 80d09bfe..0fcfba67 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -64,6 +64,7 @@ ADD_LIBRARY(afb-lib STATIC afb-hswitch.c afb-method.c afb-msg-json.c + afb-session.c afb-sig-handler.c afb-svc.c afb-subcall.c @@ -74,7 +75,6 @@ ADD_LIBRARY(afb-lib STATIC afb-ws.c afb-wsj1.c locale-root.c - session.c verbose.c websock.c ) diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index 9ebe1fad..4a5a4f1f 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -30,7 +30,7 @@ #include "afb-common.h" -#include "session.h" +#include "afb-session.h" #include "afb-msg-json.h" #include "afb-apis.h" #include "afb-api-so.h" @@ -340,7 +340,7 @@ static void api_dbus_client_call(struct api_dbus *api, struct afb_req req, struc rc = sd_bus_message_append(msg, "ssu", afb_req_raw(req, &size), - ctxClientGetUuid(context->session), + afb_session_uuid(context->session), (uint32_t)context->flags); if (rc < 0) goto error; @@ -724,7 +724,7 @@ static void afb_api_dbus_server_listener_free(struct listener *listener) free(listener); } -static struct listener *afb_api_dbus_server_listerner_get(struct api_dbus *api, const char *sender, struct AFB_clientCtx *session) +static struct listener *afb_api_dbus_server_listerner_get(struct api_dbus *api, const char *sender, struct afb_session *session) { int rc; struct listener *listener; @@ -736,7 +736,7 @@ static struct listener *afb_api_dbus_server_listerner_get(struct api_dbus *api, return NULL; /* retrieves the stored listener */ - listener = ctxClientCookieGet(session, destination); + listener = afb_session_get_cookie(session, destination); if (listener != NULL) { /* found */ afb_api_dbus_server_destination_unref(destination); @@ -751,7 +751,7 @@ static struct listener *afb_api_dbus_server_listerner_get(struct api_dbus *api, listener->destination = destination; listener->listener = afb_evt_listener_create(&evt_push_itf, destination); if (listener->listener != NULL) { - rc = ctxClientCookieSet(session, destination, listener, (void*)afb_api_dbus_server_listener_free); + rc = afb_session_set_cookie(session, destination, listener, (void*)afb_api_dbus_server_listener_free); if (rc == 0) return listener; afb_evt_listener_unref(listener->listener); @@ -963,7 +963,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd struct api_dbus *api = userdata; struct afb_req areq; uint32_t flags; - struct AFB_clientCtx *session; + struct afb_session *session; struct listener *listener; /* check the interface */ diff --git a/src/afb-api-so.c b/src/afb-api-so.c index 554df39a..74f94f36 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -33,7 +33,7 @@ #include <afb/afb-req-itf.h> #include <afb/afb-event-itf.h> -#include "session.h" +#include "afb-session.h" #include "afb-common.h" #include "afb-context.h" #include "afb-apis.h" diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c index cb7b4f58..4d1f08c8 100644 --- a/src/afb-api-ws.c +++ b/src/afb-api-ws.c @@ -37,7 +37,7 @@ #include "afb-common.h" -#include "session.h" +#include "afb-session.h" #include "afb-ws.h" #include "afb-msg-json.h" #include "afb-apis.h" @@ -827,7 +827,7 @@ static void api_ws_client_call_cb(void * closure, struct afb_req req, struct afb if (!api_ws_write_uint32(&wb, memo->msgid) || !api_ws_write_uint32(&wb, (uint32_t)context->flags) || !api_ws_write_string_nz(&wb, verb, lenverb) - || !api_ws_write_string(&wb, ctxClientGetUuid(context->session)) + || !api_ws_write_string(&wb, afb_session_uuid(context->session)) || !api_ws_write_string_length(&wb, raw, szraw)) goto overflow; diff --git a/src/afb-apis.c b/src/afb-apis.c index 6bc42779..7db3e75a 100644 --- a/src/afb-apis.c +++ b/src/afb-apis.c @@ -22,7 +22,7 @@ #include <stdio.h> #include <string.h> -#include "session.h" +#include "afb-session.h" #include "verbose.h" #include "afb-apis.h" #include "afb-context.h" diff --git a/src/afb-config.h b/src/afb-config.h index 9ff4cd64..7bbad4df 100644 --- a/src/afb-config.h +++ b/src/afb-config.h @@ -13,8 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#ifndef LOCAL_DEF_H -#define LOCAL_DEF_H #pragma once @@ -66,4 +64,3 @@ struct afb_config } aliasdir[MAX_ALIAS]; // alias mapping for icons,apps,... }; -#endif /* LOCAL_DEF_H */ diff --git a/src/afb-context.c b/src/afb-context.c index 0bcc79c3..eec4ebb0 100644 --- a/src/afb-context.c +++ b/src/afb-context.c @@ -21,10 +21,10 @@ #include <assert.h> #include <stdlib.h> -#include "session.h" +#include "afb-session.h" #include "afb-context.h" -static void init_context(struct afb_context *context, struct AFB_clientCtx *session, const char *token) +static void init_context(struct afb_context *context, struct afb_session *session, const char *token) { assert(session != NULL); @@ -32,28 +32,28 @@ static void init_context(struct afb_context *context, struct AFB_clientCtx *sess context->session = session; context->flags = 0; context->api_index = -1; - context->loa_in = ctxClientGetLOA(session) & 7; + context->loa_in = afb_session_get_LOA(session) & 7; /* check the token */ if (token != NULL) { - if (ctxTokenCheck(session, token)) + if (afb_session_check_token(session, token)) context->validated = 1; else context->invalidated = 1; } } -void afb_context_init(struct afb_context *context, struct AFB_clientCtx *session, const char *token) +void afb_context_init(struct afb_context *context, struct afb_session *session, const char *token) { - init_context(context, ctxClientAddRef(session), token); + init_context(context, afb_session_addref(session), token); } int afb_context_connect(struct afb_context *context, const char *uuid, const char *token) { int created; - struct AFB_clientCtx *session; + struct afb_session *session; - session = ctxClientGetSession (uuid, &created); + session = afb_session_get (uuid, &created); if (session == NULL) return -1; init_context(context, session, token); @@ -68,18 +68,18 @@ void afb_context_disconnect(struct afb_context *context) { if (context->session != NULL) { if (context->refreshing && !context->refreshed) { - ctxTokenNew (context->session); + afb_session_new_token (context->session); context->refreshed = 1; } if (context->loa_changing && !context->loa_changed) { - ctxClientSetLOA (context->session, context->loa_out); + afb_session_set_LOA (context->session, context->loa_out); context->loa_changed = 1; } if (context->closing && !context->closed) { - ctxClientClose(context->session); + afb_session_close(context->session); context->closed = 1; } - ctxClientUnref(context->session); + afb_session_unref(context->session); context->session = NULL; } } @@ -91,10 +91,10 @@ const char *afb_context_sent_token(struct afb_context *context) if (!context->refreshing) return NULL; if (!context->refreshed) { - ctxTokenNew (context->session); + afb_session_new_token (context->session); context->refreshed = 1; } - return ctxClientGetToken(context->session); + return afb_session_token(context->session); } const char *afb_context_sent_uuid(struct afb_context *context) @@ -103,19 +103,19 @@ const char *afb_context_sent_uuid(struct afb_context *context) return NULL; if (!context->created) return NULL; - return ctxClientGetUuid(context->session); + return afb_session_uuid(context->session); } void *afb_context_get(struct afb_context *context) { assert(context->session != NULL); - return ctxClientValueGet(context->session, context->api_index); + return afb_session_get_value(context->session, context->api_index); } void afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*)) { assert(context->session != NULL); - return ctxClientValueSet(context->session, context->api_index, value, free_value); + return afb_session_set_value(context->session, context->api_index, value, free_value); } void afb_context_close(struct afb_context *context) diff --git a/src/afb-context.h b/src/afb-context.h index 35709e20..d65e6ffa 100644 --- a/src/afb-context.h +++ b/src/afb-context.h @@ -17,11 +17,11 @@ #pragma once -struct AFB_clientCtx; +struct afb_session; struct afb_context { - struct AFB_clientCtx *session; + struct afb_session *session; union { unsigned flags; struct { @@ -41,7 +41,7 @@ struct afb_context int api_index; }; -extern void afb_context_init(struct afb_context *context, struct AFB_clientCtx *session, const char *token); +extern void afb_context_init(struct afb_context *context, struct afb_session *session, const char *token); extern int afb_context_connect(struct afb_context *context, const char *uuid, const char *token); extern void afb_context_disconnect(struct afb_context *context); extern const char *afb_context_sent_token(struct afb_context *context); diff --git a/src/afb-evt.h b/src/afb-evt.h index bd765b8c..52b40ab1 100644 --- a/src/afb-evt.h +++ b/src/afb-evt.h @@ -18,7 +18,7 @@ #pragma once struct afb_event; -struct AFB_clientCtx; +struct afb_session; struct afb_evt_listener; diff --git a/src/afb-hook.c b/src/afb-hook.c index f7d3e5b4..d5c534d0 100644 --- a/src/afb-hook.c +++ b/src/afb-hook.c @@ -28,7 +28,7 @@ #include "afb-context.h" #include "afb-hook.h" -#include "session.h" +#include "afb-session.h" #include "verbose.h" /* @@ -39,7 +39,7 @@ struct afb_hook { unsigned refcount; /* reference count */ char *api; /* api hooked or NULL for any */ char *verb; /* verb hooked or NULL for any */ - struct AFB_clientCtx *session; /* session hooked or NULL if any */ + struct afb_session *session; /* session hooked or NULL if any */ unsigned flags; /* hook flags */ struct afb_hook_req_itf *reqitf; /* interface of hook */ void *closure; /* closure for callbacks */ @@ -526,7 +526,7 @@ struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context return req; } -struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct AFB_clientCtx *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure) +struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct afb_session *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure) { struct afb_hook *hook; @@ -536,13 +536,13 @@ struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct A hook->api = api ? strdup(api) : NULL; hook->verb = verb ? strdup(verb) : NULL; - hook->session = session ? ctxClientAddRef(session) : NULL; + hook->session = session ? afb_session_addref(session) : NULL; if ((api && !hook->api) || (verb && !hook->verb)) { free(hook->api); free(hook->verb); if (hook->session) - ctxClientUnref(hook->session); + afb_session_unref(hook->session); free(hook); return NULL; } @@ -577,7 +577,7 @@ void afb_hook_unref(struct afb_hook *hook) free(hook->api); free(hook->verb); if (hook->session) - ctxClientUnref(hook->session); + afb_session_unref(hook->session); free(hook); } } diff --git a/src/afb-hook.h b/src/afb-hook.h index ae6ef832..2ad01b85 100644 --- a/src/afb-hook.h +++ b/src/afb-hook.h @@ -59,7 +59,7 @@ struct afb_context; struct json_object; struct afb_arg; struct afb_event; -struct AFB_clientCtx; +struct afb_session; struct afb_hook; struct afb_hook_req; @@ -90,7 +90,7 @@ struct afb_hook_req_itf { extern struct afb_req afb_hook_req_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb); -extern struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct AFB_clientCtx *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure); +extern struct afb_hook *afb_hook_req_create(const char *api, const char *verb, struct afb_session *session, unsigned flags, struct afb_hook_req_itf *itf, void *closure); extern struct afb_hook *afb_hook_addref(struct afb_hook *spec); extern void afb_hook_unref(struct afb_hook *spec); diff --git a/src/afb-hreq.c b/src/afb-hreq.c index b0f1172e..b2180458 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -38,7 +38,7 @@ #include "afb-context.h" #include "afb-hreq.h" #include "afb-subcall.h" -#include "session.h" +#include "afb-session.h" #include "verbose.h" #include "locale-root.h" diff --git a/src/afb-hreq.h b/src/afb-hreq.h index 72cefcf1..f07f2fa6 100644 --- a/src/afb-hreq.h +++ b/src/afb-hreq.h @@ -17,7 +17,7 @@ #pragma once -struct AFB_clientCtx; +struct afb_session; struct json_object; struct hreq_data; struct afb_hsrv; diff --git a/src/afb-hswitch.c b/src/afb-hswitch.c index 90dc2ffa..9c929e83 100644 --- a/src/afb-hswitch.c +++ b/src/afb-hswitch.c @@ -27,7 +27,7 @@ #include "afb-context.h" #include "afb-hreq.h" #include "afb-apis.h" -#include "session.h" +#include "afb-session.h" #include "afb-websock.h" int afb_hswitch_apis(struct afb_hreq *hreq, void *data) diff --git a/src/afb-session.c b/src/afb-session.c new file mode 100644 index 00000000..db81457c --- /dev/null +++ b/src/afb-session.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 2015, 2016, 2017 "IoT.bzh" + * Author "Fulup Ar Foll" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE +#include <stdio.h> +#include <time.h> +#include <pthread.h> +#include <stdlib.h> +#include <string.h> +#include <uuid/uuid.h> +#include <assert.h> +#include <errno.h> + +#include <json-c/json.h> + +#include "afb-session.h" +#include "verbose.h" + +#define NOW (time(NULL)) + +struct value +{ + void *value; + void (*freecb)(void*); +}; + +struct cookie +{ + struct cookie *next; + const void *key; + void *value; + void (*freecb)(void*); +}; + +struct afb_session +{ + 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 value *values; + struct cookie *cookies; +}; + +// Session UUID are store in a simple array [for 10 sessions this should be enough] +static struct { + pthread_mutex_t mutex; // declare a mutex to protect hash table + struct afb_session **store; // sessions store + int count; // current number of sessions + int max; + int timeout; + int apicount; + char initok[37]; +} sessions; + +/* generate a uuid */ +static void new_uuid(char uuid[37]) +{ + uuid_t newuuid; + uuid_generate(newuuid); + uuid_unparse_lower(newuuid, uuid); +} + +// Free context [XXXX Should be protected again memory abort XXXX] +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); + + // 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; + } +} + +// 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) +{ + // 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); + else if (strlen(initok) < sizeof(sessions.store[0]->token)) + strcpy(sessions.initok, initok); + else { + ERROR("initial token '%s' too long (max length 36)", initok); + exit(1); + } +} + +static struct afb_session *search (const char* uuid) +{ + int idx; + struct afb_session *session; + + assert (uuid != NULL); + + pthread_mutex_lock(&sessions.mutex); + + for (idx=0; idx < sessions.max; idx++) { + session = sessions.store[idx]; + if (session && (0 == strcmp (uuid, session->uuid))) + goto found; + } + session = NULL; + +found: + pthread_mutex_unlock(&sessions.mutex); + return session; +} + +static int destroy (struct afb_session *session) +{ + int idx; + int status; + + assert (session != NULL); + + pthread_mutex_lock(&sessions.mutex); + + for (idx=0; idx < sessions.max; idx++) { + if (sessions.store[idx] == session) { + sessions.store[idx] = NULL; + sessions.count--; + status = 1; + goto deleted; + } + } + status = 0; +deleted: + pthread_mutex_unlock(&sessions.mutex); + return status; +} + +static int add (struct afb_session *session) +{ + int idx; + int status; + + assert (session != NULL); + + pthread_mutex_lock(&sessions.mutex); + + for (idx=0; idx < sessions.max; idx++) { + if (NULL == sessions.store[idx]) { + sessions.store[idx] = session; + sessions.count++; + status = 1; + goto added; + } + } + status = 0; +added: + pthread_mutex_unlock(&sessions.mutex); + return status; +} + +// Check if context timeout or not +static int is_expired (struct afb_session *ctx, time_t now) +{ + assert (ctx != NULL); + return ctx->expiration < now; +} + +// Check if context is active or not +static int is_active (struct afb_session *ctx, time_t now) +{ + assert (ctx != NULL); + return ctx->uuid[0] != 0 && ctx->expiration >= now; +} + +// Loop on every entry and remove old context sessions.hash +static void cleanup (time_t now) +{ + struct afb_session *ctx; + long idx; + + // Loop on Sessions Table and remove anything that is older than timeout + for (idx=0; idx < sessions.max; idx++) { + ctx = sessions.store[idx]; + if (ctx != NULL && is_expired(ctx, now)) { + afb_session_close (ctx); + } + } +} + +static struct afb_session *make_session (const char *uuid, int timeout, time_t now) +{ + struct afb_session *session; + + /* allocates a new one */ + session = calloc(1, sizeof(struct afb_session) + ((unsigned)sessions.apicount * sizeof(*session->values))); + if (session == NULL) { + errno = ENOMEM; + goto error; + } + session->values = (void*)(session + 1); + + /* generate the uuid */ + if (uuid == NULL) { + new_uuid(session->uuid); + } else { + if (strlen(uuid) >= sizeof session->uuid) { + errno = EINVAL; + goto error2; + } + strcpy(session->uuid, uuid); + } + + /* init the token */ + strcpy(session->token, sessions.initok); + session->timeout = timeout; + if (timeout != 0) + session->expiration = now + timeout; + else { + session->expiration = (time_t)(~(time_t)0); + if (session->expiration < 0) + session->expiration = (time_t)(((unsigned long long)session->expiration) >> 1); + } + if (!add (session)) { + errno = ENOMEM; + goto error2; + } + + session->access = now; + session->refcount = 1; + return session; + +error2: + free(session); +error: + return NULL; +} + +struct afb_session *afb_session_create (const char *uuid, int timeout) +{ + time_t now; + + /* cleaning */ + 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); +} + +// This function will return exiting session or newly created session +struct afb_session *afb_session_get (const char *uuid, int *created) +{ + struct afb_session *session; + time_t now; + + /* cleaning */ + now = NOW; + cleanup (now); + + /* search for an existing one not too old */ + if (uuid != NULL) { + session = search(uuid); + if (session != NULL) { + *created = 0; + session->access = now; + session->refcount++; + return session; + } + } + + *created = 1; + return make_session(uuid, sessions.timeout, now); +} + +struct afb_session *afb_session_addref(struct afb_session *session) +{ + if (session != NULL) + session->refcount++; + return session; +} + +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); + } + } +} + +// Free Client Session Context +void afb_session_close (struct afb_session *session) +{ + assert(session != NULL); + if (session->uuid[0] != 0) { + session->uuid[0] = 0; + free_data (session); + if (session->refcount == 0) { + destroy (session); + free(session); + } + } +} + +// Sample Generic Ping Debug API +int afb_session_check_token (struct afb_session *session, const char *token) +{ + assert(session != NULL); + assert(token != NULL); + + // compare current token with previous one + if (!is_active (session, NOW)) + return 0; + + if (session->token[0] && strcmp (token, session->token) != 0) + return 0; + + return 1; +} + +// generate a new token and update client context +void afb_session_new_token (struct afb_session *session) +{ + assert(session != NULL); + + // Old token was valid let's regenerate a new one + new_uuid(session->token); + + // keep track of time for session timeout and further clean up + if (session->timeout != 0) + session->expiration = NOW + session->timeout; +} + +const char *afb_session_uuid (struct afb_session *session) +{ + assert(session != NULL); + return session->uuid; +} + +const char *afb_session_token (struct afb_session *session) +{ + assert(session != NULL); + return session->token; +} + +unsigned afb_session_get_LOA (struct afb_session *session) +{ + assert(session != NULL); + return session->loa; +} + +void afb_session_set_LOA (struct afb_session *session, unsigned loa) +{ + assert(session != NULL); + 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; + + cookie = session->cookies; + 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*)) +{ + struct cookie *cookie; + + /* search for a replacement */ + cookie = session->cookies; + while(cookie != NULL) { + if (cookie->key == key) { + if (cookie->value != NULL && cookie->value != value && cookie->freecb != NULL) + cookie->freecb(cookie->value); + cookie->value = value; + cookie->freecb = freecb; + return 0; + } + cookie = cookie->next; + } + + /* allocates */ + cookie = malloc(sizeof *cookie); + if (cookie == NULL) { + errno = ENOMEM; + return -1; + } + + cookie->key = key; + cookie->value = value; + cookie->freecb = freecb; + cookie->next = session->cookies; + session->cookies = cookie; + return 0; +} + diff --git a/src/afb-session.h b/src/afb-session.h new file mode 100644 index 00000000..7b3a7101 --- /dev/null +++ b/src/afb-session.h @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +struct json_object; +struct afb_session; + +extern void afb_session_init(int max_session_count, int timeout, const char *initok, int context_count); + +extern struct afb_session *afb_session_create (const char *uuid, int timeout); +extern struct afb_session *afb_session_get (const char *uuid, int *created); +extern const char *afb_session_uuid (struct afb_session *session); + +extern struct afb_session *afb_session_addref(struct afb_session *session); +extern void afb_session_unref(struct afb_session *session); + +extern void afb_session_close(struct afb_session *session); + +extern int afb_session_check_token(struct afb_session *session, const char *token); +extern void afb_session_new_token(struct afb_session *session); +extern const char *afb_session_token(struct afb_session *session); + +extern unsigned afb_session_get_LOA(struct afb_session *session); +extern void afb_session_set_LOA (struct afb_session *session, unsigned loa); + +extern void *afb_session_get_value(struct afb_session *session, int index); +extern void afb_session_set_value(struct afb_session *session, int index, void *value, void (*freecb)(void*)); + +extern void *afb_session_get_cookie(struct afb_session *session, const void *key); +extern int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)); + diff --git a/src/afb-svc.c b/src/afb-svc.c index 4038218c..c52ad654 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -24,7 +24,7 @@ #include <afb/afb-req-itf.h> #include <afb/afb-service-itf.h> -#include "session.h" +#include "afb-session.h" #include "afb-context.h" #include "afb-evt.h" #include "afb-subcall.h" @@ -36,7 +36,7 @@ struct afb_svc { /* session of the service */ - struct AFB_clientCtx *session; + struct afb_session *session; /* event listener of the service or NULL */ struct afb_evt_listener *listener; @@ -100,8 +100,8 @@ const struct afb_req_itf afb_svc_req_itf = { .subcall = (void*)svcreq_subcall }; -/* the common session for services sahring their session */ -static struct AFB_clientCtx *common_session; +/* the common session for services sharing their session */ +static struct afb_session *common_session; /* * Creates a new service @@ -120,14 +120,14 @@ struct afb_svc *afb_svc_create(int share_session, int (*init)(struct afb_service if (share_session) { /* session shared with other svcs */ if (common_session == NULL) { - common_session = ctxClientCreate (NULL, 0); + common_session = afb_session_create (NULL, 0); if (common_session == NULL) goto error2; } - svc->session = ctxClientAddRef(common_session); + svc->session = afb_session_addref(common_session); } else { /* session dedicated to the svc */ - svc->session = ctxClientCreate (NULL, 0); + svc->session = afb_session_create (NULL, 0); if (svc->session == NULL) goto error2; } @@ -153,7 +153,7 @@ error4: if (svc->listener != NULL) afb_evt_listener_unref(svc->listener); error3: - ctxClientUnref(svc->session); + afb_session_unref(svc->session); error2: free(svc); error: diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index ce0ae29f..f383868a 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -31,7 +31,7 @@ #include "afb-ws-json1.h" #include "afb-common.h" #include "afb-msg-json.h" -#include "session.h" +#include "afb-session.h" #include "afb-apis.h" #include "afb-context.h" #include "afb-evt.h" @@ -66,7 +66,7 @@ struct afb_ws_json1 int refcount; void (*cleanup)(void*); void *cleanup_closure; - struct AFB_clientCtx *session; + struct afb_session *session; struct afb_evt_listener *listener; struct afb_wsj1 *wsj1; int new_session; @@ -139,7 +139,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, vo result->refcount = 1; result->cleanup = cleanup; result->cleanup_closure = cleanup_closure; - result->session = ctxClientAddRef(context->session); + result->session = afb_session_addref(context->session); result->new_session = context->created != 0; if (result->session == NULL) goto error2; @@ -157,7 +157,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, vo error4: afb_wsj1_unref(result->wsj1); error3: - ctxClientUnref(result->session); + afb_session_unref(result->session); error2: free(result); error: @@ -178,7 +178,7 @@ static void aws_unref(struct afb_ws_json1 *ws) afb_wsj1_unref(ws->wsj1); if (ws->cleanup != NULL) ws->cleanup(ws->cleanup_closure); - ctxClientUnref(ws->session); + afb_session_unref(ws->session); free(ws); } } @@ -40,7 +40,7 @@ #include "afb-hreq.h" #include "afb-sig-handler.h" #include "afb-thread.h" -#include "session.h" +#include "afb-session.h" #include "verbose.h" #include "afb-common.h" #include "afb-hook.h" @@ -662,7 +662,7 @@ int main(int argc, char *argv[]) { start_items(config->items); config->items = NULL; - ctxStoreInit(config->nbSessionMax, config->cntxTimeout, config->token, afb_apis_count()); + afb_session_init(config->nbSessionMax, config->cntxTimeout, config->token, afb_apis_count()); if (!afb_hreq_init_cookie(config->httpdPort, config->rootapi, DEFLT_CNTX_TIMEOUT)) { ERROR("initialisation of cookies failed"); exit (1); diff --git a/src/session.c b/src/session.c deleted file mode 100644 index 7e1e4c68..00000000 --- a/src/session.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (C) 2015, 2016, 2017 "IoT.bzh" - * Author "Fulup Ar Foll" - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE -#include <stdio.h> -#include <time.h> -#include <pthread.h> -#include <stdlib.h> -#include <string.h> -#include <uuid/uuid.h> -#include <assert.h> -#include <errno.h> - -#include <json-c/json.h> - -#include "session.h" -#include "verbose.h" - -#define NOW (time(NULL)) - -struct client_value -{ - void *value; - 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 struct { - pthread_mutex_t mutex; // declare a mutex to protect hash table - struct AFB_clientCtx **store; // sessions store - int count; // current number of sessions - int max; - int timeout; - int apicount; - char initok[37]; -} sessions; - -/* generate a uuid */ -static void new_uuid(char uuid[37]) -{ - uuid_t newuuid; - uuid_generate(newuuid); - uuid_unparse_lower(newuuid, uuid); -} - -// Free context [XXXX Should be protected again memory abort XXXX] -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 -void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count) -{ - // let's create as store as hashtable does not have any - sessions.store = calloc (1 + (unsigned)max_session_count, sizeof(struct AFB_clientCtx)); - 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); - else if (strlen(initok) < sizeof(sessions.store[0]->token)) - strcpy(sessions.initok, initok); - else { - ERROR("initial token '%s' too long (max length 36)", initok); - exit(1); - } -} - -static struct AFB_clientCtx *ctxStoreSearch (const char* uuid) -{ - int idx; - struct AFB_clientCtx *client; - - assert (uuid != NULL); - - pthread_mutex_lock(&sessions.mutex); - - for (idx=0; idx < sessions.max; idx++) { - client = sessions.store[idx]; - if (client && (0 == strcmp (uuid, client->uuid))) - goto found; - } - client = NULL; - -found: - pthread_mutex_unlock(&sessions.mutex); - return client; -} - -static int ctxStoreDel (struct AFB_clientCtx *client) -{ - int idx; - int status; - - assert (client != NULL); - - pthread_mutex_lock(&sessions.mutex); - - for (idx=0; idx < sessions.max; idx++) { - if (sessions.store[idx] == client) { - sessions.store[idx] = NULL; - sessions.count--; - status = 1; - goto deleted; - } - } - status = 0; -deleted: - pthread_mutex_unlock(&sessions.mutex); - return status; -} - -static int ctxStoreAdd (struct AFB_clientCtx *client) -{ - int idx; - int status; - - assert (client != NULL); - - pthread_mutex_lock(&sessions.mutex); - - for (idx=0; idx < sessions.max; idx++) { - if (NULL == sessions.store[idx]) { - sessions.store[idx] = client; - sessions.count++; - status = 1; - goto added; - } - } - status = 0; -added: - pthread_mutex_unlock(&sessions.mutex); - return status; -} - -// Check if context timeout or not -static int ctxStoreTooOld (struct AFB_clientCtx *ctx, time_t now) -{ - assert (ctx != NULL); - return ctx->expiration < now; -} - -// Check if context is active or not -static int ctxIsActive (struct AFB_clientCtx *ctx, time_t now) -{ - assert (ctx != NULL); - return ctx->uuid[0] != 0 && ctx->expiration >= now; -} - -// Loop on every entry and remove old context sessions.hash -static void ctxStoreCleanUp (time_t now) -{ - struct AFB_clientCtx *ctx; - long idx; - - // Loop on Sessions Table and remove anything that is older than timeout - for (idx=0; idx < sessions.max; idx++) { - ctx = sessions.store[idx]; - if (ctx != NULL && ctxStoreTooOld(ctx, now)) { - ctxClientClose (ctx); - } - } -} - -static struct AFB_clientCtx *new_context (const char *uuid, int timeout, time_t now) -{ - struct AFB_clientCtx *clientCtx; - - /* allocates a new one */ - clientCtx = calloc(1, sizeof(struct AFB_clientCtx) + ((unsigned)sessions.apicount * sizeof(*clientCtx->values))); - if (clientCtx == NULL) { - errno = ENOMEM; - goto error; - } - clientCtx->values = (void*)(clientCtx + 1); - - /* generate the uuid */ - 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->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; - } - - clientCtx->access = now; - clientCtx->refcount = 1; - return clientCtx; - -error2: - free(clientCtx); -error: - 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) - clientCtx->refcount++; - return clientCtx; -} - -void ctxClientUnref(struct AFB_clientCtx *clientCtx) -{ - if (clientCtx != NULL) { - assert(clientCtx->refcount != 0); - --clientCtx->refcount; - if (clientCtx->refcount == 0 && clientCtx->uuid[0] == 0) { - ctxStoreDel (clientCtx); - free(clientCtx); - } - } -} - -// Free Client Session Context -void ctxClientClose (struct AFB_clientCtx *clientCtx) -{ - assert(clientCtx != NULL); - if (clientCtx->uuid[0] != 0) { - clientCtx->uuid[0] = 0; - ctxUuidFreeCB (clientCtx); - if (clientCtx->refcount == 0) { - ctxStoreDel (clientCtx); - free(clientCtx); - } - } -} - -// Sample Generic Ping Debug API -int ctxTokenCheck (struct AFB_clientCtx *clientCtx, const char *token) -{ - assert(clientCtx != NULL); - assert(token != NULL); - - // compare current token with previous one - if (!ctxIsActive (clientCtx, NOW)) - return 0; - - if (clientCtx->token[0] && strcmp (token, clientCtx->token) != 0) - return 0; - - return 1; -} - -// generate a new token and update client context -void ctxTokenNew (struct AFB_clientCtx *clientCtx) -{ - assert(clientCtx != NULL); - - // Old token was valid let's regenerate a new one - new_uuid(clientCtx->token); - - // keep track of time for session timeout and further clean up - if (clientCtx->timeout != 0) - clientCtx->expiration = NOW + clientCtx->timeout; -} - -const char *ctxClientGetUuid (struct AFB_clientCtx *clientCtx) -{ - assert(clientCtx != NULL); - return clientCtx->uuid; -} - -const char *ctxClientGetToken (struct AFB_clientCtx *clientCtx) -{ - assert(clientCtx != NULL); - return clientCtx->token; -} - -unsigned ctxClientGetLOA (struct AFB_clientCtx *clientCtx) -{ - assert(clientCtx != NULL); - return clientCtx->loa; -} - -void ctxClientSetLOA (struct AFB_clientCtx *clientCtx, unsigned loa) -{ - assert(clientCtx != NULL); - clientCtx->loa = loa; -} - -void *ctxClientValueGet(struct AFB_clientCtx *clientCtx, int index) -{ - assert(clientCtx != NULL); - assert(index >= 0); - assert(index < sessions.apicount); - return clientCtx->values[index].value; -} - -void ctxClientValueSet(struct AFB_clientCtx *clientCtx, int index, void *value, void (*free_value)(void*)) -{ - struct client_value prev; - assert(clientCtx != NULL); - assert(index >= 0); - assert(index < sessions.apicount); - prev = clientCtx->values[index]; - clientCtx->values[index] = (struct client_value){.value = value, .free_value = free_value}; - 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; -} - diff --git a/src/session.h b/src/session.h deleted file mode 100644 index 23993248..00000000 --- a/src/session.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (C) 2016, 2017 "IoT.bzh" - * Author: José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -struct json_object; -struct AFB_clientCtx; - -extern void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count); - -extern struct AFB_clientCtx *ctxClientCreate (const char *uuid, int timeout); -extern struct AFB_clientCtx *ctxClientGetSession (const char *uuid, int *created); -extern struct AFB_clientCtx *ctxClientAddRef(struct AFB_clientCtx *clientCtx); -extern void ctxClientUnref(struct AFB_clientCtx *clientCtx); -extern void ctxClientClose (struct AFB_clientCtx *clientCtx); - -extern int ctxTokenCheck (struct AFB_clientCtx *clientCtx, const char *token); -extern void ctxTokenNew (struct AFB_clientCtx *clientCtx); - -extern const char *ctxClientGetUuid (struct AFB_clientCtx *clientCtx); -extern const char *ctxClientGetToken (struct AFB_clientCtx *clientCtx); -extern unsigned ctxClientGetLOA (struct AFB_clientCtx *clientCtx); -extern void ctxClientSetLOA (struct AFB_clientCtx *clientCtx, unsigned loa); - -extern void *ctxClientValueGet(struct AFB_clientCtx *clientCtx, int index); -extern void ctxClientValueSet(struct AFB_clientCtx *clientCtx, int index, void *value, void (*free_value)(void*)); - -extern void *ctxClientCookieGet(struct AFB_clientCtx *clientCtx, const void *key); -extern int ctxClientCookieSet(struct AFB_clientCtx *clientCtx, const void *key, void *value, void (*free_value)(void*)); - |