From ce8de8236b96dc771d3af3094e04e797e75767af Mon Sep 17 00:00:00 2001 From: José Bollo Date: Fri, 5 May 2017 12:04:25 +0200 Subject: session: start to manage concurrency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Change-Id: I5895fa14fcb496e71fba600994e7e454cf1d110b Signed-off-by: José Bollo --- bindings/samples/DemoContext.c | 8 +++ src/afb-context.c | 6 +++ src/afb-context.h | 1 + src/afb-session.c | 117 +++++++++++++++++++++++++++++------------ src/afb-session.h | 1 + 5 files changed, 99 insertions(+), 34 deletions(-) diff --git a/bindings/samples/DemoContext.c b/bindings/samples/DemoContext.c index 66dc6ccf..26677949 100644 --- a/bindings/samples/DemoContext.c +++ b/bindings/samples/DemoContext.c @@ -67,6 +67,10 @@ static void myAction (struct afb_req request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); + if (!ctx) { + afb_req_fail(request, "invalid-state", "Can't perform action"); + return; + } // store something in our plugin private client context ctx->count++; afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Check=[%d]\n", ctx->abcd, ctx->count); @@ -80,6 +84,10 @@ static void myClose (struct afb_req request) { MyClientContextT *ctx = (MyClientContextT*) afb_req_context_get(request); + if (!ctx) { + afb_req_success(request, NULL, NULL); + return; + } // store something in our plugin private client context ctx->count++; afb_req_success_f(request, NULL, "SUCCESS: plugin [%s] Close=[%d]\n", ctx->abcd, ctx->count); diff --git a/src/afb-context.c b/src/afb-context.c index 9f5ddd3c..83ce5733 100644 --- a/src/afb-context.c +++ b/src/afb-context.c @@ -109,6 +109,12 @@ const char *afb_context_sent_uuid(struct afb_context *context) return afb_session_uuid(context->session); } +void *afb_context_data(struct afb_context *context, void *(*make_value)(void), void (*free_value)(void*)) +{ + assert(context->session != NULL); + return afb_session_cookie(context->session, context->api_key, make_value, free_value); +} + void *afb_context_get(struct afb_context *context) { assert(context->session != NULL); diff --git a/src/afb-context.h b/src/afb-context.h index ceda5d24..55605858 100644 --- a/src/afb-context.h +++ b/src/afb-context.h @@ -47,6 +47,7 @@ extern const char *afb_context_sent_uuid(struct afb_context *context); extern void *afb_context_get(struct afb_context *context); extern void afb_context_set(struct afb_context *context, void *value, void (*free_value)(void*)); +extern void *afb_context_data(struct afb_context *context, void *(*make_value)(void), void (*free_value)(void*)); extern void afb_context_close(struct afb_context *context); extern void afb_context_refresh(struct afb_context *context); diff --git a/src/afb-session.c b/src/afb-session.c index 17fddd5c..523cbf04 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -50,6 +50,7 @@ struct afb_session int timeout; time_t expiration; // expiration time of the token time_t access; + pthread_mutex_t mutex; char uuid[37]; // long term authentication of remote client char token[37]; // short term authentication of remote client struct cookie *cookies[COOKEYCOUNT]; @@ -85,6 +86,16 @@ static void new_uuid(char uuid[37]) uuid_unparse_lower(newuuid, uuid); } +static inline void lock(struct afb_session *session) +{ + pthread_mutex_lock(&session->mutex); +} + +static inline void unlock(struct afb_session *session) +{ + pthread_mutex_unlock(&session->mutex); +} + // Free context [XXXX Should be protected again memory abort XXXX] static void free_data (struct afb_session *session) { @@ -110,6 +121,7 @@ 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)); + pthread_mutex_init(&sessions.mutex, NULL); sessions.max = max_session_count; sessions.timeout = timeout; if (initok == NULL) @@ -224,11 +236,12 @@ 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)); + session = calloc(1, sizeof *session); if (session == NULL) { errno = ENOMEM; goto error; } + pthread_mutex_init(&session->mutex, NULL); /* generate the uuid */ if (uuid == NULL) { @@ -322,6 +335,7 @@ void afb_session_unref(struct afb_session *session) --session->refcount; if (session->refcount == 0 && session->uuid[0] == 0) { destroy (session); + pthread_mutex_destroy(&session->mutex); free(session); } } @@ -382,52 +396,87 @@ const char *afb_session_token (struct afb_session *session) return session->token; } -void *afb_session_get_cookie(struct afb_session *session, const void *key) +static struct cookie *cookie_search(struct afb_session *session, const void *key, int *idx) { struct cookie *cookie; - int idx; - idx = cookeyidx(key); - cookie = session->cookies[idx]; - while(cookie != NULL) { - if (cookie->key == key) - return cookie->value; + cookie = session->cookies[*idx = cookeyidx(key)]; + while(cookie != NULL && cookie->key != key) cookie = cookie->next; - } - return NULL; + return cookie; } -int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)) +static struct cookie *cookie_add(struct afb_session *session, int idx, const void *key, void *value, void (*freecb)(void*)) { struct cookie *cookie; + + cookie = malloc(sizeof *cookie); + if (!cookie) + errno = ENOMEM; + else { + cookie->key = key; + cookie->value = value; + cookie->freecb = freecb; + cookie->next = session->cookies[idx]; + session->cookies[idx] = cookie; + } + return cookie; +} + +void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void), void (*freecb)(void*)) +{ int idx; + void *value; + struct cookie *cookie; - /* search for a replacement */ - idx = cookeyidx(key); - cookie = session->cookies[idx]; - while(cookie != NULL) { - if (cookie->key == key) { - if (cookie->value != value && cookie->freecb) - cookie->freecb(cookie->value); - cookie->value = value; - cookie->freecb = freecb; - return 0; + lock(session); + cookie = cookie_search(session, key, &idx); + if (cookie) + value = cookie->value; + else { + value = makecb ? makecb() : NULL; + if (makecb || freecb) { + cookie = cookie_add(session, idx, key, value, freecb); + if (!cookie) { + if (makecb && freecb) + free(value); + value = NULL; + } } - cookie = cookie->next; } + unlock(session); + return value; +} - /* allocates */ - cookie = malloc(sizeof *cookie); - if (cookie == NULL) { - errno = ENOMEM; - return -1; - } +void *afb_session_get_cookie(struct afb_session *session, const void *key) +{ + int idx; + void *value; + struct cookie *cookie; + + lock(session); + cookie = cookie_search(session, key, &idx); + value = cookie ? cookie->value : NULL; + unlock(session); + return value; +} + +int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)) +{ + int idx; + struct cookie *cookie; - cookie->key = key; - cookie->value = value; - cookie->freecb = freecb; - cookie->next = session->cookies[idx]; - session->cookies[idx] = cookie; - return 0; + lock(session); + cookie = cookie_search(session, key, &idx); + if (!cookie) + cookie = cookie_add(session, idx, key, value, freecb); + else { + if (cookie->value != value && cookie->freecb) + cookie->freecb(cookie->value); + cookie->value = value; + cookie->freecb = freecb; + } + unlock(session); + return -!cookie; } diff --git a/src/afb-session.h b/src/afb-session.h index afff6714..e79d0376 100644 --- a/src/afb-session.h +++ b/src/afb-session.h @@ -35,5 +35,6 @@ extern void afb_session_new_token(struct afb_session *session); extern const char *afb_session_token(struct afb_session *session); extern void *afb_session_get_cookie(struct afb_session *session, const void *key); +extern void *afb_session_cookie(struct afb_session *session, const void *key, void *(*makecb)(void), void (*freecb)(void*)); extern int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)); -- cgit 1.2.3-korg