Introduce apiset for grouping apis
authorJosé Bollo <jose.bollo@iot.bzh>
Thu, 13 Apr 2017 20:58:33 +0000 (22:58 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Thu, 13 Apr 2017 21:02:25 +0000 (23:02 +0200)
This will be used at the end for debugging
facilities.

Change-Id: I75e3345667e1f58143c77a885e166375680ca194
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
30 files changed:
src/CMakeLists.txt
src/afb-api-dbus.c
src/afb-api-dbus.h
src/afb-api-so-v1.c
src/afb-api-so-v1.h
src/afb-api-so-v2.c
src/afb-api-so-v2.h
src/afb-api-so.c
src/afb-api-so.h
src/afb-api-ws.c
src/afb-api-ws.h
src/afb-api.c [new file with mode: 0644]
src/afb-api.h [moved from src/afb-apis.h with 60% similarity]
src/afb-apiset.c [moved from src/afb-apis.c with 53% similarity]
src/afb-apiset.h [new file with mode: 0644]
src/afb-ditf.h
src/afb-hreq.c
src/afb-hreq.h
src/afb-hswitch.c
src/afb-hswitch.h
src/afb-subcall.c
src/afb-svc.c
src/afb-svc.h
src/afb-websock.c
src/afb-websock.h
src/afb-ws-json1.c
src/afb-ws-json1.h
src/afb-xreq.c
src/afb-xreq.h
src/main.c

index 6956d0d..3b1f145 100644 (file)
@@ -56,12 +56,13 @@ INCLUDE_DIRECTORIES(
 )
 
 ADD_LIBRARY(afb-lib STATIC
+       afb-api.c
        afb-api-dbus.c
        afb-api-so.c
        afb-api-so-v1.c
        afb-api-so-v2.c
        afb-api-ws.c
-       afb-apis.c
+       afb-apiset.c
        afb-common.c
        afb-config.c
        afb-context.c
index 13cbf7d..2f4c4ca 100644 (file)
@@ -32,8 +32,9 @@
 
 #include "afb-session.h"
 #include "afb-msg-json.h"
-#include "afb-apis.h"
-#include "afb-api-so.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-api-dbus.h"
 #include "afb-context.h"
 #include "afb-cred.h"
 #include "afb-evt.h"
@@ -69,6 +70,7 @@ struct api_dbus
                        struct sd_bus_slot *slot_call;
                        struct afb_evt_listener *listener; /* listener for broadcasted events */
                        struct origin *origins;
+                       struct afb_apiset *apiset;
                } server;
        };
 };
@@ -110,7 +112,7 @@ static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pat
                goto error2;
        }
        api->api++;
-       if (!afb_apis_is_valid_api_name(api->api)) {
+       if (!afb_api_is_valid_name(api->api)) {
                errno = EINVAL;
                goto error2;
        }
@@ -358,19 +360,6 @@ end:
        sd_bus_message_unref(msg);
 }
 
-static int api_dbus_service_start(void *closure, int share_session, int onneed)
-{
-       struct api_dbus *api = closure;
-
-       /* not an error when onneed */
-       if (onneed != 0)
-               return 0;
-
-       /* already started: it is an error */
-       ERROR("The Dbus binding %s is not a startable service", api->name);
-       return -1;
-}
-
 /* receives broadcasted events */
 static int api_dbus_client_on_broadcast_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
 {
@@ -578,12 +567,11 @@ static int api_dbus_client_on_manage_event(sd_bus_message *m, void *userdata, sd
 }
 
 static struct afb_api_itf dbus_api_itf = {
-       .call = api_dbus_client_call,
-       .service_start = api_dbus_service_start
+       .call = api_dbus_client_call
 };
 
 /* adds a afb-dbus-service client api */
-int afb_api_dbus_add_client(const char *path)
+int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset)
 {
        int rc;
        struct api_dbus *api;
@@ -621,7 +609,7 @@ int afb_api_dbus_add_client(const char *path)
        /* record it as an API */
        afb_api.closure = api;
        afb_api.itf = &dbus_api_itf;
-       if (afb_apis_add(api->api, afb_api) < 0)
+       if (afb_apiset_add(apiset, api->api, afb_api) < 0)
                goto error2;
 
        return 0;
@@ -997,8 +985,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd
        dreq->listener = listener;
        dreq->xreq.api = api->api;
        dreq->xreq.verb = method;
-       afb_apis_call(&dreq->xreq);
-       afb_xreq_unref(&dreq->xreq);
+       afb_xreq_process(&dreq->xreq, api->server.apiset);
        return 1;
 
 out_of_memory:
@@ -1009,7 +996,7 @@ error:
 }
 
 /* create the service */
-int afb_api_dbus_add_server(const char *path)
+int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset)
 {
        int rc;
        struct api_dbus *api;
@@ -1037,6 +1024,7 @@ int afb_api_dbus_add_server(const char *path)
        INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
 
        api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api);
+       api->server.apiset = afb_apiset_addref(apiset);
        return 0;
 error3:
        sd_bus_release_name(api->sdbus, api->name);
index b4c2da8..221b52d 100644 (file)
 
 struct afb_req_itf;
 
-extern const struct afb_req_itf afb_api_dbus_req_itf;
+extern int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset);
 
-extern int afb_api_dbus_add_client(const char *path);
-
-extern int afb_api_dbus_add_server(const char *path);
+extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset);
 
 
index 4ec378e..8c4ea48 100644 (file)
@@ -24,7 +24,8 @@
 
 #include <afb/afb-binding.h>
 
-#include "afb-apis.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
 #include "afb-svc.h"
 #include "afb-evt.h"
 #include "afb-common.h"
@@ -70,10 +71,10 @@ static void call_cb(void *closure, struct afb_xreq *xreq)
        if (!verb)
                afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->verb, desc->binding->v1.prefix);
        else
-               afb_xreq_call(xreq, verb->session, verb->callback);
+               afb_xreq_so_call(xreq, verb->session, verb->callback);
 }
 
-static int service_start_cb(void *closure, int share_session, int onneed)
+static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
 {
        int (*init)(struct afb_service service);
        void (*onevent)(const char *event, struct json_object *object);
@@ -105,7 +106,7 @@ static int service_start_cb(void *closure, int share_session, int onneed)
 
        /* get the event handler if any */
        onevent = dlsym(desc->handle, afb_api_so_v1_service_event);
-       desc->service = afb_svc_create(share_session, init, onevent);
+       desc->service = afb_svc_create(apiset, share_session, init, onevent);
        if (desc->service == NULL) {
                /* starting error */
                ERROR("Starting service %s failed", desc->binding->v1.prefix);
@@ -141,7 +142,7 @@ static struct afb_api_itf so_v1_api_itf = {
        .set_verbosity = set_verbosity_cb
 };
 
-int afb_api_so_v1_add(const char *path, void *handle)
+int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset)
 {
        struct api_so_v1 *desc;
        struct afb_binding *(*register_function) (const struct afb_binding_interface *interface);
@@ -181,7 +182,7 @@ int afb_api_so_v1_add(const char *path, void *handle)
                ERROR("binding [%s] bad prefix...", path);
                goto error2;
        }
-       if (!afb_apis_is_valid_api_name(desc->binding->v1.prefix)) {
+       if (!afb_api_is_valid_name(desc->binding->v1.prefix)) {
                ERROR("binding [%s] invalid prefix...", path);
                goto error2;
        }
@@ -198,7 +199,7 @@ int afb_api_so_v1_add(const char *path, void *handle)
        afb_ditf_rename(&desc->ditf, desc->binding->v1.prefix);
        afb_api.closure = desc;
        afb_api.itf = &so_v1_api_itf;
-       if (afb_apis_add(desc->binding->v1.prefix, afb_api) < 0) {
+       if (afb_apiset_add(apiset, desc->binding->v1.prefix, afb_api) < 0) {
                ERROR("binding [%s] can't be registered...", path);
                goto error2;
        }
index d89ad60..be8f840 100644 (file)
@@ -18,4 +18,4 @@
 
 #pragma once
 
-extern int afb_api_so_v1_add(const char *path, void *handle);
+extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset);
index 714bcd0..2d939fb 100644 (file)
@@ -24,7 +24,8 @@
 
 #include <afb/afb-binding.h>
 
-#include "afb-apis.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
 #include "afb-svc.h"
 #include "afb-ditf.h"
 #include "afb-evt.h"
@@ -68,10 +69,10 @@ static void call_cb(void *closure, struct afb_xreq *xreq)
        if (!verb)
                afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->verb, desc->binding->api);
        else
-               afb_xreq_call(xreq, verb->session, verb->callback);
+               afb_xreq_so_call(xreq, verb->session, verb->callback);
 }
 
