From a8e971702f23ee67e02b4716ad4159f12cefdca6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Bollo?= Date: Thu, 13 Apr 2017 22:58:33 +0200 Subject: [PATCH] Introduce apiset for grouping apis MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This will be used at the end for debugging facilities. Change-Id: I75e3345667e1f58143c77a885e166375680ca194 Signed-off-by: José Bollo --- src/CMakeLists.txt | 3 +- src/afb-api-dbus.c | 34 +-- src/afb-api-dbus.h | 6 +- src/afb-api-so-v1.c | 15 +- src/afb-api-so-v1.h | 2 +- src/afb-api-so-v2.c | 15 +- src/afb-api-so-v2.h | 2 +- src/afb-api-so.c | 30 +-- src/afb-api-so.h | 10 +- src/afb-api-ws.c | 37 ++-- src/afb-api-ws.h | 6 +- src/afb-api.c | 64 ++++++ src/{afb-apis.h => afb-api.h} | 24 +-- src/{afb-apis.c => afb-apiset.c} | 448 ++++++++++++++++++++++++++------------- src/afb-apiset.h | 39 ++++ src/afb-ditf.h | 1 - src/afb-hreq.c | 11 +- src/afb-hreq.h | 2 +- src/afb-hswitch.c | 12 +- src/afb-hswitch.h | 1 + src/afb-subcall.c | 5 +- src/afb-svc.c | 35 ++- src/afb-svc.h | 6 +- src/afb-websock.c | 12 +- src/afb-websock.h | 4 +- src/afb-ws-json1.c | 10 +- src/afb-ws-json1.h | 6 +- src/afb-xreq.c | 44 +++- src/afb-xreq.h | 5 +- src/main.c | 40 ++-- 30 files changed, 613 insertions(+), 316 deletions(-) create mode 100644 src/afb-api.c rename src/{afb-apis.h => afb-api.h} (60%) rename src/{afb-apis.c => afb-apiset.c} (53%) create mode 100644 src/afb-apiset.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6956d0d2..3b1f1455 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index 13cbf7db..2f4c4ca9 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -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); diff --git a/src/afb-api-dbus.h b/src/afb-api-dbus.h index b4c2da8d..221b52dd 100644 --- a/src/afb-api-dbus.h +++ b/src/afb-api-dbus.h @@ -20,10 +20,8 @@ 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); diff --git a/src/afb-api-so-v1.c b/src/afb-api-so-v1.c index 4ec378e1..8c4ea484 100644 --- a/src/afb-api-so-v1.c +++ b/src/afb-api-so-v1.c @@ -24,7 +24,8 @@ #include -#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; } diff --git a/src/afb-api-so-v1.h b/src/afb-api-so-v1.h index d89ad60c..be8f8401 100644 --- a/src/afb-api-so-v1.h +++ b/src/afb-api-so-v1.h @@ -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); diff --git a/src/afb-api-so-v2.c b/src/afb-api-so-v2.c index 714bcd0f..2d939fbc 100644 --- a/src/afb-api-so-v2.c +++ b/src/afb-api-so-v2.c @@ -24,7 +24,8 @@ #include -#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; } diff --git a/src/afb-api-so-v2.h b/src/afb-api-so-v2.h index 7305db4a..28078973 100644 --- a/src/afb-api-so-v2.h +++ b/src/afb-api-so-v2.h @@ -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); diff --git a/src/afb-api-so.c b/src/afb-api-so.c index a22e4442..4b8f070c 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -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; } } diff --git a/src/afb-api-so.h b/src/afb-api-so.h index fcf66ccf..382dad03 100644 --- a/src/afb-api-so.h +++ b/src/afb-api-so.h @@ -18,12 +18,14 @@ #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); diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c index ea0781df..b03ef668 100644 --- a/src/afb-api-ws.c +++ b/src/afb-api-ws.c @@ -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: diff --git a/src/afb-api-ws.h b/src/afb-api-ws.h index 9da4e012..831d5ea0 100644 --- a/src/afb-api-ws.h +++ b/src/afb-api-ws.h @@ -20,10 +20,8 @@ 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 index 00000000..bb172d7e --- /dev/null +++ b/src/afb-api.c @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author "Fulup Ar Foll" + * Author José Bollo + * + * 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 +#include +#include +#include + +#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; +} + diff --git a/src/afb-apis.h b/src/afb-api.h similarity index 60% rename from src/afb-apis.h rename to src/afb-api.h index 02544668..6dfbf020 100644 --- a/src/afb-apis.h +++ b/src/afb-api.h @@ -17,14 +17,13 @@ #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); diff --git a/src/afb-apis.c b/src/afb-apiset.c similarity index 53% rename from src/afb-apis.c rename to src/afb-apiset.c index 6e093550..d9a4e5e8 100644 --- a/src/afb-apis.c +++ b/src/afb-apiset.c @@ -25,13 +25,16 @@ #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 +#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 index 00000000..be7932bd --- /dev/null +++ b/src/afb-apiset.h @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2016, 2017 "IoT.bzh" + * Author: José Bollo + * + * 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); + diff --git a/src/afb-ditf.h b/src/afb-ditf.h index ad8c9920..3e8d99a7 100644 --- a/src/afb-ditf.h +++ b/src/afb-ditf.h @@ -24,7 +24,6 @@ #include -#include "afb-apis.h" #include "afb-svc.h" #include "afb-evt.h" #include "afb-common.h" diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 6589f0f4..fe5af73a 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -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) diff --git a/src/afb-hreq.h b/src/afb-hreq.h index 47d6aa53..f4c00ff2 100644 --- a/src/afb-hreq.h +++ b/src/afb-hreq.h @@ -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); diff --git a/src/afb-hswitch.c b/src/afb-hswitch.c index 0eae18f7..34eafd5b 100644 --- a/src/afb-hswitch.c +++ b/src/afb-hswitch.c @@ -26,7 +26,7 @@ #include #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); } diff --git a/src/afb-hswitch.h b/src/afb-hswitch.h index 51773741..7fc8049a 100644 --- a/src/afb-hswitch.h +++ b/src/afb-hswitch.h @@ -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); diff --git a/src/afb-subcall.c b/src/afb-subcall.c index 68b33129..8a8c77a9 100644 --- a/src/afb-subcall.c +++ b/src/afb-subcall.c @@ -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 diff --git a/src/afb-svc.c b/src/afb-svc.c index 6b6b0a53..0ae56b81 100644 --- a/src/afb-svc.c +++ b/src/afb-svc.c @@ -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) diff --git a/src/afb-svc.h b/src/afb-svc.h index 7a1f7c10..0105624c 100644 --- a/src/afb-svc.h +++ b/src/afb-svc.h @@ -19,13 +19,17 @@ 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), diff --git a/src/afb-websock.c b/src/afb-websock.c index abdcfa1d..523ad8ff 100644 --- a/src/afb-websock.c +++ b/src/afb-websock.c @@ -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) diff --git a/src/afb-websock.h b/src/afb-websock.h index 379c3fb4..c9445425 100644 --- a/src/afb-websock.h +++ b/src/afb-websock.h @@ -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); diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index 4e405715..50980d7b 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -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) diff --git a/src/afb-ws-json1.h b/src/afb-ws-json1.h index 3bcda818..335ca608 100644 --- a/src/afb-ws-json1.h +++ b/src/afb-ws-json1.h @@ -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); diff --git a/src/afb-xreq.c b/src/afb-xreq.c index fecd2f95..b40f0304 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -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); +} + diff --git a/src/afb-xreq.h b/src/afb-xreq.h index f9963024..6da325ab 100644 --- a/src/afb-xreq.h +++ b/src/afb-xreq.h @@ -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); diff --git a/src/main.c b/src/main.c index 6684ed5e..01c06095 100644 --- a/src/main.c +++ b/src/main.c @@ -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 */ -- 2.16.6