Introduce object for tokens 67/22967/2 8.99.1 icefish/8.99.1 icefish_8.99.1
authorJose Bollo <jose.bollo@iot.bzh>
Mon, 28 Oct 2019 17:02:36 +0000 (18:02 +0100)
committerJose Bollo <jose.bollo@iot.bzh>
Wed, 20 Nov 2019 08:30:07 +0000 (09:30 +0100)
For further optimizations, the token is represented
by a specific structure.

Bug-AGL: SPEC-2968

Change-Id: I3d46a12c8c16809c6cc1d543fa2e6309927ed84d
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
src/CMakeLists.txt
src/afb-context.c
src/afb-context.h
src/afb-export.c
src/afb-session.c
src/afb-stub-ws.c
src/afb-token.c [new file with mode: 0644]
src/afb-token.h [new file with mode: 0644]
src/afb-ws-json1.c
src/main-afb-daemon.c

index abc81c8..0d5e712 100644 (file)
@@ -104,6 +104,7 @@ SET(AFB_LIB_SOURCES
        afb-socket.c
        afb-stub-ws.c
        afb-supervision.c
+       afb-token.c
        afb-trace.c
        afb-websock.c
        afb-ws-client.c
index fd39493..6057e69 100644 (file)
@@ -50,12 +50,19 @@ void afb_context_init(struct afb_context *context, struct afb_session *session,
        init_context(context, afb_session_addref(session), token);
 }
 
+void afb_context_init_validated(struct afb_context *context, struct afb_session *session)
+{
+       afb_context_init(context, session, NULL);
+       context->validated = 1;
+}
+
 void afb_context_subinit(struct afb_context *context, struct afb_context *super)
 {
        context->session = super->session;
        context->flags = 0;
        context->super = super;
        context->api_key = NULL;
+       context->token = NULL;
        context->validated = super->validated;
 }
 
@@ -75,6 +82,14 @@ int afb_context_connect(struct afb_context *context, const char *uuid, const cha
        return 0;
 }
 
+int afb_context_connect_validated(struct afb_context *context, const char *uuid)
+{
+       int rc = afb_context_connect(context, uuid, NULL);
+       if (!rc)
+               context->validated = 1;
+       return rc;
+}
+
 void afb_context_disconnect(struct afb_context *context)
 {
        if (context->session && !context->super) {
index bec1d35..21af4b2 100644 (file)
 #pragma once
 
 struct afb_session;
+struct afb_token;
 
 struct afb_context
 {
        struct afb_session *session;
+       struct afb_token *token;
        const void *api_key;
        struct afb_context *super;
        union {
@@ -39,8 +41,10 @@ struct afb_context
 };
 
 extern void afb_context_init(struct afb_context *context, struct afb_session *session, const char *token);
+extern void afb_context_init_validated(struct afb_context *context, struct afb_session *session);
 extern void afb_context_subinit(struct afb_context *context, struct afb_context *super);
 extern int afb_context_connect(struct afb_context *context, const char *uuid, const char *token);
+extern int afb_context_connect_validated(struct afb_context *context, const char *uuid);
 extern void afb_context_disconnect(struct afb_context *context);
 extern const char *afb_context_sent_token(struct afb_context *context);
 extern const char *afb_context_sent_uuid(struct afb_context *context);
index 38ef402..3cf1fc9 100644 (file)
@@ -1952,7 +1952,6 @@ void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq)
 
 void afb_export_context_init(struct afb_export *export, struct afb_context *context)
 {
-       afb_context_init(context, export->session, NULL);
-       context->validated = 1;
+       afb_context_init_validated(context, export->session);
 }
 
index 61aa3f6..fe5aa4a 100644 (file)
@@ -28,6 +28,7 @@
 
 #include "afb-session.h"
 #include "afb-hook.h"
+#include "afb-token.h"
 #include "verbose.h"
 #include "pearson.h"
 #include "uuid.h"
@@ -68,7 +69,7 @@ struct afb_session
        uint8_t autoclose: 1;   /**< close the session when unreferenced */
        uint8_t notinset: 1;    /**< session removed from the set of sessions */
        uuid_stringz_t uuid;    /**< long term authentication of remote client */
-       uuid_stringz_t token;   /**< short term authentication of remote client */
+       struct afb_token *token;/**< short term authentication of remote client */
 };
 
 /**
@@ -79,14 +80,14 @@ static struct {
        int max;                /**< maximum count of sessions */
        int timeout;            /**< common initial timeout */
        struct afb_session *heads[HEADCOUNT]; /**< sessions */
-       uuid_stringz_t initok;  /**< common initial token */
+       struct afb_token *initok;/**< common initial token */
        pthread_mutex_t mutex;  /**< declare a mutex to protect hash table */
 } sessions = {
        .count = 0,
        .max = 10,
        .timeout = 3600,
        .heads = { 0 },
-       .initok = { 0 },
+       .initok = 0,
        .mutex = PTHREAD_MUTEX_INITIALIZER
 };
 
@@ -203,6 +204,7 @@ static void session_destroy (struct afb_session *session)
        afb_hook_session_destroy(session);
 #endif
        pthread_mutex_destroy(&session->mutex);
+       afb_token_unref(session->token);
        free(session->lang);
        free(session);
 }