-static int service_start_cb(void *closure, int share_session, int onneed)
+static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset)
 {
        int (*start)(const struct afb_binding_interface *interface, struct afb_service service);
        void (*onevent)(const char *event, struct json_object *object);
@@ -103,7 +104,7 @@ static int service_start_cb(void *closure, int share_session, int onneed)
 
        /* get the event handler if any */
        onevent = desc->binding->onevent;
-       desc->service = afb_svc_create_v2(share_session, onevent, start, &desc->ditf.interface);
+       desc->service = afb_svc_create_v2(apiset, share_session, onevent, start, &desc->ditf.interface);
        if (desc->service == NULL) {
                /* starting error */
                ERROR("Starting service %s failed", desc->binding->api);
@@ -139,7 +140,7 @@ static struct afb_api_itf so_v2_api_itf = {
        .set_verbosity = set_verbosity_cb
 };
 
-int afb_api_so_v2_add(const char *path, void *handle)
+int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset)
 {
        int rc;
        struct api_so_v2 *desc;
@@ -158,7 +159,7 @@ int afb_api_so_v2_add(const char *path, void *handle)
                ERROR("binding [%s] bad api name...", path);
                goto error;
        }
-       if (!afb_apis_is_valid_api_name(binding->api)) {
+       if (!afb_api_is_valid_name(binding->api)) {
                ERROR("binding [%s] invalid api name...", path);
                goto error;
        }
@@ -198,7 +199,7 @@ int afb_api_so_v2_add(const char *path, void *handle)
        /* records the binding */
        afb_api.closure = desc;
        afb_api.itf = &so_v2_api_itf;
-       if (afb_apis_add(binding->api, afb_api) < 0) {
+       if (afb_apiset_add(apiset, binding->api, afb_api) < 0) {
                ERROR("binding [%s] can't be registered...", path);
                goto error2;
        }
index 7305db4..2807897 100644 (file)
@@ -18,4 +18,4 @@
 
 #pragma once
 
-extern int afb_api_so_v2_add(const char *path, void *handle);
+extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset);
index a22e444..4b8f070 100644 (file)
@@ -30,7 +30,7 @@
 #include "afb-api-so-v2.h"
 #include "verbose.h"
 
-static int load_binding(const char *path, int force)
+static int load_binding(const char *path, int force, struct afb_apiset *apiset)
 {
        int rc;
        void *handle;
@@ -47,12 +47,12 @@ static int load_binding(const char *path, int force)
        }
 
        /* retrieves the register function */
-       rc = afb_api_so_v2_add(path, handle);
+       rc = afb_api_so_v2_add(path, handle, apiset);
        if (rc < 0) {
                /* error when loading a valid v2 binding */
                goto error2;
        }
-       rc = afb_api_so_v1_add(path, handle);
+       rc = afb_api_so_v1_add(path, handle, apiset);
        if (rc < 0) {
                /* error when loading a valid v1 binding */
                goto error2;
@@ -74,12 +74,12 @@ error:
 }
 
 
-int afb_api_so_add_binding(const char *path)
+int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset)
 {
-       return load_binding(path, 1);
+       return load_binding(path, 1, apiset);
 }
 
-static int adddirs(char path[PATH_MAX], size_t end)
+static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset)
 {
        DIR *dir;
        struct dirent *dent;
@@ -119,13 +119,13 @@ static int adddirs(char path[PATH_MAX], size_t end)
                                        continue;
                        }
                        memcpy(&path[end], dent->d_name, len+1);
-                       adddirs(path, end+len);;
+                       adddirs(path, end+len, apiset);
                } else if (dent->d_type == DT_REG) {
                        /* case of files */
                        if (memcmp(&dent->d_name[len - 3], ".so", 4))
                                continue;
                        memcpy(&path[end], dent->d_name, len+1);
-                       if (load_binding(path, 0) < 0)
+                       if (load_binding(path, 0, apiset) < 0)
                                return -1;
                }
        }
@@ -133,7 +133,7 @@ static int adddirs(char path[PATH_MAX], size_t end)
        return 0;
 }
 
-int afb_api_so_add_directory(const char *path)
+int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset)
 {
        size_t length;
        char buffer[PATH_MAX];
@@ -145,10 +145,10 @@ int afb_api_so_add_directory(const char *path)
        }
 
        memcpy(buffer, path, length + 1);
-       return adddirs(buffer, length);
+       return adddirs(buffer, length, apiset);
 }
 
-int afb_api_so_add_path(const char *path)
+int afb_api_so_add_path(const char *path, struct afb_apiset *apiset)
 {
        struct stat st;
        int rc;
@@ -157,15 +157,15 @@ int afb_api_so_add_path(const char *path)
        if (rc < 0)
                ERROR("Invalid binding path [%s]: %m", path);
        else if (S_ISDIR(st.st_mode))
-               rc = afb_api_so_add_directory(path);
+               rc = afb_api_so_add_directory(path, apiset);
        else if (strstr(path, ".so"))
-               rc = load_binding(path, 0);
+               rc = load_binding(path, 0, apiset);
        else
                INFO("not a binding [%s], skipped", path);
        return rc;
 }
 
-int afb_api_so_add_pathset(const char *pathset)
+int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset)
 {
        static char sep[] = ":";
        char *ps, *p;
@@ -175,7 +175,7 @@ int afb_api_so_add_pathset(const char *pathset)
                p = strsep(&ps, sep);
                if (!p)
                        return 0;
-               if (afb_api_so_add_path(p) < 0)
+               if (afb_api_so_add_path(p, apiset) < 0)
                        return -1;
        }
 }
index fcf66cc..382dad0 100644 (file)
 
 #pragma once
 
-extern int afb_api_so_add_binding(const char *path);
+struct afb_apiset;
 
-extern int afb_api_so_add_directory(const char *path);
+extern int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset);
 
-extern int afb_api_so_add_path(const char *path);
+extern int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset);
 
-extern int afb_api_so_add_pathset(const char *pathset);
+extern int afb_api_so_add_path(const char *path, struct afb_apiset *apiset);
+
+extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset);
 
 
index ea0781d..b03ef66 100644 (file)
@@ -42,7 +42,8 @@
 #include "afb-cred.h"
 #include "afb-ws.h"
 #include "afb-msg-json.h"
-#include "afb-apis.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
 #include "afb-api-so.h"
 #include "afb-context.h"
 #include "afb-evt.h"
@@ -83,6 +84,7 @@ struct api_ws
                } client;
                struct {
                        sd_event_source *listensrc; /**< systemd source for server socket */
+                       struct afb_apiset *apiset;
                } server;
        };
 };
@@ -169,6 +171,9 @@ struct api_ws_client
 
        /* pending subcalls */
        struct api_ws_subcall *subcalls;
+
+       /* apiset */
+       struct afb_apiset *apiset;
 };
 
 /******************* websocket interface for client part **********************************/
