aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/afb-plugin.h11
-rw-r--r--include/afb-req-itf.h68
-rw-r--r--plugins/afm-main-plugin/afm-main-plugin.c3
-rw-r--r--src/CMakeLists.txt20
-rw-r--r--src/afb-api-dbus.c511
-rw-r--r--src/afb-api-dbus.h25
-rw-r--r--src/afb-api-so.c45
-rw-r--r--src/afb-apis.c9
-rw-r--r--src/afb-apis.h8
-rw-r--r--src/afb-context.c122
-rw-r--r--src/afb-context.h53
-rw-r--r--src/afb-hreq.c131
-rw-r--r--src/afb-hreq.h12
-rw-r--r--src/afb-hsrv.c4
-rw-r--r--src/afb-hswitch.c17
-rw-r--r--src/afb-websock.c3
-rw-r--r--src/afb-ws-json.c98
-rw-r--r--src/main.c1
-rw-r--r--src/session.c195
-rw-r--r--src/session.h36
20 files changed, 1041 insertions, 331 deletions
diff --git a/include/afb-plugin.h b/include/afb-plugin.h
index ce78e840..63617cbe 100644
--- a/include/afb-plugin.h
+++ b/include/afb-plugin.h
@@ -31,11 +31,12 @@ enum AFB_pluginE
/* Enum for Session/Token/Authentication middleware */
enum AFB_sessionE
{
- AFB_SESSION_NONE,
- AFB_SESSION_CREATE,
- AFB_SESSION_CLOSE,
- AFB_SESSION_RENEW,
- AFB_SESSION_CHECK
+ AFB_SESSION_NONE = 0,
+ AFB_SESSION_CREATE = 1,
+ AFB_SESSION_CLOSE = 2,
+ AFB_SESSION_RENEW = 4,
+ AFB_SESSION_CHECK = 8,
+ AFB_SESSION_MASK = 15
};
/* API definition */
diff --git a/include/afb-req-itf.h b/include/afb-req-itf.h
index 061c1f0d..a975503d 100644
--- a/include/afb-req-itf.h
+++ b/include/afb-req-itf.h
@@ -26,28 +26,30 @@ struct afb_arg {
};
struct afb_req_itf {
- struct json_object *(*json)(void *req_closure);
- struct afb_arg (*get)(void *req_closure, const char *name);
- void (*success)(void *req_closure, struct json_object *obj, const char *info);
- void (*fail)(void *req_closure, const char *status, const char *info);
- const char *(*raw)(void *req_closure, size_t *size);
- void (*send)(void *req_closure, const char *buffer, size_t size);
- void *(*context_get)(void *ctx_closure);
- void (*context_set)(void *ctx_closure, void *value, void (*free_value)(void*));
- int (*session_create)(void *req_closure);
- int (*session_check)(void *req_closure, int refresh);
- void (*session_close)(void *req_closure);
+ struct json_object *(*json)(void *closure);
+ struct afb_arg (*get)(void *closure, const char *name);
+
+ void (*success)(void *closure, struct json_object *obj, const char *info);
+ void (*fail)(void *closure, const char *status, const char *info);
+
+ const char *(*raw)(void *closure, size_t *size);
+ void (*send)(void *closure, const char *buffer, size_t size);
+
+ void *(*context_get)(void *closure);
+ void (*context_set)(void *closure, void *value, void (*free_value)(void*));
+
+ void (*addref)(void *closure);
+ void (*unref)(void *closure);
};
struct afb_req {
const struct afb_req_itf *itf;
- void *req_closure;
- void *ctx_closure;
+ void *closure;
};
static inline struct afb_arg afb_req_get(struct afb_req req, const char *name)
{
- return req.itf->get(req.req_closure, name);
+ return req.itf->get(req.closure, name);
}
static inline const char *afb_req_value(struct afb_req req, const char *name)
@@ -62,37 +64,37 @@ static inline const char *afb_req_path(struct afb_req req, const char *name)
static inline struct json_object *afb_req_json(struct afb_req req)
{
- return req.itf->json(req.req_closure);
+ return req.itf->json(req.closure);
}
static inline void afb_req_success(struct afb_req req, struct json_object *obj, const char *info)
{
- req.itf->success(req.req_closure, obj, info);
+ req.itf->success(req.closure, obj, info);
}
static inline void afb_req_fail(struct afb_req req, const char *status, const char *info)
{
- req.itf->fail(req.req_closure, status, info);
+ req.itf->fail(req.closure, status, info);
}
static inline const char *afb_req_raw(struct afb_req req, size_t *size)
{
- return req.itf->raw(req.req_closure, size);
+ return req.itf->raw(req.closure, size);
}
static inline void afb_req_send(struct afb_req req, const char *buffer, size_t size)
{
- req.itf->send(req.req_closure, buffer, size);
+ req.itf->send(req.closure, buffer, size);
}
static inline void *afb_req_context_get(struct afb_req req)
{
- return req.itf->context_get(req.ctx_closure);
+ return req.itf->context_get(req.closure);
}
static inline void afb_req_context_set(struct afb_req req, void *value, void (*free_value)(void*))
{
- return req.itf->context_set(req.ctx_closure, value, free_value);
+ return req.itf->context_set(req.closure, value, free_value);
}
static inline void afb_req_context_clear(struct afb_req req)
@@ -100,25 +102,14 @@ static inline void afb_req_context_clear(struct afb_req req)
afb_req_context_set(req, NULL, NULL);
}
-static inline int afb_req_session_create(struct afb_req req)
+static inline void afb_req_addref(struct afb_req req)
{
- int result = req.itf->session_create(req.req_closure);
- if (!result)
- afb_req_fail(req, "fail", "Can't create the session");
- return result;
-}
-
-static inline int afb_req_session_check(struct afb_req req, int refresh)
-{
- int result = req.itf->session_check(req.req_closure, refresh);
- if (!result)
- afb_req_fail(req, "fail", "Token chek failed for the session");
- return result;
+ return req.itf->addref(req.closure);
}
-static inline void afb_req_session_close(struct afb_req req)
+static inline void afb_req_unref(struct afb_req req)
{
- req.itf->session_close(req.req_closure);
+ return req.itf->unref(req.closure);
}
#include <stdlib.h>
@@ -126,8 +117,10 @@ static inline void afb_req_session_close(struct afb_req req)
static inline struct afb_req *afb_req_store(struct afb_req req)
{
struct afb_req *result = malloc(sizeof *result);
- if (result != NULL)
+ if (result != NULL) {
*result = req;
+ afb_req_addref(req);
+ }
return result;
}
@@ -135,6 +128,7 @@ static inline struct afb_req afb_req_unstore(struct afb_req *req)
{
struct afb_req result = *req;
free(req);
+ afb_req_unref(result);
return result;
}
diff --git a/plugins/afm-main-plugin/afm-main-plugin.c b/plugins/afm-main-plugin/afm-main-plugin.c
index c6408a51..8b26fe7e 100644
--- a/plugins/afm-main-plugin/afm-main-plugin.c
+++ b/plugins/afm-main-plugin/afm-main-plugin.c
@@ -62,6 +62,7 @@ static struct memo *make_memo(struct afb_req request, const char *method)
if (memo != NULL) {
memo->request = request;
memo->method = method;
+ afb_req_addref(request);
}
return memo;
}
@@ -109,6 +110,7 @@ static void embed_call_void_callback(int status, struct json_object *obj, struct
afb_req_success(memo->request, obj, NULL);
}
}
+ afb_req_unref(memo->request);
free(memo);
}
@@ -134,6 +136,7 @@ static void call_appid_callback(int status, struct json_object *obj, struct memo
obj = json_object_get(obj);
afb_req_success(memo->request, obj, NULL);
}
+ afb_req_unref(memo->request);
free(memo);
}
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index bc5fd4f0..707b2e09 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,20 +1,22 @@
ADD_LIBRARY(src OBJECT
- main.c
- session.c
+ afb-api-dbus.c
+ afb-api-so.c
+ afb-apis.c
+ afb-common.c
+ afb-context.c
+ afb-hreq.c
afb-hsrv.c
afb-hswitch.c
- afb-apis.c
- afb-api-so.c
afb-method.c
- afb-hreq.c
+ afb-msg-json.c
afb-websock.c
- afb-ws.c
afb-ws-json.c
- afb-msg-json.c
- afb-common.c
- websock.c
+ afb-ws.c
+ main.c
+ session.c
verbose.c
+ websock.c
)
INCLUDE_DIRECTORIES(${include_dirs})
diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c
new file mode 100644
index 00000000..818f8d11
--- /dev/null
+++ b/src/afb-api-dbus.c
@@ -0,0 +1,511 @@
+/*
+ * Copyright (C) 2015 "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.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <systemd/sd-bus.h>
+#include <json.h>
+
+#include "afb-plugin.h"
+#include "afb-req-itf.h"
+
+#include "afb-common.h"
+
+#include "session.h"
+#include "afb-apis.h"
+#include "afb-api-so.h"
+#include "afb-context.h"
+#include "verbose.h"
+
+static const char DEFAULT_PATH_PREFIX[] = "/org/agl/afb/api/";
+
+/*
+ * The path given are of the form
+ * system:/org/agl/afb/api/...
+ * or
+ * user:/org/agl/afb/api/...
+ */
+struct api_dbus
+{
+ struct sd_bus *sdbus; /* the bus */
+ char *path; /* path of the object for the API */
+ char *name; /* name/interface of the object */
+ char *api; /* api name of the interface */
+};
+
+#define RETOK 1
+#define RETERR 2
+#define RETRAW 3
+
+/******************* common part **********************************/
+
+/*
+ * create a structure api_dbus connected on either the system
+ * bus if 'system' is not null or on the user bus. The connection
+ * is established for either emiting/receiving on 'path' being of length
+ * 'pathlen'.
+ */
+static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pathlen)
+{
+ struct api_dbus *api;
+ struct sd_bus *sdbus;
+ char *ptr;
+
+ /* allocates the structure */
+ api = calloc(1, sizeof *api + 1 + pathlen + pathlen);
+ if (api == NULL) {
+ errno = ENOMEM;
+ goto error;
+ }
+
+ /* init the structure's strings */
+
+ /* path is copied after the struct */
+ api->path = (void*)(api+1);
+ strcpy(api->path, path);
+
+ /* api name is at the end of the path */
+ api->api = strrchr(api->path, '/');
+ if (api->api == NULL) {
+ errno = EINVAL;
+ goto error2;
+ }
+ api->api++;
+
+ /* the name/interface is copied after the path */
+ api->name = &api->path[pathlen + 1];
+ strcpy(api->name, &path[1]);
+ ptr = strchr(api->name, '/');
+ while(ptr != NULL) {
+ *ptr = '.';
+ ptr = strchr(ptr, '/');
+ }
+
+ /* choose the bus */
+ sdbus = (system ? afb_common_get_system_bus : afb_common_get_user_bus)();
+ if (sdbus == NULL)
+ goto error2;
+
+ api->sdbus = sdbus;
+ return api;
+
+error2:
+ free(api);
+error:
+ return NULL;
+}
+
+/*
+ * create a structure api_dbus connected on either the system
+ * bus if 'system' is not null or on the user bus. The connection
+ * is established for either emiting/receiving on 'path'.
+ * If 'path' is not absolute, it is prefixed with DEFAULT_PATH_PREFIX.
+ */
+static struct api_dbus *make_api_dbus_2(int system, const char *path)
+{
+ size_t len;
+ char *ptr;
+
+ /* check the length of the path */
+ len = strlen(path);
+ if (len == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* if the path is absolute, creation now */
+ if (path[0] == '/')
+ return make_api_dbus_3(system, path, len);
+
+ /* compute the path prefixed with DEFAULT_PATH_PREFIX */
+ assert(strlen(DEFAULT_PATH_PREFIX) > 0);
+ assert(DEFAULT_PATH_PREFIX[strlen(DEFAULT_PATH_PREFIX) - 1] == '/');
+ len += strlen(DEFAULT_PATH_PREFIX);
+ ptr = alloca(len + 1);
+ strcpy(stpcpy(ptr, DEFAULT_PATH_PREFIX), path);
+
+ /* creation for prefixed path */
+ return make_api_dbus_3(system, ptr, len);
+}
+
+/*
+ * create a structure api_dbus connected either emiting/receiving
+ * on 'path'.
+ * The path can be prefixed with "system:" or "user:" to select
+ * either the user or the system D-Bus. If none is set then user's
+ * bus is selected.
+ * If remaining 'path' is not absolute, it is prefixed with
+ * DEFAULT_PATH_PREFIX.
+ */
+static struct api_dbus *make_api_dbus(const char *path)
+{
+ const char *ptr;
+ size_t preflen;
+
+ /* retrieves the prefix "scheme-like" part */
+ ptr = strchr(path, ':');
+ if (ptr == NULL)
+ return make_api_dbus_2(0, path);
+
+ /* check the prefix part */
+ preflen = (size_t)(ptr - path);
+ if (strncmp(path, "system", preflen) == 0)
+ return make_api_dbus_2(1, ptr + 1);
+
+ if (strncmp(path, "user", preflen) == 0)
+ return make_api_dbus_2(0, ptr + 1);
+
+ /* TODO: connect to a foreign D-Bus? */
+ errno = EINVAL;
+ return NULL;
+}
+
+static void destroy_api_dbus(struct api_dbus *api)
+{
+ free(api);
+}
+
+/******************* client part **********************************/
+
+/*
+ * structure for recording query data
+ */
+struct dbus_memo {
+ struct afb_req req; /* the request handle */
+ struct afb_context *context; /* the context of the query */
+};
+
+/* allocates and init the memorizing data */
+static struct dbus_memo *api_dbus_client_make_memo(struct afb_req req, struct afb_context *context)
+{
+ struct dbus_memo *memo;
+
+ memo = malloc(sizeof *memo);
+ if (memo != NULL) {
+ afb_req_addref(req);
+ memo->req = req;
+ memo->context = context;
+ }
+ return memo;
+}
+
+/* free and release the memorizing data */
+static void api_dbus_client_free_memo(struct dbus_memo *memo)
+{
+ afb_req_unref(memo->req);
+ free(memo);
+}
+
+/* callback when received answer */
+static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
+{
+ int rc;
+ struct dbus_memo *memo;
+ const char *first, *second;
+ uint8_t type;
+ uint32_t flags;
+
+ /* retrieve the recorded data */
+ memo = userdata;
+
+ /* get the answer */
+ rc = sd_bus_message_read(message, "yssu", &type, &first, &second, &flags);
+ if (rc < 0) {
+ /* failing to have the answer */
+ afb_req_fail(memo->req, "error", "dbus error");
+ } else {
+ /* report the answer */
+ memo->context->flags = (unsigned)flags;
+ switch(type) {
+ case RETOK:
+ afb_req_success(memo->req, json_tokener_parse(first), second);
+ break;
+ case RETERR:
+ afb_req_fail(memo->req, first, second);
+ break;
+ case RETRAW:
+ afb_req_send(memo->req, first, strlen(first));
+ break;
+ default:
+ afb_req_fail(memo->req, "error", "dbus link broken");
+ break;
+ }
+ }
+ api_dbus_client_free_memo(memo);
+ return 1;
+}
+
+/* on call, propagate it to the dbus service */
+static void api_dbus_client_call(struct api_dbus *api, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb)
+{
+ size_t size;
+ int rc;
+ char *method = strndupa(verb, lenverb);
+ struct dbus_memo *memo;
+
+ /* create the recording data */
+ memo = api_dbus_client_make_memo(req, context);
+ if (memo == NULL) {
+ afb_req_fail(req, "error", "out of memory");
+ return;
+ }
+
+ /* makes the call */
+ rc = sd_bus_call_method_async(api->sdbus, NULL,
+ api->name, api->path, api->name, method,
+ api_dbus_client_on_reply, memo,
+ "ssu",
+ afb_req_raw(req, &size),
+ ctxClientGetUuid(context->session),
+ (uint32_t)context->flags);
+
+ /* if there was an error report it directly */
+ if (rc < 0) {
+ errno = -rc;
+ afb_req_fail(req, "error", "dbus error");
+ api_dbus_client_free_memo(memo);
+ }
+}
+
+/* adds a afb-dbus-service client api */
+int afb_api_dbus_add_client(const char *path)
+{
+ struct api_dbus *api;
+ struct afb_api afb_api;
+
+ /* create the dbus client api */
+ api = make_api_dbus(path);
+ if (api == NULL)
+ goto error;
+
+ /* record it as an API */
+ afb_api.closure = api;
+ afb_api.call = (void*)api_dbus_client_call;
+ if (afb_apis_add(api->api, afb_api) < 0)
+ goto error2;
+
+ return 0;
+
+error2:
+ destroy_api_dbus(api);
+error:
+ return -1;
+}
+
+/******************* dbus request part for server *****************/
+
+/*
+ * structure for a dbus request
+ */
+struct dbus_req {
+ struct afb_context context; /* the context, should be THE FIRST */
+ sd_bus_message *message; /* the incoming request message */
+ const char *request; /* the readen request as string */
+ struct json_object *json; /* the readen request as object */
+ int refcount; /* reference count of the request */
+};
+
+/* increment the reference count of the request */
+static void dbus_req_addref(struct dbus_req *dreq)
+{
+ dreq->refcount++;
+}
+
+/* decrement the reference count of the request and free/release it on falling to null */
+static void dbus_req_unref(struct dbus_req *dreq)
+{
+ if (dreq == NULL || --dreq->refcount)
+ return;
+
+ afb_context_disconnect(&dreq->context);
+ json_object_put(dreq->json);
+ sd_bus_message_unref(dreq->message);
+ free(dreq);
+}
+
+/* get the object of the request */
+static struct json_object *dbus_req_json(struct dbus_req *dreq)
+{
+ if (dreq->json == NULL) {
+ dreq->json = json_tokener_parse(dreq->request);
+ if (dreq->json == NULL) {
+ /* lazy error detection of json request. Is it to improve? */
+ dreq->json = json_object_new_string(dreq->request);
+ }
+ }
+ return dreq->json;
+}
+
+/* get the argument of the request of 'name' */
+static struct afb_arg dbus_req_get(struct dbus_req *dreq, const char *name)
+{
+ struct afb_arg arg;
+ struct json_object *value, *root;
+
+ root = dbus_req_json(dreq);
+ if (root != NULL && json_object_object_get_ex(root, name, &value)) {
+ arg.name = name;
+ arg.value = json_object_get_string(value);
+ } else {
+ arg.name = NULL;
+ arg.value = NULL;
+ }
+ arg.path = NULL;
+ return arg;
+}
+
+static void dbus_req_reply(struct dbus_req *dreq, uint8_t type, const char *first, const char *second)
+{
+ int rc;
+ rc = sd_bus_reply_method_return(dreq->message,
+ "yssu", type, first, second, (uint32_t)dreq->context.flags);
+}
+
+static void dbus_req_success(struct dbus_req *dreq, struct json_object *obj, const char *info)
+{
+ dbus_req_reply(dreq, RETOK, json_object_to_json_string(obj), info);
+}
+
+static void dbus_req_fail(struct dbus_req *dreq, const char *status, const char *info)
+{
+ dbus_req_reply(dreq, RETERR, status, info);
+}
+
+static const char *dbus_req_raw(struct dbus_req *dreq, size_t *size)
+{
+ if (size != NULL)
+ *size = strlen(dreq->request);
+ return dreq->request;
+}
+
+static void dbus_req_send(struct dbus_req *dreq, const char *buffer, size_t size)
+{
+ /* TODO: how to put sized buffer as strings? things aren't clear here!!! */
+ dbus_req_reply(dreq, RETRAW, buffer, "");
+}
+
+struct afb_req_itf dbus_req_itf = {
+ .json = (void*)dbus_req_json,
+ .get = (void*)dbus_req_get,
+ .success = (void*)dbus_req_success,
+ .fail = (void*)dbus_req_fail,
+ .raw = (void*)dbus_req_raw,
+ .send = (void*)dbus_req_send,
+ .context_get = (void*)afb_context_get,
+ .context_set = (void*)afb_context_set,
+ .addref = (void*)dbus_req_addref,
+ .unref = (void*)dbus_req_unref
+};
+
+/******************* server part **********************************/
+
+/* called when the object for the service is called */
+static int api_dbus_server_on_object_called(sd_bus_message *message, void *userdata, sd_bus_error *ret_error)
+{
+ int rc;
+ const char *method;
+ const char *uuid;
+ struct dbus_req *dreq;
+ struct api_dbus *api = userdata;
+ struct afb_req areq;
+ uint32_t flags;
+
+ /* check the interface */
+ if (strcmp(sd_bus_message_get_interface(message), api->name) != 0)
+ return 0;
+
+ /* get the method */
+ method = sd_bus_message_get_member(message);
+
+ /* create the request */
+ dreq = calloc(1 , sizeof *dreq);
+ if (dreq == NULL) {
+ sd_bus_reply_method_errorf(message, SD_BUS_ERROR_NO_MEMORY, "out of memory");
+ return 1;
+ }
+
+ /* get the data */
+ rc = sd_bus_message_read(message, "ssu", &dreq->request, &uuid, &flags);
+ if (rc < 0) {
+ sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature");
+ free(dreq);
+ return 1;
+ }
+
+ /* connect to the context */
+ if (afb_context_connect(&dreq->context, uuid, NULL) < 0) {
+ sd_bus_reply_method_errorf(message, SD_BUS_ERROR_NO_MEMORY, "out of memory");
+ free(dreq);
+ return 1;
+ }
+
+ /* fulfill the request and emit it */
+ dreq->context.flags = flags;
+ dreq->message = sd_bus_message_ref(message);
+ dreq->json = NULL;
+ dreq->refcount = 1;
+ areq.itf = &dbus_req_itf;
+ areq.closure = dreq;
+ afb_apis_call_(areq, &dreq->context, api->api, method);
+ dbus_req_unref(dreq);
+ return 1;
+}
+
+/* create the service */
+int afb_api_dbus_add_server(const char *path)
+{
+ int rc;
+ struct api_dbus *api;
+ sd_bus_slot *slot;
+
+ /* get the dbus api object connected */
+ api = make_api_dbus(path);
+ if (api == NULL)
+ goto error;
+
+ /* request the service object name */
+ rc = sd_bus_request_name(api->sdbus, api->name, 0);
+ if (rc < 0) {
+ errno = -rc;
+ ERROR("can't register name %s", api->name);
+ goto error2;
+ }
+
+ /* connect the service to the dbus object */
+ rc = sd_bus_add_object(api->sdbus, &slot, api->path, api_dbus_server_on_object_called, api);
+ if (rc < 0) {
+ errno = -rc;
+ ERROR("can't add dbus object %s for %s", api->path, api->name);
+ goto error3;
+ }
+ INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
+
+ return 0;
+error3:
+ sd_bus_release_name(api->sdbus, api->name);
+error2:
+ destroy_api_dbus(api);
+error:
+ return -1;
+}
+
+
diff --git a/src/afb-api-dbus.h b/src/afb-api-dbus.h
new file mode 100644
index 00000000..8ea1909b
--- /dev/null
+++ b/src/afb-api-dbus.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 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
+
+extern int afb_api_dbus_add_client(const char *path);
+
+extern int afb_api_dbus_add_server(const char *path);
+
+
diff --git a/src/afb-api-so.c b/src/afb-api-so.c
index 89418fb0..38621ecf 100644
--- a/src/afb-api-so.c
+++ b/src/afb-api-so.c
@@ -37,6 +37,7 @@
#include "session.h"
#include "afb-common.h"
+#include "afb-context.h"
#include "afb-apis.h"
#include "afb-api-so.h"
#include "verbose.h"
@@ -126,32 +127,36 @@ static void trapping_call(struct afb_req req, void(*cb)(struct afb_req))
error_handler = older;
}
-static void call_check(struct afb_req req, const struct AFB_restapi *verb)
+static void call_check(struct afb_req req, struct afb_context *context, const struct AFB_restapi *verb)
{
- switch(verb->session) {
- case AFB_SESSION_CREATE:
- if (!afb_req_session_create(req))
- return;
- break;
- case AFB_SESSION_RENEW:
- if (!afb_req_session_check(req, 1))
+ int stag = (int)(verb->session & AFB_SESSION_MASK);
+
+ if (stag != AFB_SESSION_NONE) {
+ if (!afb_context_check(context)) {
+ afb_context_close(context);
+ afb_req_fail(req, "failed", "invalid token's identity");
return;
- break;
- case AFB_SESSION_CLOSE:
- case AFB_SESSION_CHECK:
- if (!afb_req_session_check(req, 0))
+ }
+ }
+
+ if ((stag & AFB_SESSION_CREATE) != 0) {
+ if (!afb_context_create(context)) {
+ afb_context_close(context);
+ afb_req_fail(req, "failed", "invalid creation state");
return;
- break;
- case AFB_SESSION_NONE:
- default:
- break;
+ }
}
+
+ if ((stag & (AFB_SESSION_CREATE | AFB_SESSION_RENEW)) != 0)
+ afb_context_refresh(context);
+
+ if ((stag & AFB_SESSION_CLOSE) != 0)
+ afb_context_close(context);
+
trapping_call(req, verb->callback);
- if (verb->session == AFB_SESSION_CLOSE)
- afb_req_session_close(req);
}
-static void call(struct api_so_desc *desc, struct afb_req req, const char *verb, size_t lenverb)
+static void call(struct api_so_desc *desc, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb)
{
const struct AFB_restapi *v;
@@ -159,7 +164,7 @@ static void call(struct api_so_desc *desc, struct afb_req req, const char *verb,
while (v->name && (strncasecmp(v->name, verb, lenverb) || v->name[lenverb]))
v++;
if (v->name)
- call_check(req, v);
+ call_check(req, context, v);
else
afb_req_fail_f(req, "unknown-verb", "verb %.*s unknown within api %s", (int)lenverb, verb, desc->plugin->prefix);
}
diff --git a/src/afb-apis.c b/src/afb-apis.c
index bcb42429..da0b98f0 100644
--- a/src/afb-apis.c
+++ b/src/afb-apis.c
@@ -25,6 +25,7 @@
#include "session.h"
#include "verbose.h"
#include "afb-apis.h"
+#include "afb-context.h"
#include "afb-req-itf.h"
struct api_desc {
@@ -83,12 +84,12 @@ error:
return -1;
}
-void afb_apis_call_(struct afb_req req, struct AFB_clientCtx *context, const char *api, const char *verb)
+void afb_apis_call_(struct afb_req req, struct afb_context *context, const char *api, const char *verb)
{
afb_apis_call(req, context, api, strlen(api), verb, strlen(verb));
}
-void afb_apis_call(struct afb_req req, struct AFB_clientCtx *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb)
{
int i;
const struct api_desc *a;
@@ -96,8 +97,8 @@ void afb_apis_call(struct afb_req req, struct AFB_clientCtx *context, const char
a = apis_array;
for (i = 0 ; i < apis_count ; i++, a++) {
if (a->namelen == lenapi && !strncasecmp(a->name, api, lenapi)) {
- req.ctx_closure = &context->contexts[i];
- a->api.call(a->api.closure, req, verb, lenverb);
+ context->api_index = i;
+ a->api.call(a->api.closure, req, context, verb, lenverb);
return;
}
}
diff --git a/src/afb-apis.h b/src/afb-apis.h
index 795054aa..3e75130e 100644
--- a/src/afb-apis.h
+++ b/src/afb-apis.h
@@ -18,18 +18,18 @@
#pragma once
struct afb_req;
-struct AFB_clientCtx;
+struct afb_context;
struct afb_api
{
void *closure;
- void (*call)(void *closure, struct afb_req req, const char *verb, size_t lenverb);
+ void (*call)(void *closure, struct afb_req req, struct afb_context *context, const char *verb, size_t lenverb);
};
extern int afb_apis_count();
extern int afb_apis_add(const char *name, struct afb_api api);
-extern void afb_apis_call(struct afb_req req, struct AFB_clientCtx *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
-extern void afb_apis_call_(struct afb_req req, struct AFB_clientCtx *context, const char *api, const char *verb);
+extern void afb_apis_call(struct afb_req req, struct afb_context *context, const char *api, size_t lenapi, const char *verb, size_t lenverb);
+extern void afb_apis_call_(struct afb_req req, struct afb_context *context, const char *api, const char *verb);
diff --git a/src/afb-context.c b/src/afb-context.c
new file mode 100644
index 00000000..2f391dec
--- /dev/null
+++ b/src/afb-context.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2015 "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 <assert.h>
+#include <stdlib.h>
+
+#include "session.h"
+#include "afb-context.h"
+
+
+void afb_context_init(struct afb_context *context, struct AFB_clientCtx *session, const char *token)
+{
+ assert(session != NULL);
+
+ /* reset the context for the session */
+ context->session = session;
+ context->flags = 0;
+ context->api_index = -1;
+
+ /* check the token */
+ if (token != NULL) {
+ if (ctxTokenCheck(session, token))
+ context->validated = 1;
+ else
+ context->invalidated = 1;
+ }
+}
+
+int afb_context_connect(struct afb_context *context, const char *uuid, const char *token)
+{
+ int created;
+ struct AFB_clientCtx *session;
+
+ session = ctxClientGetSession (uuid, &created);
+ if (session == NULL)
+ return -1;
+ afb_context_init(context, session, token);
+ if (created)
+ context->created = 1;
+ return 0;
+}
+
+void afb_context_disconnect(struct afb_context *context)
+{
+ if (context->session != NULL) {
+ if (context->closing && !context->closed) {
+ context->closed = 1;
+ ctxClientClose(context->session);
+ }
+ ctxClientUnref(context->session);
+ }
+}
+
+const char *afb_context_sent_token(struct afb_context *context)
+{
+ if (context->session == NULL || context->closing)
+ return NULL;
+ if (!(context->created || context->refreshing))
+ return NULL;
+ if (!context->refreshed) {
+ ctxTokenNew (context->session);
+ context->refreshed = 1;
+ }
+ return ctxClientGetToken(context->session);
+}
+
+const char *afb_context_sent_uuid(struct afb_context *context)
+{
+ if (context->session == NULL || context->closing)
+ return NULL;
+ if (!context->created)
+ return NULL;
+ return ctxClientGetUuid(context->session);
+}
+
+void *afb_context_get(struct afb_context *context)
+{
+ assert(context->session != NULL);
+ return ctxClientValueGet(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);
+}
+
+void afb_context_close(struct afb_context *context)
+{
+ context->closing = 1;
+}
+
+void afb_context_refresh(struct afb_context *context)
+{
+ context->refreshing = 1;
+}
+
+int afb_context_check(struct afb_context *context)
+{
+ return context->validated;
+}
+
+int afb_context_create(struct afb_context *context)
+{
+ return context->created;
+}
diff --git a/src/afb-context.h b/src/afb-context.h
new file mode 100644
index 00000000..eeb4def3
--- /dev/null
+++ b/src/afb-context.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2016 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_clientCtx;
+
+struct afb_context
+{
+ struct AFB_clientCtx *session;
+ union {
+ unsigned flags;
+ struct {
+ unsigned created: 1;
+ unsigned validated: 1;
+ unsigned invalidated: 1;
+ unsigned refreshing: 1;
+ unsigned refreshed: 1;
+ unsigned closing: 1;
+ unsigned closed: 1;
+ };
+ };
+ int api_index;
+};
+
+extern void afb_context_init(struct afb_context *context, struct AFB_clientCtx *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);
+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_close(struct afb_context *context);
+extern void afb_context_refresh(struct afb_context *context);
+extern int afb_context_check(struct afb_context *context);
+extern int afb_context_create(struct afb_context *context);
+
diff --git a/src/afb-hreq.c b/src/afb-hreq.c
index d0adda6e..518bc5cb 100644
--- a/src/afb-hreq.c
+++ b/src/afb-hreq.c
@@ -35,6 +35,7 @@
#include "afb-method.h"
#include "afb-req-itf.h"
#include "afb-msg-json.h"
+#include "afb-context.h"
#include "afb-hreq.h"
#include "session.h"
#include "verbose.h"
@@ -55,12 +56,15 @@ static char *cookie_name = NULL;
static char *cookie_setter = NULL;
static char *tmp_pattern = NULL;
+/*
+ * Structure for storing key/values read from POST requests
+ */
struct hreq_data {
- struct hreq_data *next;
- char *key;
- size_t length;
- char *value;
- char *path;
+ struct hreq_data *next; /* chain to next data */
+ char *key; /* key name */
+ size_t length; /* length of the value (used for appending) */
+ char *value; /* the value (or original filename) */
+ char *path; /* path of the file saved */
};
static struct json_object *req_json(struct afb_hreq *hreq);
@@ -69,9 +73,6 @@ static void req_fail(struct afb_hreq *hreq, const char *status, const char *info
static void req_success(struct afb_hreq *hreq, json_object *obj, const char *info);
static const char *req_raw(struct afb_hreq *hreq, size_t *size);
static void req_send(struct afb_hreq *hreq, const char *buffer, size_t size);
-static int req_session_create(struct afb_hreq *hreq);
-static int req_session_check(struct afb_hreq *hreq, int refresh);
-static void req_session_close(struct afb_hreq *hreq);
static const struct afb_req_itf afb_hreq_itf = {
.json = (void*)req_json,
@@ -80,11 +81,10 @@ static const struct afb_req_itf afb_hreq_itf = {
.fail = (void*)req_fail,
.raw = (void*)req_raw,
.send = (void*)req_send,
- .session_create = (void*)req_session_create,
- .session_check = (void*)req_session_check,
- .session_close = (void*)req_session_close,
.context_get = (void*)afb_context_get,
- .context_set = (void*)afb_context_set
+ .context_set = (void*)afb_context_set,
+ .addref = (void*)afb_hreq_addref,
+ .unref = (void*)afb_hreq_unref
};
static struct hreq_data *get_data(struct afb_hreq *hreq, const char *key, int create)
@@ -162,7 +162,8 @@ static void afb_hreq_reply_v(struct afb_hreq *hreq, unsigned status, struct MHD_
MHD_add_response_header(response, k, v);
k = va_arg(args, const char *);
}
- if (hreq->context != NULL && asprintf(&cookie, cookie_setter, hreq->context->uuid)) {
+ v = afb_context_sent_uuid(&hreq->context);
+ if (v != NULL && asprintf(&cookie, cookie_setter, v) > 0) {
MHD_add_response_header(response, MHD_HTTP_HEADER_SET_COOKIE, cookie);
free(cookie);
}
@@ -291,26 +292,33 @@ static const char *mimetype_fd_name(int fd, const char *filename)
return result;
}
-void afb_hreq_free(struct afb_hreq *hreq)
+void afb_hreq_addref(struct afb_hreq *hreq)
+{
+ hreq->refcount++;
+}
+
+void afb_hreq_unref(struct afb_hreq *hreq)
{
struct hreq_data *data;
- if (hreq != NULL) {
- if (hreq->postform != NULL)
- MHD_destroy_post_processor(hreq->postform);
- for (data = hreq->data; data; data = hreq->data) {
- hreq->data = data->next;
- if (data->path) {
- unlink(data->path);
- free(data->path);
- }
- free(data->key);
- free(data->value);
- free(data);
+
+ if (hreq == NULL || --hreq->refcount)
+ return;
+
+ if (hreq->postform != NULL)
+ MHD_destroy_post_processor(hreq->postform);
+ for (data = hreq->data; data; data = hreq->data) {
+ hreq->data = data->next;
+ if (data->path) {
+ unlink(data->path);
+ free(data->path);
}
- ctxClientPut(hreq->context);
- json_object_put(hreq->json);
- free(hreq);
+ free(data->key);
+ free(data->value);
+ free(data);
}
+ afb_context_disconnect(&hreq->context);
+ json_object_put(hreq->json);
+ free(hreq);
}
/*
@@ -599,7 +607,7 @@ int afb_hreq_post_add_file(struct afb_hreq *hreq, const char *key, const char *f
struct afb_req afb_hreq_to_req(struct afb_hreq *hreq)
{
- return (struct afb_req){ .itf = &afb_hreq_itf, .req_closure = hreq };
+ return (struct afb_req){ .itf = &afb_hreq_itf, .closure = hreq };
}
static struct afb_arg req_get(struct afb_hreq *hreq, const char *name)
@@ -678,12 +686,9 @@ static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *statu
const char *token, *uuid;
struct MHD_Response *response;
- if (hreq->context == NULL) {
- token = uuid = NULL;
- } else {
- token = hreq->context->token;
- uuid = hreq->context->uuid;
- }
+ token = afb_context_sent_token(&hreq->context);
+ uuid = afb_context_sent_uuid(&hreq->context);
+
reply = afb_msg_json_reply(status, info, resp, token, uuid);
response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string(reply)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put);
afb_hreq_reply(hreq, retcode, response, NULL);
@@ -699,63 +704,27 @@ static void req_success(struct afb_hreq *hreq, json_object *obj, const char *inf
req_reply(hreq, MHD_HTTP_OK, "success", info, obj);
}
-struct AFB_clientCtx *afb_hreq_context(struct afb_hreq *hreq)
+int afb_hreq_init_context(struct afb_hreq *hreq)
{
const char *uuid;
-
- if (hreq->context == NULL) {
- uuid = afb_hreq_get_header(hreq, uuid_header);
- if (uuid == NULL)
- uuid = afb_hreq_get_argument(hreq, uuid_arg);
- if (uuid == NULL)
- uuid = afb_hreq_get_cookie(hreq, cookie_name);
- hreq->context = ctxClientGetForUuid(uuid);
- }
- return hreq->context;
-}
-
-static int req_session_create(struct afb_hreq *hreq)
-{
- struct AFB_clientCtx *context = afb_hreq_context(hreq);
- if (context == NULL)
- return 0;
- if (context->created)
- return 0;
- return req_session_check(hreq, 1);
-}
-
-static int req_session_check(struct afb_hreq *hreq, int refresh)
-{
const char *token;
- struct AFB_clientCtx *context = afb_hreq_context(hreq);
-
- if (context == NULL)
+ if (hreq->context.session != NULL)
return 0;
+ uuid = afb_hreq_get_header(hreq, uuid_header);
+ if (uuid == NULL)
+ uuid = afb_hreq_get_argument(hreq, uuid_arg);
+ if (uuid == NULL)
+ uuid = afb_hreq_get_cookie(hreq, cookie_name);
+
token = afb_hreq_get_header(hreq, token_header);
if (token == NULL)
token = afb_hreq_get_argument(hreq, token_arg);
if (token == NULL)
token = afb_hreq_get_cookie(hreq, token_cookie);
- if (token == NULL)
- return 0;
- if (!ctxTokenCheck (context, token))
- return 0;
-
- if (refresh) {
- ctxTokenNew (context);
- }
-
- return 1;
-}
-
-static void req_session_close(struct afb_hreq *hreq)
-{
- struct AFB_clientCtx *context = afb_hreq_context(hreq);
- if (context != NULL)
- ctxClientClose(context);
+ return afb_context_connect(&hreq->context, uuid, token);
}
int afb_hreq_init_cookie(int port, const char *path, int maxage)
diff --git a/src/afb-hreq.h b/src/afb-hreq.h
index 82e6b65a..3d197788 100644
--- a/src/afb-hreq.h
+++ b/src/afb-hreq.h
@@ -23,6 +23,8 @@ struct hreq_data;
struct afb_hsrv;
struct afb_hreq {
+ struct afb_context context;
+ int refcount;
struct afb_hsrv *hsrv;
const char *cacheTimeout;
struct MHD_Connection *connection;
@@ -37,14 +39,11 @@ struct afb_hreq {
const char *tail;
size_t lentail;
struct MHD_PostProcessor *postform;
- struct AFB_clientCtx *context;
struct hreq_data *data;
struct json_object *json;
int upgrade;
};
-extern void afb_hreq_free(struct afb_hreq *request);
-
extern int afb_hreq_unprefix(struct afb_hreq *request, const char *prefix, size_t length);
extern int afb_hreq_valid_tail(struct afb_hreq *request);
@@ -69,7 +68,7 @@ extern int afb_hreq_post_add(struct afb_hreq *hreq, const char *name, const char
extern struct afb_req afb_hreq_to_req(struct afb_hreq *hreq);
-extern struct AFB_clientCtx *afb_hreq_context(struct afb_hreq *hreq);
+extern int afb_hreq_init_context(struct afb_hreq *hreq);
extern int afb_hreq_init_cookie(int port, const char *path, int maxage);
@@ -82,3 +81,8 @@ extern void afb_hreq_reply_free(struct afb_hreq *hreq, unsigned status, size_t s
extern void afb_hreq_reply_empty(struct afb_hreq *hreq, unsigned status, ...);
extern int afb_hreq_init_download_path(const char *directory);
+
+extern void afb_hreq_addref(struct afb_hreq *hreq);
+
+extern void afb_hreq_unref(struct afb_hreq *hreq);
+
diff --git a/src/afb-hsrv.c b/src/afb-hsrv.c
index f514c97d..e64c5c9a 100644
--- a/src/afb-hsrv.c
+++ b/src/afb-hsrv.c
@@ -30,6 +30,7 @@
#include <systemd/sd-event.h>
#include "afb-method.h"
+#include "afb-context.h"
#include "afb-hreq.h"
#include "afb-hsrv.h"
#include "afb-req-itf.h"
@@ -130,6 +131,7 @@ static int access_handler(
}
/* init the request */
+ hreq->refcount = 1;
hreq->hsrv = hsrv;
hreq->cacheTimeout = hsrv->cache_to;
hreq->reqid = ++global_reqids;
@@ -228,7 +230,7 @@ static void end_handler(void *cls, struct MHD_Connection *connection, void **rec
hreq = *recordreq;
if (hreq->upgrade)
MHD_suspend_connection (connection);
- afb_hreq_free(hreq);
+ afb_hreq_unref(hreq);
}
void run_micro_httpd(struct afb_hsrv *hsrv)
diff --git a/src/afb-hswitch.c b/src/afb-hswitch.c
index 606d2664..f0308455 100644
--- a/src/afb-hswitch.c
+++ b/src/afb-hswitch.c
@@ -21,7 +21,10 @@
#include <stdlib.h>
#include <string.h>
+#include <microhttpd.h>
+
#include "afb-req-itf.h"
+#include "afb-context.h"
#include "afb-hreq.h"
#include "afb-apis.h"
#include "session.h"
@@ -31,7 +34,6 @@ int afb_hswitch_apis(struct afb_hreq *hreq, void *data)
{
const char *api, *verb;
size_t lenapi, lenverb;
- struct AFB_clientCtx *context;
api = &hreq->tail[strspn(hreq->tail, "/")];
lenapi = strcspn(api, "/");
@@ -42,8 +44,10 @@ int afb_hswitch_apis(struct afb_hreq *hreq, void *data)
if (!(*api && *verb && lenapi && lenverb))
return 0;
- context = afb_hreq_context(hreq);
- afb_apis_call(afb_hreq_to_req(hreq), context, api, lenapi, verb, lenverb);
+ if (afb_hreq_init_context(hreq) < 0)
+ afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ else
+ afb_apis_call(afb_hreq_to_req(hreq), &hreq->context, api, lenapi, verb, lenverb);
return 1;
}
@@ -77,7 +81,12 @@ int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data)
if (hreq->lentail != 0)
return 0;
- return afb_websock_check_upgrade(hreq /* TODO: protocols here */);
+ if (afb_hreq_init_context(hreq) < 0) {
+ afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+ return 1;
+ }
+
+ return afb_websock_check_upgrade(hreq);
}
diff --git a/src/afb-websock.c b/src/afb-websock.c
index 9f5619fb..0247aae6 100644
--- a/src/afb-websock.c
+++ b/src/afb-websock.c
@@ -28,6 +28,7 @@
#include "afb-ws-json.h"
#include "afb-method.h"
+#include "afb-context.h"
#include "afb-hreq.h"
#include "afb-websock.h"
@@ -203,7 +204,7 @@ int afb_websock_check_upgrade(struct afb_hreq *hreq)
return 0;
ws = NULL;
- rc = check_websocket_upgrade(hreq->connection, protodefs, afb_hreq_context(hreq), &ws);
+ rc = check_websocket_upgrade(hreq->connection, protodefs, hreq->context.session, &ws);
if (rc == 1) {
hreq->replied = 1;
if (ws != NULL)
diff --git a/src/afb-ws-json.c b/src/afb-ws-json.c
index 4bdda7ef..781722fc 100644
--- a/src/afb-ws-json.c
+++ b/src/afb-ws-json.c
@@ -31,6 +31,7 @@
#include "session.h"
#include "afb-req-itf.h"
#include "afb-apis.h"
+#include "afb-context.h"
static void aws_on_hangup(struct afb_ws_json *ws);
static void aws_on_text(struct afb_ws_json *ws, char *text, size_t size);
@@ -47,7 +48,7 @@ struct afb_ws_json
void (*cleanup)(void*);
void *cleanup_closure;
struct afb_wsreq *requests;
- struct AFB_clientCtx *context;
+ struct AFB_clientCtx *session;
struct json_tokener *tokener;
struct afb_ws *ws;
};
@@ -58,12 +59,12 @@ static const struct afb_event_listener_itf event_listener_itf = {
.send = (void*)aws_send_event
};
-struct afb_ws_json *afb_ws_json_create(int fd, struct AFB_clientCtx *context, void (*cleanup)(void*), void *cleanup_closure)
+struct afb_ws_json *afb_ws_json_create(int fd, struct AFB_clientCtx *session, void (*cleanup)(void*), void *cleanup_closure)
{
struct afb_ws_json *result;
assert(fd >= 0);
- assert(context != NULL);
+ assert(session != NULL);
result = malloc(sizeof * result);
if (result == NULL)
@@ -72,8 +73,8 @@ struct afb_ws_json *afb_ws_json_create(int fd, struct AFB_clientCtx *context, vo
result->cleanup = cleanup;
result->cleanup_closure = cleanup_closure;
result->requests = NULL;
- result->context = ctxClientGet(context);
- if (result->context == NULL)
+ result->session = ctxClientAddRef(session);
+ if (result->session == NULL)
goto error2;
result->tokener = json_tokener_new();
@@ -84,7 +85,7 @@ struct afb_ws_json *afb_ws_json_create(int fd, struct AFB_clientCtx *context, vo
if (result->ws == NULL)
goto error4;
- if (0 > ctxClientEventListenerAdd(result->context, (struct afb_event_listener){ .itf = &event_listener_itf, .closure = result }))
+ if (0 > ctxClientEventListenerAdd(result->session, (struct afb_event_listener){ .itf = &event_listener_itf, .closure = result }))
goto error5;
return result;
@@ -94,7 +95,7 @@ error5:
error4:
json_tokener_free(result->tokener);
error3:
- ctxClientPut(result->context);
+ ctxClientUnref(result->session);
error2:
free(result);
error:
@@ -104,11 +105,12 @@ error:
static void aws_on_hangup(struct afb_ws_json *ws)
{
- ctxClientEventListenerRemove(ws->context, (struct afb_event_listener){ .itf = &event_listener_itf, .closure = ws });
+ ctxClientEventListenerRemove(ws->session, (struct afb_event_listener){ .itf = &event_listener_itf, .closure = ws });
afb_ws_destroy(ws->ws);
json_tokener_free(ws->tokener);
if (ws->cleanup != NULL)
ws->cleanup(ws->cleanup_closure);
+ ctxClientUnref(ws->session);
free(ws);
}
@@ -119,6 +121,8 @@ static void aws_on_hangup(struct afb_ws_json *ws)
struct afb_wsreq
{
+ struct afb_context context;
+ int refcount;
struct afb_ws_json *aws;
struct afb_wsreq *next;
char *text;
@@ -137,15 +141,14 @@ struct afb_wsreq
struct json_object *root;
};
+static void wsreq_addref(struct afb_wsreq *wsreq);
+static void wsreq_unref(struct afb_wsreq *wsreq);
static struct json_object *wsreq_json(struct afb_wsreq *wsreq);
static struct afb_arg wsreq_get(struct afb_wsreq *wsreq, const char *name);
static void wsreq_fail(struct afb_wsreq *wsreq, const char *status, const char *info);
static void wsreq_success(struct afb_wsreq *wsreq, struct json_object *obj, const char *info);
static const char *wsreq_raw(struct afb_wsreq *wsreq, size_t *size);
static void wsreq_send(struct afb_wsreq *wsreq, const char *buffer, size_t size);
-static int wsreq_session_create(struct afb_wsreq *wsreq);
-static int wsreq_session_check(struct afb_wsreq *wsreq, int refresh);
-static void wsreq_session_close(struct afb_wsreq *wsreq);
static const struct afb_req_itf wsreq_itf = {
@@ -155,11 +158,10 @@ static const struct afb_req_itf wsreq_itf = {
.fail = (void*)wsreq_fail,
.raw = (void*)wsreq_raw,
.send = (void*)wsreq_send,
- .session_create = (void*)wsreq_session_create,
- .session_check = (void*)wsreq_session_check,
- .session_close = (void*)wsreq_session_close,
.context_get = (void*)afb_context_get,
- .context_set = (void*)afb_context_set
+ .context_set = (void*)afb_context_set,
+ .addref = (void*)wsreq_addref,
+ .unref = (void*)wsreq_unref
};
static int aws_wsreq_parse(struct afb_wsreq *r, char *text, size_t size)
@@ -303,13 +305,20 @@ static void aws_on_text(struct afb_ws_json *ws, char *text, size_t size)
goto bad_header;
/* fill and record the request */
+ if (wsreq->tok != NULL)
+ wsreq->tok[wsreq->toklen] = 0;
+ afb_context_init(&wsreq->context, ws->session, wsreq->tok);
+ if (!wsreq->context.invalidated)
+ wsreq->context.validated = 1;
+ wsreq->refcount = 1;
wsreq->aws = ws;
wsreq->next = ws->requests;
ws->requests = wsreq;
- r.req_closure = wsreq;
+ r.closure = wsreq;
r.itf = &wsreq_itf;
- afb_apis_call(r, ws->context, wsreq->api, wsreq->apilen, wsreq->verb, wsreq->verblen);
+ afb_apis_call(r, &wsreq->context, wsreq->api, wsreq->apilen, wsreq->verb, wsreq->verblen);
+ wsreq_unref(wsreq);
return;
bad_header:
@@ -320,6 +329,20 @@ alloc_error:
return;
}
+static void wsreq_addref(struct afb_wsreq *wsreq)
+{
+ wsreq->refcount++;
+}
+
+static void wsreq_unref(struct afb_wsreq *wsreq)
+{
+ if (--wsreq->refcount == 0) {
+ afb_context_disconnect(&wsreq->context);
+ free(wsreq->text);
+ free(wsreq);
+ }
+}
+
static struct json_object *wsreq_json(struct afb_wsreq *wsreq)
{
struct json_object *root = wsreq->root;
@@ -352,41 +375,9 @@ static struct afb_arg wsreq_get(struct afb_wsreq *wsreq, const char *name)
return arg;
}
-static int wsreq_session_create(struct afb_wsreq *wsreq)
-{
- struct AFB_clientCtx *context = wsreq->aws->context;
- if (context->created)
- return 0;
- return wsreq_session_check(wsreq, 1);
-}
-
-static int wsreq_session_check(struct afb_wsreq *wsreq, int refresh)
-{
- struct AFB_clientCtx *context = wsreq->aws->context;
-
- if (wsreq->tok == NULL)
- return 0;
-
- if (!ctxTokenCheckLen (context, wsreq->tok, wsreq->toklen))
- return 0;
-
- if (refresh) {
- ctxTokenNew (context);
- }
-
- return 1;
-}
-
-static void wsreq_session_close(struct afb_wsreq *wsreq)
-{
- struct AFB_clientCtx *context = wsreq->aws->context;
- ctxClientClose(context);
-}
-
-static void aws_emit(struct afb_ws_json *aws, int code, const char *id, size_t idlen, struct json_object *data)
+static void aws_emit(struct afb_ws_json *aws, int code, const char *id, size_t idlen, struct json_object *data, const char *token)
{
json_object *msg;
- const char *token;
const char *txt;
/* pack the message */
@@ -394,7 +385,6 @@ static void aws_emit(struct afb_ws_json *aws, int code, const char *id, size_t i
json_object_array_add(msg, json_object_new_int(code));
json_object_array_add(msg, json_object_new_string_len(id, (int)idlen));
json_object_array_add(msg, data);
- token = aws->context->token;
if (token)
json_object_array_add(msg, json_object_new_string(token));
@@ -406,8 +396,8 @@ static void aws_emit(struct afb_ws_json *aws, int code, const char *id, size_t i
static void wsreq_reply(struct afb_wsreq *wsreq, int retcode, const char *status, const char *info, json_object *resp)
{
- aws_emit(wsreq->aws, retcode, wsreq->id, wsreq->idlen, afb_msg_json_reply(status, info, resp, NULL, NULL));
- /* TODO eliminates the wsreq */
+ const char *token = afb_context_sent_token(&wsreq->context);
+ aws_emit(wsreq->aws, retcode, wsreq->id, wsreq->idlen, afb_msg_json_reply(status, info, resp, token, NULL), token);
}
static void wsreq_fail(struct afb_wsreq *wsreq, const char *status, const char *info)
@@ -433,6 +423,6 @@ static void wsreq_send(struct afb_wsreq *wsreq, const char *buffer, size_t size)
static void aws_send_event(struct afb_ws_json *aws, const char *event, struct json_object *object)
{
- aws_emit(aws, EVENT, event, strlen(event), afb_msg_json_event(event, object));
+ aws_emit(aws, EVENT, event, strlen(event), afb_msg_json_event(event, object), NULL);
}
diff --git a/src/main.c b/src/main.c
index fcedd2a6..be1927e3 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,6 +39,7 @@
#include "afb-apis.h"
#include "afb-api-so.h"
#include "afb-hsrv.h"
+#include "afb-context.h"
#include "afb-hreq.h"
#include "session.h"
#include "verbose.h"
diff --git a/src/session.c b/src/session.c
index ae44f793..d586e517 100644
--- a/src/session.c
+++ b/src/session.c
@@ -31,6 +31,30 @@
#define NOW (time(NULL))
+struct client_value
+{
+ void *value;
+ void (*free_value)(void*);
+};
+
+struct afb_event_listener_list
+{
+ struct afb_event_listener_list *next;
+ struct afb_event_listener listener;
+ int refcount;
+};
+
+struct AFB_clientCtx
+{
+ unsigned refcount;
+ 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 afb_event_listener_list *listeners;
+};
+
// 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
@@ -42,31 +66,17 @@ static struct {
const char *initok;
} sessions;
-void *afb_context_get(struct afb_context *actx)
-{
- return actx->context;
-}
-
-void afb_context_set(struct afb_context *actx, void *context, void (*free_context)(void*))
-{
-fprintf(stderr, "afb_context_set(%p,%p) was (%p,%p)\n",context, free_context, actx->context, actx->free_context);
- if (actx->context != NULL && actx->free_context != NULL)
- actx->free_context(actx->context);
- actx->context = context;
- actx->free_context = free_context;
-}
-
// Free context [XXXX Should be protected again memory abort XXXX]
static void ctxUuidFreeCB (struct AFB_clientCtx *client)
{
int idx;
// If application add a handle let's free it now
- assert (client->contexts != NULL);
+ 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 ++)
- afb_context_set(&client->contexts[idx], NULL, NULL);
+ ctxClientValueSet(client, idx, NULL, NULL);
}
// Create a new store in RAM, not that is too small it will be automatically extended
@@ -77,7 +87,7 @@ void ctxStoreInit (int max_session_count, int timeout, const char *initok, int c
sessions.max = max_session_count;
sessions.timeout = timeout;
sessions.apicount = context_count;
- if (strlen(initok) >= 37) {
+ if (strlen(initok) >= sizeof(sessions.store[0]->token)) {
fprintf(stderr, "Error: initial token '%s' too long (max length 36)", initok);
exit(1);
}
@@ -175,67 +185,80 @@ static void ctxStoreCleanUp (time_t now)
}
// This function will return exiting client context or newly created client context
-struct AFB_clientCtx *ctxClientGetForUuid (const char *uuid)
+struct AFB_clientCtx *ctxClientGetSession (const char *uuid, int *created)
{
uuid_t newuuid;
struct AFB_clientCtx *clientCtx;
time_t now;
- /* search for an existing one not too old */
+ /* cleaning */
now = NOW;
ctxStoreCleanUp (now);
- clientCtx = uuid != NULL ? ctxStoreSearch (uuid) : NULL;
- if (clientCtx) {
- clientCtx->refcount++;
- return clientCtx;
- }
- /* mimic old behaviour */
-/*
-TODO remove? not remove?
- if (sessions.initok == NULL)
- return NULL;
-*/
- /* check the uuid if given */
- if (uuid != NULL && strlen(uuid) >= sizeof clientCtx->uuid)
- return NULL;
+ /* 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 */
- clientCtx = calloc(1, sizeof(struct AFB_clientCtx)); // init NULL clientContext
- if (clientCtx != NULL) {
- clientCtx->contexts = calloc ((unsigned)sessions.apicount, sizeof(*clientCtx->contexts));
- if (clientCtx->contexts != NULL) {
- /* generate the uuid */
- if (uuid == NULL) {
- uuid_generate(newuuid);
- uuid_unparse_lower(newuuid, clientCtx->uuid);
- } else {
- strcpy(clientCtx->uuid, uuid);
- }
- strcpy(clientCtx->token, sessions.initok);
- clientCtx->expiration = now + sessions.timeout;
- clientCtx->refcount = 1;
- if (ctxStoreAdd (clientCtx))
- return clientCtx;
- free(clientCtx->contexts);
- }
- free(clientCtx);
+ 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) {
+ uuid_generate(newuuid);
+ uuid_unparse_lower(newuuid, clientCtx->uuid);
+ } else {
+ strcpy(clientCtx->uuid, uuid);
+ }
+
+ /* init the token */
+ strcpy(clientCtx->token, sessions.initok);
+ clientCtx->expiration = now + sessions.timeout;
+ if (!ctxStoreAdd (clientCtx)) {
+ errno = ENOMEM;
+ goto error2;
}
+ *created = 1;
+
+found:
+ clientCtx->access = now;
+ clientCtx->refcount++;
+ return clientCtx;
+
+error2:
+ free(clientCtx);
+error:
return NULL;
}
-struct AFB_clientCtx *ctxClientGet(struct AFB_clientCtx *clientCtx)
+struct AFB_clientCtx *ctxClientAddRef(struct AFB_clientCtx *clientCtx)
{
if (clientCtx != NULL)
clientCtx->refcount++;
return clientCtx;
}
-void ctxClientPut(struct AFB_clientCtx *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);
+ }
}
}
@@ -243,16 +266,12 @@ void ctxClientPut(struct AFB_clientCtx *clientCtx)
void ctxClientClose (struct AFB_clientCtx *clientCtx)
{
assert(clientCtx != NULL);
- if (clientCtx->created) {
- clientCtx->created = 0;
- ctxUuidFreeCB (clientCtx);
- }
- if (clientCtx->refcount == 0)
- ctxStoreDel (clientCtx);
+ ctxUuidFreeCB (clientCtx);
+ clientCtx->uuid[0] = 0;
}
// Sample Generic Ping Debug API
-int ctxTokenCheckLen (struct AFB_clientCtx *clientCtx, const char *token, size_t length)
+int ctxTokenCheck (struct AFB_clientCtx *clientCtx, const char *token)
{
assert(clientCtx != NULL);
assert(token != NULL);
@@ -261,22 +280,12 @@ int ctxTokenCheckLen (struct AFB_clientCtx *clientCtx, const char *token, size_t
if (ctxStoreTooOld (clientCtx, NOW))
return 0;
- if (clientCtx->token[0] && (length >= sizeof(clientCtx->token) || strncmp (token, clientCtx->token, length) || clientCtx->token[length]))
+ if (clientCtx->token[0] && strcmp (token, clientCtx->token) != 0)
return 0;
- clientCtx->created = 1; /* creates by default */
return 1;
}
-// Sample Generic Ping Debug API
-int ctxTokenCheck (struct AFB_clientCtx *clientCtx, const char *token)
-{
- assert(clientCtx != NULL);
- assert(token != NULL);
-
- return ctxTokenCheckLen(clientCtx, token, strlen(token));
-}
-
// generate a new token and update client context
void ctxTokenNew (struct AFB_clientCtx *clientCtx)
{
@@ -292,13 +301,6 @@ void ctxTokenNew (struct AFB_clientCtx *clientCtx)
clientCtx->expiration = NOW + sessions.timeout;
}
-struct afb_event_listener_list
-{
- struct afb_event_listener_list *next;
- struct afb_event_listener listener;
- int refcount;
-};
-
int ctxClientEventListenerAdd(struct AFB_clientCtx *clientCtx, struct afb_event_listener listener)
{
struct afb_event_listener_list *iter, **prv;
@@ -375,12 +377,43 @@ int ctxClientEventSend(struct AFB_clientCtx *clientCtx, const char *event, struc
for (idx=0; idx < sessions.max; idx++) {
clientCtx = sessions.store[idx];
if (clientCtx != NULL && !ctxStoreTooOld(clientCtx, now)) {
- clientCtx = ctxClientGet(clientCtx);
+ clientCtx = ctxClientAddRef(clientCtx);
result += send(clientCtx, event, object);
- ctxClientPut(clientCtx);
+ ctxClientUnref(clientCtx);
}
}
}
return result;
}
+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;
+}
+
+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.free_value != NULL)
+ prev.free_value(prev.value);
+}
diff --git a/src/session.h b/src/session.h
index f6d67fe6..c2722455 100644
--- a/src/session.h
+++ b/src/session.h
@@ -18,15 +18,7 @@
#pragma once
struct json_object;
-
-struct afb_context
-{
- void *context;
- void (*free_context)(void*);
-};
-
-extern void *afb_context_get(struct afb_context *actx);
-extern void afb_context_set(struct afb_context *actx, void *context, void (*free_context)(void*));
+struct AFB_clientCtx;
struct afb_event_listener_itf
{
@@ -39,24 +31,11 @@ struct afb_event_listener
void *closure;
};
-struct afb_event_listener_list;
-
-struct AFB_clientCtx
-{
- int created;
- unsigned refcount;
- time_t expiration; // expiration time of the token
- struct afb_context *contexts;
- char uuid[37]; // long term authentication of remote client
- char token[37]; // short term authentication of remote client
- struct afb_event_listener_list *listeners;
-};
-
extern void ctxStoreInit (int max_session_count, int timeout, const char *initok, int context_count);
-extern struct AFB_clientCtx *ctxClientGetForUuid (const char *uuid);
-extern struct AFB_clientCtx *ctxClientGet(struct AFB_clientCtx *clientCtx);
-extern void ctxClientPut(struct AFB_clientCtx *clientCtx);
+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 ctxClientEventListenerAdd(struct AFB_clientCtx *clientCtx, struct afb_event_listener listener);
@@ -64,6 +43,11 @@ extern void ctxClientEventListenerRemove(struct AFB_clientCtx *clientCtx, struct
extern int ctxClientEventSend(struct AFB_clientCtx *clientCtx, const char *event, struct json_object *object);
extern int ctxTokenCheck (struct AFB_clientCtx *clientCtx, const char *token);
-extern int ctxTokenCheckLen (struct AFB_clientCtx *clientCtx, const char *token, size_t length);
extern void ctxTokenNew (struct AFB_clientCtx *clientCtx);
+extern const char *ctxClientGetUuid (struct AFB_clientCtx *clientCtx);
+extern const char *ctxClientGetToken (struct AFB_clientCtx *clientCtx);
+
+extern void *ctxClientValueGet(struct AFB_clientCtx *clientCtx, int index);
+extern void ctxClientValueSet(struct AFB_clientCtx *clientCtx, int index, void *value, void (*free_value)(void*));
+