summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/afb-api-dbus.c34
-rw-r--r--src/afb-api-dbus.h6
-rw-r--r--src/afb-api-so-v1.c15
-rw-r--r--src/afb-api-so-v1.h2
-rw-r--r--src/afb-api-so-v2.c15
-rw-r--r--src/afb-api-so-v2.h2
-rw-r--r--src/afb-api-so.c30
-rw-r--r--src/afb-api-so.h10
-rw-r--r--src/afb-api-ws.c37
-rw-r--r--src/afb-api-ws.h6
-rw-r--r--src/afb-api.c64
-rw-r--r--src/afb-api.h (renamed from src/afb-apis.h)24
-rw-r--r--src/afb-apiset.c (renamed from src/afb-apis.c)448
-rw-r--r--src/afb-apiset.h39
-rw-r--r--src/afb-ditf.h1
-rw-r--r--src/afb-hreq.c11
-rw-r--r--src/afb-hreq.h2
-rw-r--r--src/afb-hswitch.c12
-rw-r--r--src/afb-hswitch.h1
-rw-r--r--src/afb-subcall.c5
-rw-r--r--src/afb-svc.c35
-rw-r--r--src/afb-svc.h6
-rw-r--r--src/afb-websock.c12
-rw-r--r--src/afb-websock.h4
-rw-r--r--src/afb-ws-json1.c10
-rw-r--r--src/afb-ws-json1.h6
-rw-r--r--src/afb-xreq.c44
-rw-r--r--src/afb-xreq.h5
-rw-r--r--src/main.c40
30 files changed, 613 insertions, 316 deletions
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 <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;
}
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 <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;
}
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 <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;
+}
+
diff --git a/src/afb-apis.h b/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
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 <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
index 00000000..be7932bd
--- /dev/null
+++ b/src/afb-apiset.h
@@ -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);
+
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 <afb/afb-binding.h>
-#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 <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);
}
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 */