@@ -238,7 +243,7 @@ static struct api_ws *api_ws_make(const char *path)
        while (length && path[length - 1] != '/' && path[length - 1] != ':')
                length = length - 1;
        api->api = &api->path[length];
-       if (api->api == NULL || !afb_apis_is_valid_api_name(api->api)) {
+       if (api->api == NULL || !afb_api_is_valid_name(api->api)) {
                errno = EINVAL;
                goto error2;
        }
@@ -931,19 +936,6 @@ end:
        pthread_mutex_unlock(&apiws->mutex);
 }
 
-static int api_ws_service_start_cb(void *closure, int share_session, int onneed)
-{
-       struct api_ws *api = closure;
-
-       /* not an error when onneed */
-       if (onneed != 0)
-               return 0;
-
-       /* already started: it is an error */
-       ERROR("The WS binding %s is not a startable service", api->path);
-       return -1;
-}
-
 /*  */
 static void api_ws_client_disconnect(struct api_ws *api)
 {
@@ -975,12 +967,11 @@ static int api_ws_client_connect(struct api_ws *api)
 }
 
 static struct afb_api_itf ws_api_itf = {
-       .call = api_ws_client_call_cb,
-       .service_start = api_ws_service_start_cb
+       .call = api_ws_client_call_cb
 };
 
 /* adds a afb-ws-service client api */
-int afb_api_ws_add_client(const char *path)
+int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset)
 {
        int rc;
        struct api_ws *api;
@@ -1001,7 +992,7 @@ int afb_api_ws_add_client(const char *path)
        /* record it as an API */
        afb_api.closure = api;
        afb_api.itf = &ws_api_itf;
-       if (afb_apis_add(api->api, afb_api) < 0)
+       if (afb_apiset_add(apiset, api->api, afb_api) < 0)
                goto error3;
 
        return 0;
@@ -1031,6 +1022,7 @@ static void api_ws_server_client_unref(struct api_ws_client *client)
                        free(sc);
                }
                afb_cred_unref(client->cred);
+               afb_apiset_unref(client->apiset);
                free(client);
        }
 }
@@ -1081,8 +1073,7 @@ static void api_ws_server_on_call(struct api_ws_client *client, struct readbuf *
        wreq->xreq.api = client->api;
        wreq->xreq.verb = cverb;
        wreq->xreq.json = object;
-       afb_apis_call(&wreq->xreq);
-       afb_xreq_unref(&wreq->xreq);
+       afb_xreq_process(&wreq->xreq, client->apiset);
        return;
 
 unconnected:
@@ -1180,6 +1171,7 @@ static void api_ws_server_accept(struct api_ws *api)
                                client->ws = afb_ws_create(afb_common_get_event_loop(), client->fd, &api_ws_server_ws_itf, client);
                                if (client->ws != NULL) {
                                        client->api = api->api;
+                                       client->apiset = afb_apiset_addref(api->server.apiset);
                                        client->refcount = 1;
                                        client->subcalls = NULL;
                                        return;
@@ -1429,7 +1421,7 @@ static int api_ws_server_connect(struct api_ws *api)
 }
 
 /* create the service */
-int afb_api_ws_add_server(const char *path)
+int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset)
 {
        int rc;
        struct api_ws *api;
@@ -1444,6 +1436,7 @@ int afb_api_ws_add_server(const char *path)
        if (rc < 0)
                goto error2;
 
+       api->server.apiset = afb_apiset_addref(apiset);
        return 0;
 
 error2:
index 9da4e01..831d5ea 100644 (file)
 
 struct afb_req_itf;
 
-extern const struct afb_req_itf afb_api_ws_req_itf;
+extern int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset);
 
-extern int afb_api_ws_add_client(const char *path);
-
-extern int afb_api_ws_add_server(const char *path);
+extern int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset);
 
 
diff --git a/src/afb-api.c b/src/afb-api.c
new file mode 100644 (file)
index 0000000..bb172d7
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include "afb-api.h"
+
+/**
+ * Checks wether 'name' is a valid API name.
+ * @return 1 if valid, 0 otherwise
+ */
+int afb_api_is_valid_name(const char *name)
+{
+       unsigned char c;
+
+       c = (unsigned char)*name;
+       if (c == 0)
+               /* empty names aren't valid */
+               return 0;
+
+       do {
+               if (c < (unsigned char)'\x80') {
+                       switch(c) {
+                       default:
+                               if (c > ' ')
+                                       break;
+                       case '"':
+                       case '#':
+                       case '%':
+                       case '&':
+                       case '\'':
+                       case '/':
+                       case '?':
+                       case '`':
+                       case '\\':
+                       case '\x7f':
+                               return 0;
+                       }
+               }
+               c = (unsigned char)*++name;
+       } while(c != 0);
+       return 1;
+}
+
similarity index 60%
rename from src/afb-apis.h
rename to src/afb-api.h
index 0254466..6dfbf02 100644 (file)
 
 #pragma once
 
-struct afb_req;
-struct afb_context;
 struct afb_xreq;
+struct afb_apiset;
 
 struct afb_api_itf
 {
        void (*call)(void *closure, struct afb_xreq *xreq);
-       int (*service_start)(void *closure, int share_session, int onneed);
+       int (*service_start)(void *closure, int share_session, int onneed, struct afb_apiset *apiset);
        void (*update_hooks)(void *closure);
        int (*get_verbosity)(void *closure);
        void (*set_verbosity)(void *closure, int level);
@@ -36,21 +35,4 @@ struct afb_api
        struct afb_api_itf *itf;
 };
 
-extern void afb_apis_set_timeout(int to);
-
-extern int afb_apis_is_valid_api_name(const char *name);
-
-extern int afb_apis_add(const char *name, struct afb_api api);
-
-extern int afb_apis_start_all_services(int share_session);
-extern int afb_apis_start_service(const char *name, int share_session, int onneed);
-
-extern void afb_apis_call(struct afb_xreq *xreq);
-extern void afb_apis_call_direct(struct afb_xreq *xreq);
-
-extern void afb_apis_update_hooks(const char *api);
-
-extern void afb_apis_set_verbosity(const char *api, int level);
-extern int afb_apis_get_verbosity(const char *api);
-extern const char **afb_apis_get_names();
-
+extern int afb_api_is_valid_name(const char *name);
similarity index 53%
rename from src/afb-apis.c
rename to src/afb-apiset.c
index 6e09355..d9a4e5e 100644 (file)
 
 #include "afb-session.h"
 #include "verbose.h"
-#include "afb-apis.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
 #include "afb-context.h"
 #include "afb-xreq.h"
 #include "jobs.h"
 
 #include <afb/afb-req-itf.h>
 
+#define INCR 8         /* CAUTION: must be a power of 2 */
+
 /**
  * Internal description of an api
  */
@@ -40,24 +43,58 @@ struct api_desc {
        struct afb_api api;     /**< handler of the api */
 };
 
-static struct api_desc *apis_array = NULL;
-static int apis_count = 0;
-static int apis_timeout = 15;
+struct afb_apiset
+{
+       struct afb_apiset *subset;
+       struct api_desc *apis;
+       int count;
+       int timeout;
+       int refcount;
+       char name[1];
+};
 
 /**
- * Set the API timeout
- * @param to the timeout in seconds
+ * Search the api of 'name'.
+ * @param set the api set
+ * @param name the api name to search
+ * @return the descriptor if found or NULL otherwise
  */
-void afb_apis_set_timeout(int to)
+static const struct api_desc *search(struct afb_apiset *set, const char *name)
 {
-       apis_timeout = to;
+       int i, c, up, lo;
+       const struct api_desc *a;
+
+       /* dichotomic search of the api */
+       /* initial slice */
+       lo = 0;
+       up = set->count;
+       for (;;) {
+               /* check remaining slice */
+               if (lo >= up) {
+                       /* not found */
+                       return NULL;
+               }
+               /* check the mid of the slice */
+               i = (lo + up) >> 1;
+               a = &set->apis[i];
+               c = strcasecmp(a->name, name);
+               if (c == 0) {
+                       /* found */
+                       return a;
+               }
+               /* update the slice */
+               if (c < 0)
+                       lo = i + 1;
+               else
+                       up = i;
+       }
 }
 
 /**
  * Checks wether 'name' is a valid API name.
  * @return 1 if valid, 0 otherwise
  */
