)
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
#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"
struct sd_bus_slot *slot_call;
struct afb_evt_listener *listener; /* listener for broadcasted events */
struct origin *origins;
+ struct afb_apiset *apiset;
} server;
};
};
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;
}
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)
{
}
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;
/* 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;
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:
}
/* 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;
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);
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);
#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"
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);
/* 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);
.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);
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;
}
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;
}
#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);
#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"
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);
/* 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);
.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;
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;
}
/* 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;
}
#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);
#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;
}
/* 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;
}
-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;
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;
}
}
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];
}
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;
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;
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;
}
}
#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);
#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"
} client;
struct {
sd_event_source *listensrc; /**< systemd source for server socket */
+ struct afb_apiset *apiset;
} server;
};
};
/* pending subcalls */
struct api_ws_subcall *subcalls;
+
+ /* apiset */
+ struct afb_apiset *apiset;
};
/******************* websocket interface for client part **********************************/
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;
}
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)
{
}
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;
/* 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;
free(sc);
}
afb_cred_unref(client->cred);
+ afb_apiset_unref(client->apiset);
free(client);
}
}
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:
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;
}
/* 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;
if (rc < 0)
goto error2;
+ api->server.apiset = afb_apiset_addref(apiset);
return 0;
error2:
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);
--- /dev/null
+/*
+ * 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;
+}
+
#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);
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);
#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
*/
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;
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
* - 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;
}
/* 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);
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) {
/**
* 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) {
/**
* 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;
/**
* 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
+
--- /dev/null
+/*
+ * 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);
+
#include <afb/afb-binding.h>
-#include "afb-apis.h"
#include "afb-svc.h"
#include "afb-evt.h"
#include "afb-common.h"
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)
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);
#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"
{
const char *api, *verb;
size_t lenapi, lenverb;
+ struct afb_apiset *apiset = data;
api = &hreq->tail[strspn(hreq->tail, "/")];
lenapi = strcspn(api, "/");
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;
}
int afb_hswitch_websocket_switch(struct afb_hreq *hreq, void *data)
{
+ struct afb_apiset *apiset = data;
+
if (hreq->lentail != 0)
return 0;
return 1;
}
- return afb_websock_check_upgrade(hreq);
+ return afb_websock_check_upgrade(hreq, apiset);
}
#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);
#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"
return;
}
- afb_apis_call(&subcall->xreq);
- afb_xreq_unref(&subcall->xreq);
+ afb_xreq_process(&subcall->xreq, caller->apiset);
}
struct subcall_sync
#include "afb-svc.h"
#include "afb-xreq.h"
#include "afb-cred.h"
-#include "afb-apis.h"
+#include "afb-apiset.h"
#include "verbose.h"
/*
/* 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;
/*
* 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;
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 */
error3:
afb_session_unref(svc->session);
error2:
+ afb_apiset_unref(svc->apiset);
free(svc);
error:
return NULL;
/*
* 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;
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;
* 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;
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;
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)
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),
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)
}
}
-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;
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);
}
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;
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)
#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);
#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"
struct afb_evt_listener *listener;
struct afb_wsj1 *wsj1;
struct afb_cred *cred;
+ struct afb_apiset *apiset;
int new_session;
};
****************************************************************
***************************************************************/
-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;
goto error4;
result->cred = afb_cred_create_for_socket(fd);
+ result->apiset = afb_apiset_addref(apiset);
return result;
error4:
ws->cleanup(ws->cleanup_closure);
afb_session_unref(ws->session);
afb_cred_unref(ws->cred);
+ afb_apiset_unref(ws->apiset);
free(ws);
}
}
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)
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);
#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"
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));
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);
+}
+
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);
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) */
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);
#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"
*/
#define SELF_PGROUP 1
+struct afb_apiset *main_apiset;
+
static struct afb_config *config;
static pid_t childpid;
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) {
killpg(0, SIGTERM);
else if (childpid > 0)
killpg(childpid, SIGTERM);
+ exit(0);
}
static void on_sigterm(int signum, siginfo_t *info, void *uctx)
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))
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;
}
}
}
/* 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");
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 */