@@ -249,12 +251,13 @@ static struct afb_session *session_add(const char *uuid, int timeout, time_t now
        pthread_mutex_init(&session->mutex, NULL);
        session->refcount = 1;
        strcpy(session->uuid, uuid);
-       strcpy(session->token, sessions.initok);
+       session->token = afb_token_addref(sessions.initok);
        session->timeout = timeout;
        session_update_expiration(session, now);
 
        /* add */
        if (sessionset_add(session, hashidx)) {
+               afb_token_unref(session->token);
                free(session);
                return NULL;
        }
@@ -309,6 +312,9 @@ static time_t sessionset_cleanup (int force)
  */
 int afb_session_init (int max_session_count, int timeout, const char *initok)
 {
+       int rc;
+       uuid_stringz_t uuid;
+
        /* check parameters */
        if (initok && strlen(initok) >= sizeof sessions.initok) {
                ERROR("initial token '%s' too long (max length %d)",
@@ -322,10 +328,16 @@ int afb_session_init (int max_session_count, int timeout, const char *initok)
        sessionset_cleanup(1);
        sessions.max = max_session_count;
        sessions.timeout = timeout;
-       if (initok == NULL)
-               uuid_new_stringz(sessions.initok);
-       else
-               strcpy(sessions.initok, initok);
+       if (initok == NULL) {
+               uuid_new_stringz(uuid);
+               initok = uuid;
+       }
+       sessions.initok = 0;
+       if (*initok) {
+               rc = afb_token_get(&sessions.initok, initok);
+               if (rc < 0)
+                       return rc;
+       }
        sessionset_unlock();
        return 0;
 }
@@ -367,7 +379,7 @@ void afb_session_purge()
  */
 const char *afb_session_initial_token()
 {
-       return sessions.initok;
+       return sessions.initok ? afb_token_string(sessions.initok) : "";
 }
 
 /* Searchs the session of 'uuid' */
@@ -528,7 +540,7 @@ int afb_session_check_token (struct afb_session *session, const char *token)
        session_lock(session);
        r = !session->closed
          && session->expiration >= NOW
-         && !(session->token[0] && strcmp (token, session->token));
+         && !(session->token && strcmp(token, afb_session_token(session)));
        session_unlock(session);
        return r;
 }
@@ -536,12 +548,23 @@ 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)
 {
+       int rc;
+       uuid_stringz_t uuid;
+       struct afb_token *previous, *next;
        session_lock(session);
-       uuid_new_stringz(session->token);
-       session_update_expiration(session, NOW);
+       uuid_new_stringz(uuid);
+       rc = afb_token_get(&next, uuid);
+       if (rc < 0)
+               ERROR("can't renew token");
+       else {
+               previous = session->token;
+               session->token = next;
+               session_update_expiration(session, NOW);
 #if WITH_AFB_HOOK
-       afb_hook_session_renew(session);
+               afb_hook_session_renew(session);
 #endif
+               afb_token_unref(previous);
+       }
        session_unlock(session);
 }
 
@@ -554,7 +577,7 @@ const char *afb_session_uuid (struct afb_session *session)
 /* Returns the token of 'session' */
 const char *afb_session_token (struct afb_session *session)
 {
-       return session->token;
+       return afb_token_string(session->token);
 }
 
 /**
index 6a52f6f..3e9ede2 100644 (file)
@@ -523,9 +523,8 @@ static void server_on_call_cb(void *closure, struct afb_proto_ws_call *call, con
        wreq->call = call;
 
        /* init the context */
-       if (afb_context_connect(&wreq->xreq.context, sessionid, NULL) < 0)
+       if (afb_context_connect_validated(&wreq->xreq.context, sessionid) < 0)
                goto unconnected;
-       wreq->xreq.context.validated = 1;
        server_record_session(stubws, wreq->xreq.context.session);
        if (wreq->xreq.context.created)
                afb_session_set_autoclose(wreq->xreq.context.session, 1);
diff --git a/src/afb-token.c b/src/afb-token.c
new file mode 100644 (file)
index 0000000..b81a87d
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015-2019 "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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <errno.h>
+
+#include "afb-token.h"
+
+/**
+ * structure for recording a token
+ */
+struct afb_token
+{
+       /** link to the next token of the list */
+       struct afb_token *next;
+
+       /** reference of the token */
+       uint16_t refcount;
+
+       /** local numeric id of the token */
+       uint16_t id;
+
+       /** string value of the token */
+       char text[];
+};
+
+struct tokenset
+{
+       struct afb_token *first;
+       pthread_mutex_t mutex;
+       uint16_t idgen;
+};
+
+static struct tokenset tokenset = {
+       .first = 0,
+       .mutex = PTHREAD_MUTEX_INITIALIZER,
+       .idgen = 0
+};
+
+static struct afb_token *searchid(uint16_t id)
+{
+       struct afb_token *r = tokenset.first;
+       while (r && r->id != id)
+               r = r->next;
+       return r;
+}
+
+/**
+ * Get a token for the given value
+ *
+ * @param token address to return the pointer to the gotten token
+ * @param tokenstring string value of the token to get
+ * @return 0 in case of success or a -errno like negative code
+ */
+int afb_token_get(struct afb_token **token, const char *tokenstring)
+{
+       int rc;
+       struct afb_token *tok;
+       size_t length;
+
+       /* get length of the token string */
+       length =  + strlen(tokenstring);
+
+       /* concurrency */
+       pthread_mutex_lock(&tokenset.mutex);
+
+       /* search the token */
+       tok = tokenset.first;
+       while (tok && memcmp(tokenstring, tok->text, length))
+               tok = tok->next;
+
+       /* search done */
+       if (tok) {
+               /* found */
+               tok = afb_token_addref(tok);
+               rc = 0;
+       } else {
+               /* not found, create */
+               tok = malloc(length + sizeof *tok);
+               if (!tok)
+                       /* creation failed */
+                       rc = -ENOMEM;
+               else {
+                       while(!++tokenset.idgen || searchid(tokenset.idgen));
+                       tok->next = tokenset.first;
+                       tokenset.first = tok;
+                       tok->id = tokenset.idgen;
+                       tok->refcount = 1;
+                       memcpy(tok->text, tokenstring, length);
+                       rc = 0;
+               }
+       }
+       pthread_mutex_unlock(&tokenset.mutex);
+       *token = tok;
+       return rc;
+}
+
+/**
+ * Add a reference count to the given token
+ *
+ * @param token the token to reference
+ * @return the token with the reference added
+ */
+struct afb_token *afb_token_addref(struct afb_token *token)
+{
+       if (token)
+               __atomic_add_fetch(&token->refcount, 1, __ATOMIC_RELAXED);
+       return token;
+}
+
+/**
+ * Remove a reference to the given token and clean the memory if needed
+ *
+ * @param token the token that is unreferenced
+ */
+void afb_token_unref(struct afb_token *token)
+{
+       struct afb_token **pt;
+       if (token && !__atomic_sub_fetch(&token->refcount, 1, __ATOMIC_RELAXED)) {
+               pthread_mutex_lock(&tokenset.mutex);
+               pt = &tokenset.first;
+               while (*pt && *pt != token)
+               if (*pt)
+                       *pt = token->next;
+               pthread_mutex_unlock(&tokenset.mutex);
+               free(token);
+       }
+}
+
+/**
+ * Check whether the token is valid or not
+ *
+ * @param token the token to check
+ * @return a boolean value: 0 if not valid, 1 if valid
+ */
+int afb_token_check(struct afb_token *token)
+{
+       /* TODO */
+       return 1;
+}
+
+/**
+ * Get the string value of the token
+ *
+ * @param token the token whose string value is queried
+ * @return the string value of the token
+ */
+const char *afb_token_string(const struct afb_token *token)
+{
+       return token->text;
+}
+
+/**
+ * Get the "local" numeric id of the token
+ *
+ * @param token the token whose id is queried
+ * @return the numeric id of the token
+ */
+uint16_t afb_token_id(const struct afb_token *token)
+{
+       return token->id;
+}
diff --git a/src/afb-token.h b/src/afb-token.h
new file mode 100644 (file)
index 0000000..69b0fa0
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016-2019 "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 afb_token;
+
+extern int afb_token_get(struct afb_token **token, const char *tokenstring);
+extern struct afb_token *afb_token_addref(struct afb_token *token);
+extern void afb_token_unref(struct afb_token *token);
+
+extern int afb_token_check(struct afb_token *token);
+extern const char *afb_token_string(const struct afb_token *token);
+extern uint16_t afb_token_id(const struct afb_token *token);
index c799193..d0cca2b 100644 (file)
@@ -34,6 +34,7 @@
 #include "afb-xreq.h"
 #include "afb-context.h"
 #include "afb-evt.h"
+#include "afb-token.h"
 
 #include "systemd.h"
 #include "verbose.h"
@@ -62,6 +63,7 @@ struct afb_ws_json1
        void (*cleanup)(void*);
        void *cleanup_closure;
        struct afb_session *session;
+       struct afb_token *token;
        struct afb_evt_listener *listener;
        struct afb_wsj1 *wsj1;
        struct afb_cred *cred;
@@ -121,6 +123,7 @@ struct afb_ws_json1 *afb_ws_json1_create(struct fdev *fdev, struct afb_apiset *a
        result->cleanup = cleanup;
        result->cleanup_closure = cleanup_closure;
        result->session = afb_session_addref(context->session);
+       result->token = afb_token_addref(context->token);
        result->new_session = context->created != 0;
        if (result->session == NULL)
                goto error2;
@@ -141,6 +144,7 @@ error4:
        afb_wsj1_unref(result->wsj1);
 error3:
        afb_session_unref(result->session);
+       afb_token_unref(result->token);
 error2:
        free(result);
 error:
@@ -161,6 +165,7 @@ void afb_ws_json1_unref(struct afb_ws_json1 *ws)
                afb_wsj1_unref(ws->wsj1);
                if (ws->cleanup != NULL)
                        ws->cleanup(ws->cleanup_closure);
+               afb_token_unref(ws->token);
                afb_session_unref(ws->session);
                afb_cred_unref(ws->cred);
                afb_apiset_unref(ws->apiset);
index 3421be8..165d140 100644 (file)
@@ -659,8 +659,7 @@ static void startup_call_current(struct startup_req *sreq)
                json = strchr(verb, ':');
                if (json) {
                        afb_xreq_init(&sreq->xreq, &startup_xreq_itf);
-                       afb_context_init(&sreq->xreq.context, sreq->session, NULL);
-                       sreq->xreq.context.validated = 1;
+                       afb_context_init_validated(&sreq->xreq.context, sreq->session);
                        sreq->api = strndup(api, verb - api);
                        sreq->verb = strndup(verb + 1, json - verb - 1);
                        sreq->xreq.request.called_api = sreq->api;