-int afb_apis_is_valid_api_name(const char *name)
+int afb_apiset_valid_name(const char *name)
 {
        unsigned char c;
 
@@ -90,8 +127,90 @@ int afb_apis_is_valid_api_name(const char *name)
        return 1;
 }
 
+struct afb_apiset *afb_apiset_addref(struct afb_apiset *set)
+{
+       if (set)
+               __atomic_add_fetch(&set->refcount, 1, __ATOMIC_RELAXED);
+       return set;
+}
+
+void afb_apiset_unref(struct afb_apiset *set)
+{
+       if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) {
+               afb_apiset_unref(set->subset);
+               free(set->apis);
+               free(set);
+       }
+}
+
+/**
+ * Create an apiset
+ */
+struct afb_apiset *afb_apiset_create(const char *name, int timeout, struct afb_apiset *subset)
+{
+       struct afb_apiset *set;
+
+       set = malloc((name ? strlen(name) : 0) + sizeof *set);
+       if (set) {
+               set->subset = afb_apiset_addref(subset);
+               set->apis = malloc(INCR * sizeof *set->apis);
+               set->count = 0;
+               set->timeout = timeout;
+               set->refcount = 1;
+               if (name)
+                       strcpy(set->name, name);
+               else
+                       set->name[0] = 0;
+       }
+       return set;
+}
+
+
+/**
+ * Get the API timeout of the set
+ * @param set the api set
+ * @return the timeout in seconds
+ */
+int afb_apiset_get_timeout(struct afb_apiset *set)
+{
+       return set->timeout;
+}
+
+/**
+ * Set the API timeout of the set
+ * @param set the api set
+ * @param to the timeout in seconds
+ */
+void afb_apiset_set_timeout(struct afb_apiset *set, int to)
+{
+       set->timeout = to;
+}
+
+/**
+ * Get the subset of the set
+ * @param set the api set
+ * @return the subset of set
+ */
+struct afb_apiset *afb_apiset_get_subset(struct afb_apiset *set)
+{
+       return set->subset;
+}
+
+/**
+ * Set the subset of the set
+ * @param set the api set
+ * @param subset the subset to set
+ */
+void afb_apiset_set_subset(struct afb_apiset *set, struct afb_apiset *subset)
+{
+       struct afb_apiset *tmp = set->subset;
+       set->subset = afb_apiset_addref(subset);
+       afb_apiset_unref(tmp);
+}
+
 /**
  * Adds the api of 'name' described by 'api'.
+ * @param set the api set
  * @param name the name of the api to add (have to survive, not copied!)
  * @param api the api
  * @returns 0 in case of success or -1 in case
@@ -100,21 +219,21 @@ int afb_apis_is_valid_api_name(const char *name)
  *   - EEXIST if name already registered
  *   - ENOMEM when out of memory
  */
-int afb_apis_add(const char *name, struct afb_api api)
+int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api)
 {
        struct api_desc *apis;
        int i, c;
 
        /* Checks the api name */
-       if (!afb_apis_is_valid_api_name(name)) {
+       if (!afb_apiset_valid_name(name)) {
                ERROR("invalid api name forbidden (name is '%s')", name);
                errno = EINVAL;
                goto error;
        }
 
        /* check previously existing plugin */
-       for (i = 0 ; i < apis_count ; i++) {
-               c = strcasecmp(apis_array[i].name, name);
+       for (i = 0 ; i < set->count ; i++) {
+               c = strcasecmp(set->apis[i].name, name);
                if (c == 0) {
                        ERROR("api of name %s already exists", name);
                        errno = EEXIST;
@@ -125,26 +244,24 @@ int afb_apis_add(const char *name, struct afb_api api)
        }
 
        /* allocates enough memory */
-       apis = realloc(apis_array, ((unsigned)apis_count + 1) * sizeof * apis);
+       c = (set->count + INCR) & ~(INCR - 1);
+       apis = realloc(set->apis, ((unsigned)c) * sizeof * apis);
        if (apis == NULL) {
                ERROR("out of memory");
                errno = ENOMEM;
                goto error;
        }
-       apis_array = apis;
+       set->apis = apis;
 
        /* copy higher part of the array */
-       c = apis_count;
-       while (c > i) {
-               apis_array[c] = apis_array[c - 1];
-               c--;
-       }
+       apis += i;
+       if (i != set->count)
+               memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis);
 
        /* record the plugin */
-       apis = &apis_array[i];
        apis->api = api;
        apis->name = name;
-       apis_count++;
+       set->count++;
 
        NOTICE("API %s added", name);
 
@@ -154,158 +271,116 @@ error:
        return -1;
 }
 
-/**
- * Search the 'api'.
- * @param api the api of the verb
- * @return the descriptor if found or NULL otherwise
- */
-static const struct api_desc *search(const char *api)
+int afb_apiset_del(struct afb_apiset *set, const char *name)
 {
-       int i, c, up, lo;
-       const struct api_desc *a;
+       int i, c;
 
-       /* dichotomic search of the api */
-       /* initial slice */
-       lo = 0;
-       up = apis_count;
-       for (;;) {
-               /* check remaining slice */
-               if (lo >= up) {
-                       /* not found */
-                       return NULL;
-               }
-               /* check the mid of the slice */
-               i = (lo + up) >> 1;
-               a = &apis_array[i];
-               c = strcasecmp(a->name, api);
+       /* search the api */
+       for (i = 0 ; i < set->count ; i++) {
+               c = strcasecmp(set->apis[i].name, name);
                if (c == 0) {
-                       /* found */
-                       return a;
+                       set->count--;
+                       while(i < set->count) {
+                               set->apis[i] = set->apis[i + 1];
+                               i++;
+                       }
+                       return 0;
                }
-               /* update the slice */
-               if (c < 0)
-                       lo = i + 1;
-               else
-                       up = i;
+               if (c > 0)
+                       break;
        }
+       errno = ENOENT;
+       return -1;
 }
 
-/**
- * Starts a service by its 'api' name.
- * @param api name of the service to start
- * @param share_session if true start the servic"e in a shared session
- *                      if false start it in its own session
- * @param onneed if true start the service if possible, if false the api
- *               must be a service
- * @return a positive number on success
- */
-int afb_apis_start_service(const char *api, int share_session, int onneed)
+int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api)
 {
-       int i;
+       const struct api_desc *i;
 
-       for (i = 0 ; i < apis_count ; i++) {
-               if (!strcasecmp(apis_array[i].name, api))
-                       return apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, onneed);
+       i = search(set, name);
+       if (i) {
+               *api = i->api;
+               return 0;
        }
-       ERROR("can't find service %s", api);
+       if (set->subset)
+               return afb_apiset_get(set->subset, name, api);
+
        errno = ENOENT;
        return -1;
 }
 
 /**
- * Starts all possible services but stops at first error.
+ * Starts a service by its 'api' name.
+ * @param set the api set
+ * @param name name of the service to start
  * @param share_session if true start the servic"e in a shared session
  *                      if false start it in its own session
- * @return 0 on success or a negative number when an error is found
- */
-int afb_apis_start_all_services(int share_session)
-{
-       int i, rc;
-
-       for (i = 0 ; i < apis_count ; i++) {
-               rc = apis_array[i].api.itf->service_start(apis_array[i].api.closure, share_session, 1);
-               if (rc < 0)
-                       return rc;
-       }
-       return 0;
-}
-
-/**
- * Internal direct dispatch of the request 'xreq'
- * @param xreq the request to dispatch
+ * @param onneed if true start the service if possible, if false the api
+ *               must be a service
+ * @return a positive number on success
  */
-static void do_call_direct(struct afb_xreq *xreq)
+int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed)
 {
        const struct api_desc *a;
 
-       /* search the api */
-       a = search(xreq->api);
-       if (!a)
-               afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api);
-       else {
-               xreq->context.api_key = a->api.closure;
-               a->api.itf->call(a->api.closure, xreq);
+       a = search(set, name);
+       if (!a) {
+               ERROR("can't find service %s", name);
+               errno = ENOENT;
+               return -1;
        }
-}
 
-/**
- * Asynchronous dispatch callback for the request 'xreq'
- * @param signum 0 on normal flow or the signal number that interupted the normal flow
- */
-static void do_call_async(int signum, void *arg)
-{
-       struct afb_xreq *xreq = arg;
+       if (a->api.itf->service_start)
+               return a->api.itf->service_start(a->api.closure, share_session, onneed, set);
 
-       if (signum != 0)
-               afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
-       else {
-               do_call_direct(xreq);
-       }
-       afb_xreq_unref(xreq);
-}
+       if (onneed)
+               return 0;
 
-/**
- * Dispatch the request 'xreq' synchronously and directly.
- * @param xreq the request to dispatch
- */
-void afb_apis_call_direct(struct afb_xreq *xreq)
-{
-       afb_xreq_begin(xreq);
-       do_call_direct(xreq);
+       /* already started: it is an error */
+       ERROR("The api %s is not a startable service", name);
+       errno = EINVAL;
+       return -1;
 }
 
 /**
- * Dispatch the request 'xreq' asynchronously.
- * @param xreq the request to dispatch
+ * Starts all possible services but stops at first error.
+ * @param set the api set
+ * @param share_session if true start the servic"e in a shared session
+ *                      if false start it in its own session
+ * @return 0 on success or a negative number when an error is found
  */
-void afb_apis_call(struct afb_xreq *xreq)
+int afb_apiset_start_all_services(struct afb_apiset *set, int share_session)
 {
        int rc;
+       const struct api_desc *i, *e;
 
-       afb_xreq_begin(xreq);
-       afb_xreq_addref(xreq);
-       rc = jobs_queue(NULL, apis_timeout, do_call_async, xreq);
-       if (rc < 0) {
-               /* TODO: allows or not to proccess it directly as when no threading? (see above) */
-               ERROR("can't process job with threads: %m");
-               afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task");
-               afb_xreq_unref(xreq);
+       i = set->apis;
+       e = &set->apis[set->count];
+       while (i != e) {
+               if (i->api.itf->service_start) {
+                       rc = i->api.itf->service_start(i->api.closure, share_session, 1, set);
+                       if (rc < 0)
+                               return rc;
+               }
+               i++;
        }
+       return 0;
 }
 
 /**
  * Ask to update the hook flags of the 'api'
- * @param api the api to update (NULL updates all)
+ * @param set the api set
+ * @param name the api to update (NULL updates all)
  */
-void afb_apis_update_hooks(const char *api)
+void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
 {
        const struct api_desc *i, *e;
 
-       if (!api) {
-               i = apis_array;
-               e = &apis_array[apis_count];
+       if (!name) {
+               i = set->apis;
+               e = &set->apis[set->count];
        } else {
-               i = search(api);
+               i = search(set, name);
                e = &i[!!i];
        }
        while (i != e) {
@@ -317,17 +392,18 @@ void afb_apis_update_hooks(const char *api)
 
 /**
  * Set the verbosity level of the 'api'
- * @param api the api to set (NULL set all)
+ * @param set the api set
+ * @param name the api to set (NULL set all)
  */
-void afb_apis_set_verbosity(const char *api, int level)
+void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level)
 {
        const struct api_desc *i, *e;
 
-       if (!api) {
-               i = apis_array;
-               e = &apis_array[apis_count];
+       if (!name) {
+               i = set->apis;
+               e = &set->apis[set->count];
        } else {
-               i = search(api);
+               i = search(set, name);
                e = &i[!!i];
        }
        while (i != e) {
@@ -339,13 +415,14 @@ void afb_apis_set_verbosity(const char *api, int level)
 
 /**
  * Set the verbosity level of the 'api'
- * @param api the api to set (NULL set all)
+ * @param set the api set
+ * @param name the api to set (NULL set all)
  */
-int afb_apis_get_verbosity(const char *api)
+int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name)
 {
        const struct api_desc *i;
 
-       i = api ? search(api) : NULL;
+       i = name ? search(set, name) : NULL;
        if (!i) {
                errno = ENOENT;
                return -1;
@@ -358,30 +435,105 @@ int afb_apis_get_verbosity(const char *api)
 
 /**
  * Get the list of api names
+ * @param set the api set
  * @return a NULL terminated array of api names. Must be freed.
  */
-const char **afb_apis_get_names()
+const char **afb_apiset_get_names(struct afb_apiset *set)
 {
        size_t size;
        char *dest;
        const char **names;
        int i;
 
-       size = apis_count * (1 + sizeof(*names)) + sizeof(*names);
-       for (i = 0 ; i < apis_count ; i++)
-               size += strlen(apis_array[i].name);
+       size = set->count * (1 + sizeof(*names)) + sizeof(*names);
+       for (i = 0 ; i < set->count ; i++)
+               size += strlen(set->apis[i].name);
 
        names = malloc(size);
        if (!names)
                errno = ENOMEM;
        else {
-               dest = (void*)&names[apis_count+1];
-               for (i = 0 ; i < apis_count ; i++) {
+               dest = (void*)&names[set->count+1];
+               for (i = 0 ; i < set->count ; i++) {
                        names[i] = dest;
-                       dest = stpcpy(dest, apis_array[i].name) + 1;
+                       dest = stpcpy(dest, set->apis[i].name) + 1;
                }
                names[i] = NULL;
        }
        return names;
 }
 
+
+#if 0
+
+
+
+/**
+ * Internal direct dispatch of the request 'xreq'
+ * @param set the api set
+ * @param xreq the request to dispatch
+ */
+static void do_call_direct(struct afb_xreq *xreq)
+{
+       const struct api_desc *a;
+
+       /* search the api */
+       a = search(xreq->api);
+       if (!a)
+               afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api);
+       else {
+               xreq->context.api_key = a->api.closure;
+               a->api.itf->call(a->api.closure, xreq);
+       }
+}
+
+/**
+ * Asynchronous dispatch callback for the request 'xreq'
+ * @param set the api set
+ * @param signum 0 on normal flow or the signal number that interupted the normal flow
+ */
+static void do_call_async(int signum, void *arg)
+{
+       struct afb_xreq *xreq = arg;
+
+       if (signum != 0)
+               afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
+       else {
+               do_call_direct(xreq);
+       }
+       afb_xreq_unref(xreq);
+}
+
+/**
+ * Dispatch the request 'xreq' synchronously and directly.
+ * @param set the api set
+ * @param xreq the request to dispatch
+ */
+void afb_apiset_call_direct(struct afb_apiset *set, struct afb_xreq *xreq)
+{
+       afb_xreq_begin(xreq);
+       do_call_direct(xreq);
+}
+
+/**
+ * Dispatch the request 'xreq' asynchronously.
+ * @param set the api set
+ * @param xreq the request to dispatch
+ */
+void afb_apiset_call(struct afb_apiset *set, struct afb_xreq *xreq)
+{
+       int rc;
+
+       afb_xreq_begin(xreq);
+       afb_xreq_addref(xreq);
+       rc = jobs_queue(NULL, apis_timeout, do_call_async, xreq);
+       if (rc < 0) {
+               /* TODO: allows or not to proccess it directly as when no threading? (see above) */
+               ERROR("can't process job with threads: %m");
+               afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task");
+               afb_xreq_unref(xreq);
+       }
+}
+
+#endif
+
diff --git a/src/afb-apiset.h b/src/afb-apiset.h
new file mode 100644 (file)
index 0000000..be7932b
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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 afb_api;
+struct afb_apiset;
+
+extern struct afb_apiset *afb_apiset_addref(struct afb_apiset *set);
+extern void afb_apiset_unref(struct afb_apiset *set);
+extern struct afb_apiset *afb_apiset_create(const char *name, int timeout, struct afb_apiset *subset);
+extern int afb_apiset_get_timeout(struct afb_apiset *set);
+extern void afb_apiset_set_timeout(struct afb_apiset *set, int to);
+extern struct afb_apiset *afb_apiset_get_subset(struct afb_apiset *set);
+extern void afb_apiset_set_subset(struct afb_apiset *set, struct afb_apiset *subset);
+extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api);
+extern int afb_apiset_del(struct afb_apiset *set, const char *name);
+extern int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api);
+extern int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed);
+extern int afb_apiset_start_all_services(struct afb_apiset *set, int share_session);
+extern void afb_apiset_update_hooks(struct afb_apiset *set, const char *name);
+extern void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level);
+extern int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name);
+extern const char **afb_apiset_get_names(struct afb_apiset *set);
+
index ad8c992..3e8d99a 100644 (file)
@@ -24,7 +24,6 @@
 
 #include <afb/afb-binding.h>
 
-#include "afb-apis.h"
 #include "afb-svc.h"
 #include "afb-evt.h"
 #include "afb-common.h"
index 6589f0f..fe5af73 100644 (file)
@@ -910,16 +910,19 @@ static void req_success(struct afb_xreq *xreq, json_object *obj, const char *inf
        req_reply(hreq, MHD_HTTP_OK, "success", info, obj);
 }
 
-int afb_hreq_init_req_call(struct afb_hreq *hreq, const char *api, size_t lenapi, const char *verb, size_t lenverb)
+void afb_hreq_call(struct afb_hreq *hreq, struct afb_apiset *apiset, const char *api, size_t lenapi, const char *verb, size_t lenverb)
 {
        hreq->xreq.api = strndup(api, lenapi);
        hreq->xreq.verb = strndup(verb, lenverb);
        if (hreq->xreq.api == NULL || hreq->xreq.verb == NULL) {
                ERROR("Out of memory");
-               errno = ENOMEM;
-               return -1;
+               afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+       } else if (afb_hreq_init_context(hreq) < 0) {
+               afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
+       } else {
+               afb_xreq_addref(&hreq->xreq); /* TODO check if needed */
+               afb_xreq_process(&hreq->xreq, apiset);
        }
-       return afb_hreq_init_context(hreq);
 }
 
 int afb_hreq_init_context(struct afb_hreq *hreq)
index 47d6aa5..f4c00ff 100644 (file)
@@ -75,7 +75,7 @@ extern int afb_hreq_post_add_file(struct afb_hreq *hreq, const char *name, const
 
 extern int afb_hreq_post_add(struct afb_hreq *hreq, const char *name, const char *data, size_t size);
 
-extern int afb_hreq_init_req_call(struct afb_hreq *hreq, const char *api, size_t lenapi, const char *verb, size_t lenverb);
+extern void afb_hreq_call(struct afb_hreq *hreq, struct afb_apiset *apiset, const char *api, size_t lenapi, const char *verb, size_t lenverb);
 
 extern int afb_hreq_init_context(struct afb_hreq *hreq);
 
index 0eae18f..34eafd5 100644 (file)
@@ -26,7 +26,7 @@
 #include <afb/afb-req-itf.h>
 #include "afb-context.h"
 #include "afb-hreq.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
 #include "afb-session.h"
 #include "afb-websock.h"
 
@@ -34,6 +34,7 @@ int afb_hswitch_apis(struct afb_hreq *hreq, void *data)
 {
        const char *api, *verb;
        size_t lenapi, lenverb;
+       struct afb_apiset *apiset = data;
 
        api = &hreq->tail[strspn(hreq->tail, "/")];
        lenapi = strcspn(api, "/");
@@ -44,10 +45,7 @@ int afb_hswitch_apis(struct afb_hreq *hreq, void *data)
        if (!(*api && *verb && lenapi && lenverb))
                return 0;
 
-       if (afb_hreq_init_req_call(hreq, api, lenapi, verb, lenverb) < 0)
-               afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR);
-       else
-               afb_apis_call(&hreq->xreq);
+       afb_hreq_call(hreq, apiset, api, lenapi, verb, lenverb);
        return 1;
 }
 
@@ -79,6 +77,8 @@ int afb_hswitch_one_page_api_redirect(struct afb_hreq *hreq, void *data)
 
 int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data)
 {
+       struct afb_apiset *apiset = data;
+
        if (hreq->lentail != 0)
                return 0;
 
@@ -92,7 +92,7 @@ int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data)
                return 1;
        }
 
-       return afb_websock_check_upgrade(hreq);
+       return afb_websock_check_upgrade(hreq, apiset);
 }
 
 
index 5177374..7fc8049 100644 (file)
@@ -19,6 +19,7 @@
 #pragma once
 
 struct afb_hreq;
+
 extern int afb_hswitch_apis(struct afb_hreq *hreq, void *data);
 extern int afb_hswitch_one_page_api_redirect(struct afb_hreq *hreq, void *data);
 extern int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data);
index 68b3312..8a8c77a 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "afb-subcall.h"
 #include "afb-msg-json.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
 #include "afb-context.h"
 #include "afb-xreq.h"
 #include "afb-cred.h"
@@ -133,8 +133,7 @@ void afb_subcall(
                return;
        }
 
-       afb_apis_call(&subcall->xreq);
-       afb_xreq_unref(&subcall->xreq);
+       afb_xreq_process(&subcall->xreq, caller->apiset);
 }
 
 struct subcall_sync
index 6b6b0a5..0ae56b8 100644 (file)
@@ -31,7 +31,7 @@
 #include "afb-svc.h"
 #include "afb-xreq.h"
 #include "afb-cred.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
 #include "verbose.h"
 
 /*
@@ -42,6 +42,9 @@ struct afb_svc
        /* session of the service */
        struct afb_session *session;
 
+       /* the apiset for the service */
+       struct afb_apiset *apiset;
+
        /* event listener of the service or NULL */
        struct afb_evt_listener *listener;
 
@@ -93,7 +96,11 @@ static struct afb_session *common_session;
 /*
  * Allocates a new service
  */
-static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const char *event, struct json_object *object))
+static struct afb_svc *afb_svc_alloc(
+                       struct afb_apiset *apiset,
+                       int share_session,
+                       void (*on_event)(const char *event, struct json_object *object)
+)
 {
        struct afb_svc *svc;
 
@@ -102,6 +109,9 @@ static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const c
        if (svc == NULL)
                goto error;
 
+       /* instanciate the apiset */
+       svc->apiset = afb_apiset_addref(apiset);
+
        /* instanciate the session */
        if (share_session) {
                /* session shared with other svcs */
@@ -133,6 +143,7 @@ static struct afb_svc *afb_svc_alloc(int share_session, void (*on_event)(const c
 error3:
        afb_session_unref(svc->session);
 error2:
+       afb_apiset_unref(svc->apiset);
        free(svc);
 error:
        return NULL;
@@ -141,13 +152,18 @@ error:
 /*
  * Creates a new service
  */
-struct afb_svc *afb_svc_create(int share_session, int (*init)(struct afb_service service), void (*on_event)(const char *event, struct json_object *object))
+struct afb_svc *afb_svc_create(
+               struct afb_apiset *apiset,
+               int share_session,
+               int (*init)(struct afb_service service),
+               void (*on_event)(const char *event, struct json_object *object)
+)
 {
        int rc;
        struct afb_svc *svc;
 
        /* allocates the svc handler */
-       svc = afb_svc_alloc(share_session, on_event);
+       svc = afb_svc_alloc(apiset, share_session, on_event);
        if (svc == NULL)
                goto error;
 
@@ -162,6 +178,7 @@ error2:
        if (svc->listener != NULL)
                afb_evt_listener_unref(svc->listener);
        afb_session_unref(svc->session);
+       afb_apiset_unref(svc->apiset);
        free(svc);
 error:
        return NULL;
@@ -171,16 +188,18 @@ error:
  * Creates a new service
  */
 struct afb_svc *afb_svc_create_v2(
+                       struct afb_apiset *apiset,
                        int share_session,
                        void (*on_event)(const char *event, struct json_object *object),
                        int (*start)(const struct afb_binding_interface *interface, struct afb_service service),
-                       const struct afb_binding_interface *interface)
+                       const struct afb_binding_interface *interface
+)
 {
        int rc;
        struct afb_svc *svc;
 
        /* allocates the svc handler */
-       svc = afb_svc_alloc(share_session, on_event);
+       svc = afb_svc_alloc(apiset, share_session, on_event);
        if (svc == NULL)
                goto error;
 
@@ -195,6 +214,7 @@ error2:
        if (svc->listener != NULL)
                afb_evt_listener_unref(svc->listener);
        afb_session_unref(svc->session);
+       afb_apiset_unref(svc->apiset);
        free(svc);
 error:
        return NULL;
@@ -240,8 +260,7 @@ static void svc_call(void *closure, const char *api, const char *verb, struct js
        svcreq->closure = cbclosure;
 
        /* terminates and frees ressources if needed */
-       afb_apis_call(&svcreq->xreq);
-       afb_xreq_unref(&svcreq->xreq);
+       afb_xreq_process(&svcreq->xreq, svc->apiset);
 }
 
 static void svcreq_destroy(struct afb_xreq *xreq)
index 7a1f7c1..0105624 100644 (file)
 
 struct afb_svc;
 struct afb_service;
+struct afb_apiset;
 struct afb_binding_interface;
 
-extern struct afb_svc *afb_svc_create(int share_session,
+extern struct afb_svc *afb_svc_create(
+                       struct afb_apiset *apiset,
+                       int share_session,
                        int (*init)(struct afb_service service),
                        void (*onevent)(const char *event, struct json_object *object));
 
 extern struct afb_svc *afb_svc_create_v2(
+                       struct afb_apiset *apiset,
                        int share_session,
                        void (*on_event)(const char *event, struct json_object *object),
                        int (*start)(const struct afb_binding_interface *interface, struct afb_service service),
index abdcfa1..523ad8f 100644 (file)
@@ -94,7 +94,7 @@ static int headerhas(const char *header, const char *needle)
 struct protodef
 {
        const char *name;
-       void *(*create)(int fd, void *context, void (*cleanup)(void*), void *cleanup_closure);
+       void *(*create)(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure);
 };
 
 static const struct protodef *search_proto(const struct protodef *protodefs, const char *protocols)
@@ -119,7 +119,7 @@ static const struct protodef *search_proto(const struct protodef *protodefs, con
        }
 }
 
-static int check_websocket_upgrade(struct MHD_Connection *con, const struct protodef *protodefs, void *context, void **websock)
+static int check_websocket_upgrade(struct MHD_Connection *con, const struct protodef *protodefs, void *context, void **websock, struct afb_apiset *apiset)
 {
        const union MHD_ConnectionInfo *info;
        struct MHD_Response *response;
@@ -174,7 +174,7 @@ static int check_websocket_upgrade(struct MHD_Connection *con, const struct prot
                MHD_destroy_response(response);
                return 1;
        }
-       ws = proto->create(info->connect_fd, context, (void*)MHD_resume_connection, con);
+       ws = proto->create(info->connect_fd, apiset, context, (void*)MHD_resume_connection, con);
        if (ws == NULL) {
                response = MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_PERSISTENT);
                MHD_queue_response(con, MHD_HTTP_INTERNAL_SERVER_ERROR, response);
@@ -197,11 +197,11 @@ static int check_websocket_upgrade(struct MHD_Connection *con, const struct prot
 }
 
 static const struct protodef protodefs[] = {
-       { "x-afb-ws-json1",     (void*)afb_ws_json1_create },
+       { "x-afb-ws-json1",     afb_ws_json1_create },
        { NULL, NULL }
 };
 
-int afb_websock_check_upgrade(struct afb_hreq *hreq)
+int afb_websock_check_upgrade(struct afb_hreq *hreq, struct afb_apiset *apiset)
 {
        void *ws;
        int rc;
@@ -212,7 +212,7 @@ int afb_websock_check_upgrade(struct afb_hreq *hreq)
                return 0;
 
        ws = NULL;
-       rc = check_websocket_upgrade(hreq->connection, protodefs, &hreq->xreq.context, &ws);
+       rc = check_websocket_upgrade(hreq->connection, protodefs, &hreq->xreq.context, &ws, apiset);
        if (rc == 1) {
                hreq->replied = 1;
                if (ws != NULL)
index 379c3fb..c944542 100644 (file)
@@ -18,6 +18,8 @@
 #pragma once
 
 struct afb_hreq;
-extern int afb_websock_check_upgrade(struct afb_hreq *hreq);
+struct afb_apiset;
+
+extern int afb_websock_check_upgrade(struct afb_hreq *hreq, struct afb_apiset *apiset);
 
 
index 4e40571..50980d7 100644 (file)
@@ -33,7 +33,7 @@
 #include "afb-msg-json.h"
 #include "afb-session.h"
 #include "afb-cred.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
 #include "afb-xreq.h"
 #include "afb-context.h"
 #include "afb-evt.h"
@@ -63,6 +63,7 @@ struct afb_ws_json1
        struct afb_evt_listener *listener;
        struct afb_wsj1 *wsj1;
        struct afb_cred *cred;
+       struct afb_apiset *apiset;
        int new_session;
 };
 
@@ -101,7 +102,7 @@ static const struct afb_evt_itf evt_itf = {
 ****************************************************************
 ***************************************************************/
 
-struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure)
+struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *cleanup_closure)
 {
        struct afb_ws_json1 *result;
 
@@ -129,6 +130,7 @@ struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, vo
                goto error4;
 
        result->cred = afb_cred_create_for_socket(fd);
+       result->apiset = afb_apiset_addref(apiset);
        return result;
 
 error4:
@@ -157,6 +159,7 @@ static void aws_unref(struct afb_ws_json1 *ws)
                        ws->cleanup(ws->cleanup_closure);
                afb_session_unref(ws->session);
                afb_cred_unref(ws->cred);
+               afb_apiset_unref(ws->apiset);
                free(ws);
        }
 }
@@ -200,8 +203,7 @@ static void aws_on_call(struct afb_ws_json1 *ws, const char *api, const char *ve
        wsreq->xreq.listener = wsreq->aws->listener;
 
        /* emits the call */
-       afb_apis_call(&wsreq->xreq);
-       afb_xreq_unref(&wsreq->xreq);
+       afb_xreq_process(&wsreq->xreq, ws->apiset);
 }
 
 static void aws_on_event(struct afb_ws_json1 *aws, const char *event, int eventid, struct json_object *object)
index 3bcda81..335ca60 100644 (file)
@@ -19,9 +19,7 @@
 
 struct afb_ws_json1;
 struct afb_context;
-struct afb_req_itf;
+struct afb_apiset;
 
-extern const struct afb_req_itf afb_ws_json1_req_itf;
-
-extern struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_context *context, void (*cleanup)(void*), void *closure);
+extern struct afb_ws_json1 *afb_ws_json1_create(int fd, struct afb_apiset *apiset, struct afb_context *context, void (*cleanup)(void*), void *closure);
 
index fecd2f9..b40f030 100644 (file)
@@ -31,6 +31,9 @@
 #include "afb-msg-json.h"
 #include "afb-subcall.h"
 #include "afb-hook.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "jobs.h"
 #include "verbose.h"
 
 
@@ -476,7 +479,7 @@ static int xcheck(struct afb_xreq *xreq, int sessionflags)
        return 1;
 }
 
-void afb_xreq_call(struct afb_xreq *xreq, int sessionflags, void (*method)(struct afb_req req))
+void afb_xreq_so_call(struct afb_xreq *xreq, int sessionflags, void (*method)(struct afb_req req))
 {
        if (xcheck(xreq, sessionflags))
                method(to_req(xreq));
@@ -496,3 +499,42 @@ void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *query
        xreq->queryitf = queryitf;
 }
 
+
+static void process_async(int signum, void *arg)
+{
+       struct afb_xreq *xreq = arg;
+       struct afb_api api;
+
+       if (signum != 0) {
+               afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum);
+       } else {
+               /* init hooking */
+               afb_hook_init_xreq(xreq);
+               if (xreq->hookflags)
+                       afb_hook_xreq_begin(xreq);
+
+               /* search the api */
+               if (afb_apiset_get(xreq->apiset, xreq->api, &api) < 0) {
+                       afb_xreq_fail_f(xreq, "unknown-api", "api %s not found", xreq->api);
+               } else {
+                       xreq->context.api_key = api.closure;
+                       api.itf->call(api.closure, xreq);
+               }
+       }
+       afb_xreq_unref(xreq);
+}
+
+void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset)
+{
+       xreq->apiset = apiset;
+
+       afb_xreq_addref(xreq);
+       if (jobs_queue(NULL, afb_apiset_get_timeout(apiset), process_async, xreq) < 0) {
+               /* TODO: allows or not to proccess it directly as when no threading? (see above) */
+               ERROR("can't process job with threads: %m");
+               afb_xreq_fail_f(xreq, "cancelled", "not able to create a job for the task");
+               afb_xreq_unref(xreq);
+       }
+       afb_xreq_unref(xreq);
+}
+
index f996302..6da325a 100644 (file)
@@ -27,6 +27,7 @@ struct json_object;
 struct afb_evt_listener;
 struct afb_xreq;
 struct afb_cred;
+struct afb_apiset;
 
 struct afb_xreq_query_itf {
        struct json_object *(*json)(struct afb_xreq *xreq);
@@ -46,6 +47,7 @@ struct afb_xreq_query_itf {
 struct afb_xreq
 {
        struct afb_context context; /**< context of the request */
+       struct afb_apiset *apiset; /**< apiset of the xreq */
        const char *api;        /**< the requested API */
        const char *verb;       /**< the requested VERB */
        struct json_object *json; /**< the json object (or NULL) */
@@ -74,5 +76,6 @@ extern void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, co
 
 extern void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf);
 extern void afb_xreq_begin(struct afb_xreq *xreq);
-extern void afb_xreq_call(struct afb_xreq *xreq, int sessionflags, void (*callback)(struct afb_req req));
+extern void afb_xreq_so_call(struct afb_xreq *xreq, int sessionflags, void (*callback)(struct afb_req req));
 
+extern void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset);
index 6684ed5..01c0609 100644 (file)
@@ -36,7 +36,7 @@
 
 #include "afb-config.h"
 #include "afb-hswitch.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
 #include "afb-api-so.h"
 #include "afb-api-dbus.h"
 #include "afb-api-ws.h"
@@ -58,6 +58,8 @@
 */
 #define SELF_PGROUP 1
 
+struct afb_apiset *main_apiset;
+
 static struct afb_config *config;
 static pid_t childpid;
 
@@ -83,12 +85,12 @@ static struct afb_config_list *run_for_list(struct afb_config_list *list,
 
 static int run_start(void *closure, char *value)
 {
-       int (*starter) (const char *value) = closure;
-       return starter(value) >= 0;
+       int (*starter) (const char *value, struct afb_apiset *apiset) = closure;
+       return starter(value, main_apiset) >= 0;
 }
 
-static void start_list(struct afb_config_list *list,
-                      int (*starter) (const char *value), const char *message)
+static void apiset_start_list(struct afb_config_list *list,
+                      int (*starter) (const char *value, struct afb_apiset *apiset), const char *message)
 {
        list = run_for_list(list, run_start, starter);
        if (list) {
@@ -113,6 +115,7 @@ static void exit_handler()
                killpg(0, SIGTERM);
        else if (childpid > 0)
                killpg(childpid, SIGTERM);
+       exit(0);
 }
 
 static void on_sigterm(int signum, siginfo_t *info, void *uctx)
@@ -215,11 +218,11 @@ static int init_alias(void *closure, char *spec)
 static int init_http_server(struct afb_hsrv *hsrv)
 {
        if (!afb_hsrv_add_handler
-           (hsrv, config->rootapi, afb_hswitch_websocket_switch, NULL, 20))
+           (hsrv, config->rootapi, afb_hswitch_websocket_switch, main_apiset, 20))
                return 0;
 
        if (!afb_hsrv_add_handler
-           (hsrv, config->rootapi, afb_hswitch_apis, NULL, 10))
+           (hsrv, config->rootapi, afb_hswitch_apis, main_apiset, 10))
                return 0;
 
        if (run_for_list(config->aliases, init_alias, hsrv))
@@ -505,8 +508,7 @@ static void startup_call_current(struct startup_req *sreq)
                        sreq->xreq.verb = sreq->verb;
                        sreq->xreq.json = json_tokener_parse(json + 1);
                        if (sreq->api && sreq->verb && sreq->xreq.json) {
-                               afb_apis_call(&sreq->xreq);
-                               afb_xreq_unref(&sreq->xreq);
+                               afb_xreq_process(&sreq->xreq, main_apiset);
                                return;
                        }
                }
@@ -555,7 +557,11 @@ static void start()
        }
 
        /* configure the daemon */
-       afb_apis_set_timeout(config->apiTimeout);
+       main_apiset = afb_apiset_create("main", config->apiTimeout, NULL);
+       if (!main_apiset) {
+               ERROR("can't create main api set");
+               goto error;
+       }
        afb_session_init(config->nbSessionMax, config->cntxTimeout, config->token);
        if (!afb_hreq_init_cookie(config->httpdPort, config->rootapi, config->cntxTimeout)) {
                ERROR("initialisation of cookies failed");
@@ -569,18 +575,18 @@ static void start()
                afb_hook_create_ditf(NULL, config->traceditf, NULL, NULL);
 
        /* load bindings */
-       start_list(config->dbus_clients, afb_api_dbus_add_client, "the afb-dbus client");
-       start_list(config->ws_clients, afb_api_ws_add_client, "the afb-websocket client");
-       start_list(config->ldpaths, afb_api_so_add_pathset, "the binding path set");
-       start_list(config->so_bindings, afb_api_so_add_binding, "the binding");
+       apiset_start_list(config->dbus_clients, afb_api_dbus_add_client, "the afb-dbus client");
+       apiset_start_list(config->ws_clients, afb_api_ws_add_client, "the afb-websocket client");
+       apiset_start_list(config->ldpaths, afb_api_so_add_pathset, "the binding path set");
+       apiset_start_list(config->so_bindings, afb_api_so_add_binding, "the binding");
 
-       start_list(config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service");
-       start_list(config->ws_servers, afb_api_ws_add_server, "the afb-websocket service");
+       apiset_start_list(config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service");
+       apiset_start_list(config->ws_servers, afb_api_ws_add_server, "the afb-websocket service");
 
        DEBUG("Init config done");
 
        /* start the services */
-       if (afb_apis_start_all_services(1) < 0)
+       if (afb_apiset_start_all_services(main_apiset, 1) < 0)
                goto error;
 
        /* start the HTTP server */