diff options
Diffstat (limited to 'src')
79 files changed, 7882 insertions, 4010 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c789fca3..ed59ac0c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,16 +24,18 @@ ADD_DEFINITIONS(-DBINDING_INSTALL_DIR="${binding_install_dir}") # Always add INFER_EXTENSION (more details in afb-hreq.c) ADD_DEFINITIONS(-DINFER_EXTENSION) -ADD_LIBRARY(afb-lib STATIC +SET(AFB_LIB_SOURCES afb-api.c - afb-api-dyn.c afb-api-so.c - afb-api-so-v1.c afb-api-so-v2.c + afb-api-so-v3.c afb-api-so-vdyn.c + afb-api-v3.c afb-api-ws.c afb-apiset.c afb-auth.c + afb-autoset.c + afb-calls.c afb-common.c afb-config.c afb-context.c @@ -66,6 +68,7 @@ ADD_LIBRARY(afb-lib STATIC fdev-systemd.c jobs.c locale-root.c + pearson.c process-name.c sig-monitor.c subpath.c @@ -74,15 +77,26 @@ ADD_LIBRARY(afb-lib STATIC wrap-json.c ) +IF(INCLUDE_LEGACY_BINDING_V1) + ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_V1) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-v1.c) +ENDIF(INCLUDE_LEGACY_BINDING_V1) +IF(INCLUDE_LEGACY_BINDING_VDYN) + ADD_DEFINITIONS(-DWITH_LEGACY_BINDING_VDYN) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-so-vdyn.c) +ENDIF(INCLUDE_LEGACY_BINDING_VDYN) + IF(INCLUDE_DBUS_TRANSPARENCY) ADD_DEFINITIONS(-DWITH_DBUS_TRANSPARENCY) - TARGET_SOURCES(afb-lib PUBLIC afb-api-dbus.c) + SET(AFB_LIB_SOURCES ${AFB_LIB_SOURCES} afb-api-dbus.c) ENDIF() +ADD_LIBRARY(afb-lib STATIC ${AFB_LIB_SOURCES}) + ########################################### # build and install afb-daemon ########################################### -ADD_EXECUTABLE(afb-daemon main.c) +ADD_EXECUTABLE(afb-daemon main-afb-daemon.c) TARGET_LINK_LIBRARIES(afb-daemon afb-lib ${link_libraries} @@ -94,7 +108,7 @@ INSTALL(TARGETS afb-daemon # build and install afb-daemon ########################################### IF(INCLUDE_SUPERVISOR) - ADD_EXECUTABLE(afs-supervisor afs-main.c afs-supervisor.c afs-discover.c afs-config.c) + ADD_EXECUTABLE(afs-supervisor main-afs-supervisor.c afs-supervisor.c afs-discover.c afs-config.c) TARGET_LINK_LIBRARIES(afs-supervisor afb-lib ${link_libraries} @@ -124,7 +138,7 @@ INSTALL(FILES afb-wsj1.h afb-ws-client.h afb-proto-ws.h DESTINATION ${CMAKE_INST ########################################### # build and install afb-client-demo ########################################### -ADD_EXECUTABLE(afb-client-demo afb-client-demo.c) +ADD_EXECUTABLE(afb-client-demo main-afb-client-demo.c) TARGET_LINK_LIBRARIES(afb-client-demo afbwsc ${link_libraries} diff --git a/src/afb-api-dbus.c b/src/afb-api-dbus.c index 98c26930..a1e15fd3 100644 --- a/src/afb-api-dbus.c +++ b/src/afb-api-dbus.c @@ -27,7 +27,7 @@ #include <systemd/sd-bus.h> #include <json-c/json.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2.h> #include "afb-systemd.h" @@ -76,9 +76,6 @@ struct api_dbus }; }; -#define RETOK 1 -#define RETERR 2 - /******************* common part **********************************/ /* @@ -113,7 +110,7 @@ static struct api_dbus *make_api_dbus_3(int system, const char *path, size_t pat goto error2; } api->api++; - if (!afb_api_is_valid_name(api->api, 1)) { + if (!afb_api_is_valid_name(api->api)) { errno = EINVAL; goto error2; } @@ -226,7 +223,7 @@ struct dbus_memo { struct dbus_event { struct dbus_event *next; - struct afb_eventid *eventid; + struct afb_event_x2 *event; int id; int refcount; }; @@ -283,32 +280,19 @@ static int api_dbus_client_on_reply(sd_bus_message *message, void *userdata, sd_ { int rc; struct dbus_memo *memo; - const char *first, *second; - uint8_t type; - uint32_t flags; + const char *json, *error, *info; /* retrieve the recorded data */ memo = userdata; /* get the answer */ - rc = sd_bus_message_read(message, "yssu", &type, &first, &second, &flags); + rc = sd_bus_message_read(message, "sss", &json, &error, &info); if (rc < 0) { /* failing to have the answer */ - afb_xreq_fail(memo->xreq, "error", "dbus error"); + afb_xreq_reply(memo->xreq, NULL, "error", "dbus error"); } else { /* report the answer */ - memo->xreq->context.flags = (unsigned)flags; - switch(type) { - case RETOK: - afb_xreq_success(memo->xreq, json_tokener_parse(first), *second ? second : NULL); - break; - case RETERR: - afb_xreq_fail(memo->xreq, first, *second ? second : NULL); - break; - default: - afb_xreq_fail(memo->xreq, "error", "dbus link broken"); - break; - } + afb_xreq_reply(memo->xreq, *json ? json_tokener_parse(json) : NULL, *error ? error : NULL, *info ? info : NULL); } api_dbus_client_memo_destroy(memo); return 1; @@ -322,24 +306,27 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq) int rc; struct dbus_memo *memo; struct sd_bus_message *msg; + const char *creds; /* create the recording data */ memo = api_dbus_client_memo_make(api, xreq); if (memo == NULL) { - afb_xreq_fail(xreq, "error", "out of memory"); + afb_xreq_reply(memo->xreq, NULL, "error", "out of memory"); return; } /* creates the message */ msg = NULL; - rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.verb); + rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.called_verb); if (rc < 0) goto error; - rc = sd_bus_message_append(msg, "ssu", + creds = xreq_on_behalf_cred_export(xreq); + rc = sd_bus_message_append(msg, "ssus", afb_xreq_raw(xreq, &size), afb_session_uuid(xreq->context.session), - (uint32_t)xreq->context.flags); + (uint32_t)xreq->context.flags, + creds ?: ""); if (rc < 0) goto error; @@ -355,7 +342,7 @@ static void api_dbus_client_call(void *closure, struct afb_xreq *xreq) error: /* if there was an error report it directly */ errno = -rc; - afb_xreq_fail(xreq, "error", "dbus error"); + afb_xreq_reply(memo->xreq, NULL, "error", "dbus error"); api_dbus_client_memo_destroy(memo); end: sd_bus_message_unref(msg); @@ -382,7 +369,7 @@ static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int struct dbus_event *ev; ev = api->client.events; - while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name))) + while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name))) ev = ev->next; return ev; @@ -403,8 +390,8 @@ static void api_dbus_client_event_create(struct api_dbus *api, int id, const cha /* no conflict, try to add it */ ev = malloc(sizeof *ev); if (ev != NULL) { - ev->eventid = afb_evt_eventid_create(name); - if (ev->eventid == NULL) + ev->event = afb_evt_event_x2_create(name); + if (ev->event == NULL) free(ev); else { ev->refcount = 1; @@ -440,7 +427,7 @@ static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *prv = ev->next; /* destroys the event */ - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); } @@ -459,7 +446,7 @@ static void api_dbus_client_event_push(struct api_dbus *api, int id, const char /* destroys the event */ object = json_tokener_parse(data); - afb_evt_eventid_push(ev->eventid, object); + afb_evt_event_x2_push(ev->event, object); } /* subscribes an event */ @@ -484,7 +471,7 @@ static void api_dbus_client_event_subscribe(struct api_dbus *api, int id, const } /* subscribe the request to the event */ - rc = afb_xreq_subscribe(memo->xreq, ev->eventid); + rc = afb_xreq_subscribe(memo->xreq, ev->event); if (rc < 0) ERROR("can't subscribe: %m"); } @@ -511,7 +498,7 @@ static void api_dbus_client_event_unsubscribe(struct api_dbus *api, int id, cons } /* unsubscribe the request from the event */ - rc = afb_xreq_unsubscribe(memo->xreq, ev->eventid); + rc = afb_xreq_unsubscribe(memo->xreq, ev->event); if (rc < 0) ERROR("can't unsubscribe: %m"); } @@ -572,11 +559,11 @@ static struct afb_api_itf dbus_api_itf = { }; /* adds a afb-dbus-service client api */ -int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset) +int afb_api_dbus_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_dbus *api; - struct afb_api afb_api; + struct afb_api_item afb_api; char *match; /* create the dbus client api */ @@ -611,7 +598,7 @@ int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset) afb_api.closure = api; afb_api.itf = &dbus_api_itf; afb_api.group = NULL; - if (afb_apiset_add(apiset, api->api, afb_api) < 0) + if (afb_apiset_add(declare_set, api->api, afb_api) < 0) goto error2; return 0; @@ -816,77 +803,51 @@ static struct json_object *dbus_req_json(struct afb_xreq *xreq) return dreq->json; } -/* get the argument of the request of 'name' */ -static void dbus_req_reply(struct dbus_req *dreq, uint8_t type, const char *first, const char *second) +void dbus_req_raw_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { + struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); int rc; - rc = sd_bus_reply_method_return(dreq->message, - "yssu", type, first ? : "", second ? : "", (uint32_t)dreq->xreq.context.flags); + + rc = sd_bus_reply_method_return(dreq->message, "sss", + obj ? json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN) : "", + error ? : "", + info ? : ""); if (rc < 0) ERROR("sending the reply failed"); } -static void dbus_req_success(struct afb_xreq *xreq, struct json_object *obj, const char *info) -{ - struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); - - dbus_req_reply(dreq, RETOK, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN), info); -} - -static void dbus_req_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); - - dbus_req_reply(dreq, RETERR, status, info); -} - static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid); -static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); uint64_t msgid; int rc; - rc = afb_evt_eventid_add_watch(dreq->listener->listener, eventid); + rc = afb_evt_event_x2_add_watch(dreq->listener->listener, event); sd_bus_message_get_cookie(dreq->message, &msgid); - afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid); + afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid); return rc; } -static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq); uint64_t msgid; int rc; sd_bus_message_get_cookie(dreq->message, &msgid); - afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid); - rc = afb_evt_eventid_remove_watch(dreq->listener->listener, eventid); + afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event), "", msgid); + rc = afb_evt_event_x2_remove_watch(dreq->listener->listener, event); return rc; } -static void dbus_req_subcall( - struct afb_xreq *xreq, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cb_closure) -{ - ERROR("DBUS API doesn't support subcalls, info: %s/%s(%s)", api, verb, json_object_to_json_string(args)); - callback(cb_closure, 1, afb_msg_json_reply_error("error", "subcall isn't supported", NULL, NULL)); - json_object_put(args); -} - const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = { .json = dbus_req_json, - .success = dbus_req_success, - .fail = dbus_req_fail, + .reply = dbus_req_raw_reply, .unref = dbus_req_destroy, .subscribe = dbus_req_subscribe, .unsubscribe = dbus_req_unsubscribe, - .subcall = dbus_req_subcall }; /******************* server part **********************************/ @@ -954,6 +915,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd int rc; const char *method; const char *uuid; + const char *creds; struct dbus_req *dreq; struct api_dbus *api = userdata; uint32_t flags; @@ -973,7 +935,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd goto out_of_memory; /* get the data */ - rc = sd_bus_message_read(message, "ssu", &dreq->request, &uuid, &flags); + rc = sd_bus_message_read(message, "ssus", &dreq->request, &uuid, &flags, &creds); if (rc < 0) { sd_bus_reply_method_errorf(message, SD_BUS_ERROR_INVALID_SIGNATURE, "invalid signature"); goto error; @@ -992,6 +954,7 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd /* fulfill the request and emit it */ dreq->xreq.context.flags = flags; + dreq->xreq.cred = afb_cred_mixed_on_behalf_import(listener->origin->cred, uuid, creds && creds[0] ? creds : NULL); dreq->message = sd_bus_message_ref(message); dreq->json = json_tokener_parse(dreq->request); if (dreq->json == NULL && strcmp(dreq->request, "null")) { @@ -999,8 +962,8 @@ static int api_dbus_server_on_object_called(sd_bus_message *message, void *userd dreq->json = json_object_new_string(dreq->request); } dreq->listener = listener; - dreq->xreq.request.api = api->api; - dreq->xreq.request.verb = method; + dreq->xreq.request.called_api = api->api; + dreq->xreq.request.called_verb = method; afb_xreq_process(&dreq->xreq, api->server.apiset); return 1; @@ -1012,7 +975,7 @@ error: } /* create the service */ -int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset) +int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_dbus *api; @@ -1040,7 +1003,7 @@ int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset) 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); + api->server.apiset = afb_apiset_addref(call_set); 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 90f20c16..1c47685b 100644 --- a/src/afb-api-dbus.h +++ b/src/afb-api-dbus.h @@ -20,8 +20,8 @@ struct afb_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, struct afb_apiset *declare_set, struct afb_apiset *call_set); -extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset); +extern int afb_api_dbus_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-api-dyn.c b/src/afb-api-dyn.c deleted file mode 100644 index c2d6cdc4..00000000 --- a/src/afb-api-dyn.c +++ /dev/null @@ -1,285 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author José Bollo <jose.bollo@iot.bzh> - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define _GNU_SOURCE - -#include <stdlib.h> -#include <string.h> -#include <assert.h> -#include <errno.h> - -#include <json-c/json.h> - -#define AFB_BINDING_VERSION 0 -#include <afb/afb-binding.h> - -#include "afb-api.h" -#include "afb-api-dyn.h" -#include "afb-apiset.h" -#include "afb-auth.h" -#include "afb-export.h" -#include "afb-xreq.h" -#include "verbose.h" - -/* - * Description of a binding - */ -struct afb_api_dyn { - int count; - struct afb_api_dyn_verb **verbs; - const struct afb_verb_v2 *verbsv2; - struct afb_export *export; - char info[1]; -}; - -void afb_api_dyn_set_verbs_v2( - struct afb_api_dyn *dynapi, - const struct afb_verb_v2 *verbs) -{ - dynapi->verbsv2 = verbs; -} - -int afb_api_dyn_add_verb( - struct afb_api_dyn *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session) -{ - struct afb_api_dyn_verb *v, **vv; - - afb_api_dyn_sub_verb(dynapi, verb); - - vv = realloc(dynapi->verbs, (1 + dynapi->count) * sizeof *vv); - if (!vv) - goto oom; - dynapi->verbs = vv; - - v = malloc(sizeof *v + strlen(verb) + (info ? 1 + strlen(info) : 0)); - if (!v) - goto oom; - - v->callback = callback; - v->vcbdata = vcbdata; - v->auth = auth; - v->session = session; - - v->info = 1 + stpcpy(v->verb, verb); - if (info) - strcpy((char*)v->info, info); - else - v->info = NULL; - - dynapi->verbs[dynapi->count++] = v; - return 0; -oom: - errno = ENOMEM; - return -1; -} - -int afb_api_dyn_sub_verb( - struct afb_api_dyn *dynapi, - const char *verb) -{ - struct afb_api_dyn_verb *v; - int i; - - /* look first in dyna mic verbs */ - for (i = 0 ; i < dynapi->count ; i++) { - v = dynapi->verbs[i]; - if (!strcasecmp(v->verb, verb)) { - if (i != --dynapi->count) - dynapi->verbs[i] = dynapi->verbs[dynapi->count]; - free(v); - return 0; - } - } - - errno = ENOENT; - return -1; -} - -static void call_cb(void *closure, struct afb_xreq *xreq) -{ - struct afb_api_dyn *dynapi = closure; - struct afb_api_dyn_verb **verbs, *v; - const struct afb_verb_v2 *verbsv2; - int i; - const char *name; - - name = xreq->request.verb; - xreq->request.dynapi = (void*)dynapi->export; /* hack: this avoids to export afb_export structure */ - - /* look first in dyna mic verbs */ - verbs = dynapi->verbs; - i = dynapi->count; - while (i) { - v = verbs[--i]; - if (!strcasecmp(v->verb, name)) { - xreq->request.vcbdata = v->vcbdata; - afb_xreq_call_verb_vdyn(xreq, verbs[i]); - return; - } - } - - verbsv2 = dynapi->verbsv2; - if (verbsv2) { - while (verbsv2->verb) { - if (strcasecmp(verbsv2->verb, name)) - verbsv2++; - else { - afb_xreq_call_verb_v2(xreq, verbsv2); - return; - } - } - } - - afb_xreq_fail_unknown_verb(xreq); -} - -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct afb_api_dyn *dynapi = closure; - return afb_export_start(dynapi->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - afb_export_update_hook(dynapi->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - return afb_export_verbosity_get(dynapi->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct afb_api_dyn *dynapi = closure; - afb_export_verbosity_set(dynapi->export, level); -} - -static struct json_object *make_description_openAPIv3(struct afb_api_dyn *dynapi) -{ - char buffer[256]; - struct afb_api_dyn_verb **iter, **end, *verb; - struct json_object *r, *f, *a, *i, *p, *g; - - r = json_object_new_object(); - json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); - - i = json_object_new_object(); - json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(dynapi->export))); - json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(dynapi->info)); - - p = json_object_new_object(); - json_object_object_add(r, "paths", p); - iter = dynapi->verbs; - end = iter + dynapi->count; - while (iter != end) { - verb = *iter++; - buffer[0] = '/'; - strncpy(buffer + 1, verb->verb, sizeof buffer - 1); - buffer[sizeof buffer - 1] = 0; - f = json_object_new_object(); - json_object_object_add(p, buffer, f); - g = json_object_new_object(); - json_object_object_add(f, "get", g); - - a = afb_auth_json_v2(verb->auth, verb->session); - if (a) - json_object_object_add(g, "x-permissions", a); - - a = json_object_new_object(); - json_object_object_add(g, "responses", a); - f = json_object_new_object(); - json_object_object_add(a, "200", f); - json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb)); - } - return r; -} - -static struct json_object *describe_cb(void *closure) -{ - struct afb_api_dyn *dynapi = closure; - struct json_object *r = make_description_openAPIv3(dynapi); - return r; -} - -static struct afb_api_itf dyn_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_dyn_add(struct afb_apiset *apiset, const char *name, const char *info, int noconcurrency, int (*preinit)(void*, struct afb_dynapi*), void *closure) -{ - int rc; - struct afb_api_dyn *dynapi; - struct afb_api afb_api; - struct afb_export *export; - - INFO("Starting creation of dynamic API %s", name); - - /* allocates the description */ - info = info ?: ""; - dynapi = calloc(1, sizeof *dynapi + strlen(info)); - export = afb_export_create_vdyn(apiset, name, dynapi); - if (!dynapi || !export) { - ERROR("out of memory"); - goto error; - } - strcpy(dynapi->info, info); - dynapi->export = export; - - /* preinit the api */ - rc = afb_export_preinit_vdyn(export, preinit, closure); - if (rc < 0) { - ERROR("dynamic api %s preinit function failed, ABORTING it!", - afb_export_apiname(dynapi->export)); - goto error; - } - - /* records the binding */ - afb_api.closure = dynapi; - afb_api.itf = &dyn_api_itf; - afb_api.group = noconcurrency ? dynapi : NULL; - if (afb_apiset_add(apiset, afb_export_apiname(dynapi->export), afb_api) < 0) { - ERROR("dynamic api %s can't be registered to set %s, ABORTING it!", - afb_export_apiname(dynapi->export), - afb_apiset_name(apiset)); - goto error; - } - INFO("binding %s added to set %s", afb_export_apiname(dynapi->export), afb_apiset_name(apiset)); - return 0; - -error: - afb_export_destroy(export); - free(dynapi); - - return -1; -} - diff --git a/src/afb-api-dyn.h b/src/afb-api-dyn.h deleted file mode 100644 index 107d944e..00000000 --- a/src/afb-api-dyn.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (C) 2016, 2017, 2018 "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_apiset; -struct afb_dynapi; -struct afb_auth; -struct afb_request; -struct afb_verb_v2; - -struct afb_api_dyn_verb -{ - void (*callback)(struct afb_request *request); - void *vcbdata; - const struct afb_auth *auth; - const char *info; - int session; - char verb[1]; -}; - -struct afb_api_dyn; - -extern int afb_api_dyn_add( - struct afb_apiset *apiset, - const char *name, - const char *info, - int noconcurrency, - int (*preinit)(void*, struct afb_dynapi*), - void *closure); - -extern void afb_api_dyn_set_verbs_v2( - struct afb_api_dyn *dynapi, - const struct afb_verb_v2 *verbs); - -extern int afb_api_dyn_add_verb( - struct afb_api_dyn *dynapi, - const char *verb, - const char *info, - void (*callback)(struct afb_request *request), - void *vcbdata, - const struct afb_auth *auth, - uint32_t session); - -extern int afb_api_dyn_sub_verb( - struct afb_api_dyn *dynapi, - const char *verb); - diff --git a/src/afb-api-so-v1.c b/src/afb-api-so-v1.c index 985a113d..7db686d8 100644 --- a/src/afb-api-so-v1.c +++ b/src/afb-api-so-v1.c @@ -21,9 +21,9 @@ #include <string.h> #include <dlfcn.h> #include <assert.h> +#include <stdarg.h> #include <json-c/json.h> - #include <afb/afb-binding-v1.h> #include "afb-api.h" @@ -43,59 +43,24 @@ static const char afb_api_so_v1_register[] = "afbBindingV1Register"; static const char afb_api_so_v1_service_init[] = "afbBindingV1ServiceInit"; static const char afb_api_so_v1_service_event[] = "afbBindingV1ServiceEvent"; -/* - * Description of a binding - */ -struct api_so_v1 { - struct afb_binding_v1 *binding; /* descriptor */ - void *handle; /* context of dlopen */ - struct afb_export *export; /* export */ -}; - -static const struct afb_verb_desc_v1 *search(struct api_so_v1 *desc, const char *name) +static const struct afb_verb_desc_v1 *search(struct afb_binding_v1 *binding, const char *name) { const struct afb_verb_desc_v1 *verb; - verb = desc->binding->v1.verbs; + verb = binding->v1.verbs; while (verb->name && strcasecmp(verb->name, name)) verb++; return verb->name ? verb : NULL; } -static void call_cb(void *closure, struct afb_xreq *xreq) +void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq) { const struct afb_verb_desc_v1 *verb; - struct api_so_v1 *desc = closure; - xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */ - verb = search(desc, xreq->request.verb); + verb = search(binding, xreq->request.called_verb); afb_xreq_call_verb_v1(xreq, verb); } -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct api_so_v1 *desc = closure; - return afb_export_start(desc->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct api_so_v1 *desc = closure; - afb_export_update_hook(desc->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct api_so_v1 *desc = closure; - return afb_export_verbosity_get(desc->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct api_so_v1 *desc = closure; - afb_export_verbosity_set(desc->export, level); -} - static struct json_object *addperm(struct json_object *o, struct json_object *x) { struct json_object *a; @@ -130,7 +95,7 @@ static struct json_object *addperm_key_valint(struct json_object *o, const char return addperm_key_val(o, key, json_object_new_int(val)); } -static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) +struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname) { char buffer[256]; const struct afb_verb_desc_v1 *verb; @@ -141,13 +106,13 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) i = json_object_new_object(); json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export))); + json_object_object_add(i, "title", json_object_new_string(apiname)); json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(desc->binding->v1.info ?: afb_export_apiname(desc->export))); + json_object_object_add(i, "description", json_object_new_string(binding->v1.info ?: apiname)); p = json_object_new_object(); json_object_object_add(r, "paths", p); - verb = desc->binding->v1.verbs; + verb = binding->v1.verbs; while (verb->name) { buffer[0] = '/'; strncpy(buffer + 1, verb->name, sizeof buffer - 1); @@ -158,14 +123,14 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) json_object_object_add(f, "get", g); a = NULL; - if (verb->session & AFB_SESSION_CLOSE_V1) + if (verb->session & AFB_SESSION_CLOSE_X1) a = addperm_key_valstr(a, "session", "close"); - if (verb->session & AFB_SESSION_CHECK_V1) + if (verb->session & AFB_SESSION_CHECK_X1) a = addperm_key_valstr(a, "session", "check"); - if (verb->session & AFB_SESSION_RENEW_V1) + if (verb->session & AFB_SESSION_RENEW_X1) a = addperm_key_valstr(a, "token", "refresh"); - if (verb->session & AFB_SESSION_LOA_MASK_V1) - a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1); + if (verb->session & AFB_SESSION_LOA_MASK_X1) + a = addperm_key_valint(a, "LOA", (verb->session >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1); if (a) json_object_object_add(g, "x-permissions", a); @@ -179,95 +144,75 @@ static struct json_object *make_description_openAPIv3(struct api_so_v1 *desc) return r; } -static struct json_object *describe_cb(void *closure) +int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - struct api_so_v1 *desc = closure; - - return make_description_openAPIv3(desc); -} - -static struct afb_api_itf so_v1_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset) -{ - struct api_so_v1 *desc; + struct afb_binding_v1 *binding; /* descriptor */ struct afb_binding_v1 *(*register_function) (const struct afb_binding_interface_v1 *interface); - int (*init)(struct afb_service service); + int (*init)(struct afb_service_x1 service); void (*onevent)(const char *event, struct json_object *object); - struct afb_api afb_api; struct afb_export *export; /* retrieves the register function */ register_function = dlsym(handle, afb_api_so_v1_register); if (!register_function) return 0; + INFO("binding [%s] is a valid AFB binding V1", path); /* allocates the description */ init = dlsym(handle, afb_api_so_v1_service_init); onevent = dlsym(handle, afb_api_so_v1_service_event); - export = afb_export_create_v1(apiset, path, init, onevent); - desc = calloc(1, sizeof *desc); - if (desc == NULL || export == NULL) { - ERROR("out of memory"); + export = afb_export_create_v1(declare_set, call_set, path, init, onevent); + if (export == NULL) { + ERROR("binding [%s] creation failure...", path); goto error; } - desc->export = export; - desc->handle = handle; - - /* init the binding */ - INFO("binding [%s] calling registering function %s", path, afb_api_so_v1_register); - desc->binding = afb_export_register_v1(desc->export, register_function); - if (desc->binding == NULL) { - ERROR("binding [%s] register function failed. continuing...", path); + binding = afb_export_register_v1(export, register_function); + if (binding == NULL) { + ERROR("binding [%s] register failure...", path); goto error; } /* check the returned structure */ - if (desc->binding->type != AFB_BINDING_VERSION_1) { - ERROR("binding [%s] invalid type %d...", path, desc->binding->type); + if (binding->type != AFB_BINDING_VERSION_1) { + ERROR("binding [%s] invalid type %d...", path, binding->type); goto error; } - if (desc->binding->v1.prefix == NULL || *desc->binding->v1.prefix == 0) { + if (binding->v1.prefix == NULL || *binding->v1.prefix == 0) { ERROR("binding [%s] bad prefix...", path); goto error; } - if (!afb_api_is_valid_name(desc->binding->v1.prefix, 1)) { + if (!afb_api_is_valid_name(binding->v1.prefix)) { ERROR("binding [%s] invalid prefix...", path); goto error; } - if (desc->binding->v1.info == NULL || *desc->binding->v1.info == 0) { + if (binding->v1.info == NULL || *binding->v1.info == 0) { ERROR("binding [%s] bad description...", path); goto error; } - if (desc->binding->v1.verbs == NULL) { - ERROR("binding [%s] no APIs...", path); + if (binding->v1.verbs == NULL) { + ERROR("binding [%s] no verbs...", path); goto error; } /* records the binding */ - if (!strcmp(path, afb_export_apiname(desc->export))) - afb_export_rename(desc->export, desc->binding->v1.prefix); - afb_api.closure = desc; - afb_api.itf = &so_v1_api_itf; - afb_api.group = NULL; - if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) { + if (!strcmp(path, afb_export_apiname(export))) { + if (afb_export_rename(export, binding->v1.prefix) < 0) { + ERROR("binding [%s] can't be renamed to %s", path, binding->v1.prefix); + goto error; + } + } + + if (afb_export_declare(export, 0) < 0) { ERROR("binding [%s] can't be registered...", path); goto error; } - INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(desc->export)); + INFO("binding %s loaded with API prefix %s", path, afb_export_apiname(export)); + afb_export_unref(export); return 1; error: - afb_export_destroy(export); - free(desc); + afb_export_unref(export); return -1; } diff --git a/src/afb-api-so-v1.h b/src/afb-api-so-v1.h index 42f18a19..ebe00950 100644 --- a/src/afb-api-so-v1.h +++ b/src/afb-api-so-v1.h @@ -18,4 +18,12 @@ #pragma once -extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *apiset); +struct afb_apiset; +struct afb_binding_v1; +struct afb_xreq; +struct json_object; + +extern int afb_api_so_v1_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); + +extern void afb_api_so_v1_process_call(struct afb_binding_v1 *binding, struct afb_xreq *xreq); +extern struct json_object *afb_api_so_v1_make_description_openAPIv3(struct afb_binding_v1 *binding, const char *apiname); diff --git a/src/afb-api-so-v2.c b/src/afb-api-so-v2.c index fb901f58..a13c00e4 100644 --- a/src/afb-api-so-v2.c +++ b/src/afb-api-so-v2.c @@ -21,9 +21,10 @@ #include <string.h> #include <dlfcn.h> #include <assert.h> +#include <stdarg.h> -#include <afb/afb-binding-v2.h> #include <json-c/json.h> +#include <afb/afb-binding-v2.h> #include "afb-api.h" #include "afb-api-so-v2.h" @@ -42,78 +43,50 @@ static const char afb_api_so_v2_descriptor[] = "afbBindingV2"; static const char afb_api_so_v2_data[] = "afbBindingV2data"; -/* - * Description of a binding - */ -struct api_so_v2 { - const struct afb_binding_v2 *binding; /* descriptor */ - void *handle; /* context of dlopen */ - struct afb_export *export; /* exportations */ -}; - -static const struct afb_verb_v2 *search(struct api_so_v2 *desc, const char *name) +static const struct afb_verb_v2 *search(const struct afb_binding_v2 *binding, const char *name) { const struct afb_verb_v2 *verb; - verb = desc->binding->verbs; + verb = binding->verbs; while (verb->verb && strcasecmp(verb->verb, name)) verb++; return verb->verb ? verb : NULL; return NULL; } -static void call_cb(void *closure, struct afb_xreq *xreq) +void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq) { - struct api_so_v2 *desc = closure; const struct afb_verb_v2 *verb; - xreq->request.dynapi = (void*)desc->export; /* hack: this avoids to export afb_export structure */ - verb = search(desc, xreq->request.verb); + verb = search(binding, xreq->request.called_verb); afb_xreq_call_verb_v2(xreq, verb); } -static int service_start_cb(void *closure, int share_session, int onneed, struct afb_apiset *apiset) -{ - struct api_so_v2 *desc = closure; - return afb_export_start(desc->export, share_session, onneed, apiset); -} - -static void update_hooks_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - afb_export_update_hook(desc->export); -} - -static int get_verbosity_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - return afb_export_verbosity_get(desc->export); -} - -static void set_verbosity_cb(void *closure, int level) -{ - struct api_so_v2 *desc = closure; - afb_export_verbosity_set(desc->export, level); -} - -static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc) +struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname) { char buffer[256]; const struct afb_verb_v2 *verb; struct json_object *r, *f, *a, *i, *p, *g; + + if (binding->specification) { + r = json_tokener_parse(binding->specification); + if (r) + return r; + } + r = json_object_new_object(); json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); i = json_object_new_object(); json_object_object_add(r, "info", i); - json_object_object_add(i, "title", json_object_new_string(afb_export_apiname(desc->export))); + json_object_object_add(i, "title", json_object_new_string(apiname)); json_object_object_add(i, "version", json_object_new_string("0.0.0")); - json_object_object_add(i, "description", json_object_new_string(desc->binding->info ?: afb_export_apiname(desc->export))); + json_object_object_add(i, "description", json_object_new_string(binding->info ?: apiname)); p = json_object_new_object(); json_object_object_add(r, "paths", p); - verb = desc->binding->verbs; + verb = binding->verbs; while (verb->verb) { buffer[0] = '/'; strncpy(buffer + 1, verb->verb, sizeof buffer - 1); @@ -137,29 +110,9 @@ static struct json_object *make_description_openAPIv3(struct api_so_v2 *desc) return r; } -static struct json_object *describe_cb(void *closure) -{ - struct api_so_v2 *desc = closure; - struct json_object *r = desc->binding->specification ? json_tokener_parse(desc->binding->specification) : NULL; - if (!r) - r = make_description_openAPIv3(desc); - return r; -} - -static struct afb_api_itf so_v2_api_itf = { - .call = call_cb, - .service_start = service_start_cb, - .update_hooks = update_hooks_cb, - .get_verbosity = get_verbosity_cb, - .set_verbosity = set_verbosity_cb, - .describe = describe_cb -}; - -int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data) +int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data) { int rc; - struct api_so_v2 *desc; - struct afb_api afb_api; struct afb_export *export; /* basic checks */ @@ -169,45 +122,38 @@ int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle assert(data); /* allocates the description */ - export = afb_export_create_v2(apiset, binding->api, data, binding->init, binding->onevent); - desc = calloc(1, sizeof *desc); - if (!desc || !export) { + export = afb_export_create_v2(declare_set, call_set, binding->api, binding, data, binding->init, binding->onevent); + if (!export) { ERROR("out of memory"); goto error; } - desc->binding = binding; - desc->handle = handle; - desc->export = export; + /* records the binding */ + if (afb_export_declare(export, binding->noconcurrency) < 0) { + ERROR("binding %s can't be registered to set %s...", afb_export_apiname(export), afb_apiset_name(declare_set)); + goto error; + } /* init the binding */ if (binding->preinit) { INFO("binding %s calling preinit function", binding->api); rc = binding->preinit(); if (rc < 0) { - ERROR("binding %s preinit function failed...", afb_export_apiname(desc->export)); + ERROR("binding %s preinit function failed...", afb_export_apiname(export)); + afb_export_undeclare(export); goto error; } } - /* records the binding */ - afb_api.closure = desc; - afb_api.itf = &so_v2_api_itf; - afb_api.group = binding->noconcurrency ? export : NULL; - if (afb_apiset_add(apiset, afb_export_apiname(desc->export), afb_api) < 0) { - ERROR("binding %s can't be registered to set %s...", afb_export_apiname(desc->export), afb_apiset_name(apiset)); - goto error; - } - INFO("binding %s added to set %s", afb_export_apiname(desc->export), afb_apiset_name(apiset)); + INFO("binding %s added to set %s", afb_export_apiname(export), afb_apiset_name(declare_set)); return 1; error: - afb_export_destroy(export); - free(desc); + afb_export_unref(export); return -1; } -int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset) +int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { const struct afb_binding_v2 *binding; struct afb_binding_data_v2 *data; @@ -230,22 +176,17 @@ int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset) ERROR("binding [%s] bad api name...", path); goto error; } - if (!afb_api_is_valid_name(binding->api, 1)) { + if (!afb_api_is_valid_name(binding->api)) { ERROR("binding [%s] invalid api name...", path); goto error; } -#if 0 - if (binding->specification == NULL || *binding->specification == 0) { - ERROR("binding [%s] bad specification...", path); - goto error; - } -#endif + if (binding->verbs == NULL) { ERROR("binding [%s] no verbs...", path); goto error; } - return afb_api_so_v2_add_binding(binding, handle, apiset, data); + return afb_api_so_v2_add_binding(binding, handle, declare_set, call_set, data); error: return -1; diff --git a/src/afb-api-so-v2.h b/src/afb-api-so-v2.h index 87cd80d5..d53206d3 100644 --- a/src/afb-api-so-v2.h +++ b/src/afb-api-so-v2.h @@ -21,6 +21,11 @@ struct afb_apiset; struct afb_binding_v2; struct afb_binding_data_v2; +struct afb_xreq; +struct json_object; -extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *apiset); -extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *apiset, struct afb_binding_data_v2 *data); +extern int afb_api_so_v2_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); +extern int afb_api_so_v2_add_binding(const struct afb_binding_v2 *binding, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set, struct afb_binding_data_v2 *data); + +extern void afb_api_so_v2_process_call(const struct afb_binding_v2 *binding, struct afb_xreq *xreq); +extern struct json_object *afb_api_so_v2_make_description_openAPIv3(const struct afb_binding_v2 *binding, const char *apiname); diff --git a/src/afb-api-so-v3.c b/src/afb-api-so-v3.c new file mode 100644 index 00000000..415c13d9 --- /dev/null +++ b/src/afb-api-so-v3.c @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <dlfcn.h> +#include <assert.h> +#include <stdarg.h> + +#include <json-c/json.h> +#include <afb/afb-binding-v3.h> + +#include "afb-api.h" +#include "afb-api-so-v3.h" +#include "afb-api-v3.h" +#include "afb-apiset.h" +#include "afb-export.h" +#include "verbose.h" + +/* + * names of symbols + */ +static const char afb_api_so_v3_desc[] = "afbBindingV3"; +static const char afb_api_so_v3_root[] = "afbBindingV3root"; +static const char afb_api_so_v3_entry[] = "afbBindingV3entry"; + +struct args +{ + struct afb_api_x3 **root; + const struct afb_binding_v3 *desc; + int (*entry)(struct afb_api_x3 *); +}; + +static int init(void *closure, struct afb_api_x3 *api) +{ + const struct args *a = closure; + int rc = 0; + + *a->root = api; + if (a->desc) { + api->userdata = a->desc->userdata; + rc = afb_api_v3_set_binding_fields(a->desc, api); + } + + if (rc >= 0 && a->entry) + rc = a->entry(api); + + if (rc >= 0) + afb_api_x3_seal(api); + + return rc; +} + +int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) +{ + struct args a; + struct afb_api_v3 *api; + struct afb_export *export; + + /* retrieves the register function */ + a.root = dlsym(handle, afb_api_so_v3_root); + a.desc = dlsym(handle, afb_api_so_v3_desc); + a.entry = dlsym(handle, afb_api_so_v3_entry); + if (!a.root && !a.desc && !a.entry) + return 0; + + INFO("binding [%s] looks like an AFB binding V3", path); + + /* basic checks */ + if (!a.root) { + ERROR("binding [%s] incomplete symbol set: %s is missing", + path, afb_api_so_v3_root); + goto error; + } + if (a.desc) { + if (a.desc->api == NULL || *a.desc->api == 0) { + ERROR("binding [%s] bad api name...", path); + goto error; + } + if (!afb_api_is_valid_name(a.desc->api)) { + ERROR("binding [%s] invalid api name...", path); + goto error; + } + if (!a.entry) + a.entry = a.desc->preinit; + else if (a.desc->preinit) { + ERROR("binding [%s] clash: you can't define %s and %s.preinit, choose only one", + path, afb_api_so_v3_entry, afb_api_so_v3_desc); + goto error; + } + + api = afb_api_v3_create(declare_set, call_set, a.desc->api, a.desc->info, a.desc->noconcurrency, init, &a, 0); + if (api) + return 1; + } else { + if (!a.entry) { + ERROR("binding [%s] incomplete symbol set: %s is missing", + path, afb_api_so_v3_entry); + goto error; + } + + export = afb_export_create_none_for_path(declare_set, call_set, path, init, &a); + if (export) + return 1; + } + + ERROR("binding [%s] initialisation failed", path); + +error: + return -1; +} + diff --git a/src/afb-api-so-v3.h b/src/afb-api-so-v3.h new file mode 100644 index 00000000..52ec22ac --- /dev/null +++ b/src/afb-api-so-v3.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2018 "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_apiset; + +extern int afb_api_so_v3_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-so-vdyn.c b/src/afb-api-so-vdyn.c index 300aa130..17344945 100644 --- a/src/afb-api-so-vdyn.c +++ b/src/afb-api-so-vdyn.c @@ -20,6 +20,10 @@ #include <stdlib.h> #include <dlfcn.h> +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-api-so-v3.h" #include "afb-api-so-vdyn.h" #include "afb-export.h" #include "verbose.h" @@ -29,19 +33,15 @@ */ static const char afb_api_so_vdyn_entry[] = "afbBindingVdyn"; -/* - * Description of a binding - */ -static int vdyn_preinit(void *closure, struct afb_dynapi *dynapi) +static int preinit(void *closure, struct afb_api_x3 *api) { - int (*entry)(struct afb_dynapi*) = closure; - return entry(dynapi); + int (*entry)(struct afb_api_x3*) = closure; + return entry(api); } -int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset) +int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - int rc; - int (*entry)(void*, struct afb_dynapi*); + int (*entry)(struct afb_api_x3*); struct afb_export *export; entry = dlsym(handle, afb_api_so_vdyn_entry); @@ -50,15 +50,12 @@ int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apise INFO("binding [%s] looks like an AFB binding Vdyn", path); - export = afb_export_create_vdyn(apiset, path, NULL); + export = afb_export_create_none_for_path(declare_set, call_set, path, preinit, entry); if (!export) { - ERROR("can't create export for %s", path); + INFO("binding [%s] creation failed", path); return -1; } - INFO("binding [%s] calling dynamic initialisation %s", path, afb_api_so_vdyn_entry); - rc = afb_export_preinit_vdyn(export, vdyn_preinit, entry); - afb_export_destroy(export); - return rc < 0 ? rc : 1; + return 1; } diff --git a/src/afb-api-so-vdyn.h b/src/afb-api-so-vdyn.h index 05d96235..d8a43f75 100644 --- a/src/afb-api-so-vdyn.h +++ b/src/afb-api-so-vdyn.h @@ -20,4 +20,4 @@ struct afb_apiset; -extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *apiset); +extern int afb_api_so_vdyn_add(const char *path, void *handle, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-so.c b/src/afb-api-so.c index 87916cbb..3167ffad 100644 --- a/src/afb-api-so.c +++ b/src/afb-api-so.c @@ -25,12 +25,18 @@ #include <sys/stat.h> #include "afb-api-so.h" -#include "afb-api-so-v1.h" #include "afb-api-so-v2.h" -#include "afb-api-so-vdyn.h" +#include "afb-api-so-v3.h" #include "verbose.h" #include "sig-monitor.h" +#if defined(WITH_LEGACY_BINDING_V1) +# include "afb-api-so-v1.h" +#endif +#if defined(WITH_LEGACY_BINDING_VDYN) +# include "afb-api-so-vdyn.h" +#endif + struct safe_dlopen { const char *path; @@ -59,8 +65,9 @@ static void *safe_dlopen(const char *filename, int flags) return sd.handle; } -static int load_binding(const char *path, int force, struct afb_apiset *apiset) +static int load_binding(const char *path, int force, struct afb_apiset *declare_set, struct afb_apiset * call_set) { + int obsolete = 0; int rc; void *handle; @@ -76,7 +83,16 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset) } /* try the version 2 */ - rc = afb_api_so_v2_add(path, handle, apiset); + rc = afb_api_so_v3_add(path, handle, declare_set, call_set); + if (rc < 0) { + /* error when loading a valid v3 binding */ + goto error2; + } + if (rc) + return 0; /* yes version 2 */ + + /* try the version 2 */ + rc = afb_api_so_v2_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid v2 binding */ goto error2; @@ -84,29 +100,41 @@ static int load_binding(const char *path, int force, struct afb_apiset *apiset) if (rc) return 0; /* yes version 2 */ +#if defined(WITH_LEGACY_BINDING_VDYN) /* try the version dyn */ - rc = afb_api_so_vdyn_add(path, handle, apiset); + rc = afb_api_so_vdyn_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid dyn binding */ goto error2; } if (rc) return 0; /* yes version dyn */ +#else + if (dlsym(handle, "afbBindingVdyn")) { + WARNING("binding [%s]: version DYN not supported", path); + obsolete = 1; + } +#endif +#if defined(WITH_LEGACY_BINDING_V1) /* try the version 1 */ - rc = afb_api_so_v1_add(path, handle, apiset); + rc = afb_api_so_v1_add(path, handle, declare_set, call_set); if (rc < 0) { /* error when loading a valid v1 binding */ goto error2; } if (rc) return 0; /* yes version 1 */ +#else + if (dlsym(handle, "afbBindingV1Register")) { + WARNING("binding [%s]: version 1 not supported", path); + obsolete = 1; + } +#endif /* not a valid binding */ - if (force) - ERROR("binding [%s] is not an AFB binding", path); - else - INFO("binding [%s] is not an AFB binding", path); + _VERBOSE_(force ? Log_Level_Error : Log_Level_Info, "binding [%s] %s", + path, obsolete ? "is obsolete" : "isn't an AFB binding"); error2: dlclose(handle); @@ -115,12 +143,12 @@ error: } -int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset) +int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return load_binding(path, 1, apiset); + return load_binding(path, 1, declare_set, call_set); } -static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, int failstops) +static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { DIR *dir; struct dirent *dent; @@ -159,12 +187,12 @@ static int adddirs(char path[PATH_MAX], size_t end, struct afb_apiset *apiset, i Exclude from the search of bindings any directory starting with a dot (.) by default. -It is possible to reactivate the prvious behaviour +It is possible to reactivate the prvious behaviour by defining the following preprocessor variables - AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS - When this variable is defined, the directories + When this variable is defined, the directories starting with a dot are searched except if their name is "." or ".." or ".debug" @@ -181,7 +209,7 @@ This change is intended to definitely solve the issue SPEC-662. Yocto installed the debugging symbols in the subdirectory .debug. For example the binding.so also had a .debug/binding.so file attached. Opening that -debug file made dlopen crashing. +debug file made dlopen crashing. See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 */ #if !defined(AFB_API_SO_ACCEPT_DOT_PREFIXED_DIRS) /* not defined by default */ @@ -203,13 +231,13 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 #endif } memcpy(&path[end], dent->d_name, len+1); - rc = adddirs(path, end+len, apiset, failstops); + rc = adddirs(path, end+len, declare_set, call_set, failstops); } 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); - rc = load_binding(path, 0, apiset); + rc = load_binding(path, 0, declare_set, call_set); } if (rc < 0 && failstops) { closedir(dir); @@ -220,7 +248,7 @@ See https://sourceware.org/bugzilla/show_bug.cgi?id=22101 return 0; } -int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { size_t length; char buffer[PATH_MAX]; @@ -232,10 +260,10 @@ int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int fa } memcpy(buffer, path, length + 1); - return adddirs(buffer, length, apiset, failstops); + return adddirs(buffer, length, declare_set, call_set, failstops); } -int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { struct stat st; int rc; @@ -244,15 +272,15 @@ int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failsto if (rc < 0) ERROR("Invalid binding path [%s]: %m", path); else if (S_ISDIR(st.st_mode)) - rc = afb_api_so_add_directory(path, apiset, failstops); + rc = afb_api_so_add_directory(path, declare_set, call_set, failstops); else if (strstr(path, ".so")) - rc = load_binding(path, 0, apiset); + rc = load_binding(path, 0, declare_set, call_set); else INFO("not a binding [%s], skipped", path); return rc; } -int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops) +int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops) { static char sep[] = ":"; char *ps, *p; @@ -263,19 +291,19 @@ int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int f p = strsep(&ps, sep); if (!p) return 0; - rc = afb_api_so_add_path(p, apiset, failstops); + rc = afb_api_so_add_path(p, declare_set, call_set, failstops); if (rc < 0) return rc; } } -int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset) +int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return afb_api_so_add_pathset(pathset, apiset, 1); + return afb_api_so_add_pathset(pathset, declare_set, call_set, 1); } -int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset) +int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set) { - return afb_api_so_add_pathset(pathset, apiset, 0); + return afb_api_so_add_pathset(pathset, declare_set, call_set, 0); } diff --git a/src/afb-api-so.h b/src/afb-api-so.h index d37f77c6..e6527469 100644 --- a/src/afb-api-so.h +++ b/src/afb-api-so.h @@ -20,15 +20,15 @@ struct afb_apiset; -extern int afb_api_so_add_binding(const char *path, struct afb_apiset *apiset); +extern int afb_api_so_add_binding(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set); -extern int afb_api_so_add_directory(const char *path, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_directory(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_path(const char *path, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_path(const char *path, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *apiset, int failstops); +extern int afb_api_so_add_pathset(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set, int failstops); -extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *apiset); -extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *apiset); +extern int afb_api_so_add_pathset_fails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set); +extern int afb_api_so_add_pathset_nofails(const char *pathset, struct afb_apiset *declare_set, struct afb_apiset * call_set); diff --git a/src/afb-api-v3.c b/src/afb-api-v3.c new file mode 100644 index 00000000..8c755f94 --- /dev/null +++ b/src/afb-api-v3.c @@ -0,0 +1,358 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <errno.h> +#include <fnmatch.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-api.h" +#include "afb-api-v3.h" +#include "afb-apiset.h" +#include "afb-auth.h" +#include "afb-export.h" +#include "afb-xreq.h" +#include "verbose.h" + +/* + * Description of a binding + */ +struct afb_api_v3 { + int refcount; + int count; + struct afb_verb_v3 **verbs; + const struct afb_verb_v2 *verbsv2; + const struct afb_verb_v3 *verbsv3; + struct afb_export *export; + const char *info; +}; + +static const char nulchar = 0; + +static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name) +{ + return verb->glob + ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD) + : strcasecmp(verb->verb, name); +} + +static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name) +{ + struct afb_verb_v3 **v, **e, *i; + + v = api->verbs; + e = &v[api->count]; + while (v != e) { + i = *v; + if (!verb_name_compare(i, name)) + return i; + v++; + } + return 0; +} + +void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq) +{ + const struct afb_verb_v3 *verbsv3; + const struct afb_verb_v2 *verbsv2; + const char *name; + + name = xreq->request.called_verb; + + /* look first in dynamic set */ + verbsv3 = search_dynamic_verb(api, name); + if (!verbsv3) { + /* look then in static set */ + verbsv3 = api->verbsv3; + while (verbsv3) { + if (!verbsv3->verb) + verbsv3 = 0; + else if (!verb_name_compare(verbsv3, name)) + break; + else + verbsv3++; + } + } + /* is it a v3 verb ? */ + if (verbsv3) { + /* yes */ + xreq->request.vcbdata = verbsv3->vcbdata; + afb_xreq_call_verb_v3(xreq, verbsv3); + return; + } + + /* look in legacy set */ + verbsv2 = api->verbsv2; + if (verbsv2) { + while (verbsv2->verb) { + if (strcasecmp(verbsv2->verb, name)) + verbsv2++; + else { + afb_xreq_call_verb_v2(xreq, verbsv2); + return; + } + } + } + + afb_xreq_reply_unknown_verb(xreq); +} + +struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname) +{ + char buffer[256]; + struct afb_verb_v3 **iter, **end, *verb; + struct json_object *r, *f, *a, *i, *p, *g; + + r = json_object_new_object(); + json_object_object_add(r, "openapi", json_object_new_string("3.0.0")); + + i = json_object_new_object(); + json_object_object_add(r, "info", i); + json_object_object_add(i, "title", json_object_new_string(apiname)); + json_object_object_add(i, "version", json_object_new_string("0.0.0")); + json_object_object_add(i, "description", json_object_new_string(api->info)); + + p = json_object_new_object(); + json_object_object_add(r, "paths", p); + iter = api->verbs; + end = iter + api->count; + while (iter != end) { + verb = *iter++; + buffer[0] = '/'; + strncpy(buffer + 1, verb->verb, sizeof buffer - 1); + buffer[sizeof buffer - 1] = 0; + f = json_object_new_object(); + json_object_object_add(p, buffer, f); + g = json_object_new_object(); + json_object_object_add(f, "get", g); + + a = afb_auth_json_v2(verb->auth, verb->session); + if (a) + json_object_object_add(g, "x-permissions", a); + + a = json_object_new_object(); + json_object_object_add(g, "responses", a); + f = json_object_new_object(); + json_object_object_add(a, "200", f); + json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb)); + } + return r; +} + +struct afb_api_v3 *afb_api_v3_create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure, + int copy_info +) +{ + struct afb_api_v3 *api; + + /* allocates the description */ + api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0)); + if (!api) + goto oom; + api->refcount = 1; + if (!info) + api->info = &nulchar; + else if (copy_info) + api->info = strcpy((char*)(api + 1), info); + else + api->info = info; + + api->export = afb_export_create_v3(declare_set, call_set, apiname, api); + if (!api->export) + goto oom2; + + if (afb_export_declare(api->export, noconcurrency) < 0) + goto oom3; + + if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0) + goto oom4; + + return api; + +oom4: + afb_export_undeclare(api->export); +oom3: + afb_export_unref(api->export); +oom2: + free(api); +oom: + ERROR("out of memory"); + return NULL; +} + +struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api) +{ + if (api) + __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED); + return api; +} + +void afb_api_v3_unref(struct afb_api_v3 *api) +{ + if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) { + afb_export_destroy(api->export); + free(api); + } +} + +struct afb_export *afb_api_v3_export(struct afb_api_v3 *api) +{ + return api->export; +} + +void afb_api_v3_set_verbs_v2( + struct afb_api_v3 *api, + const struct afb_verb_v2 *verbs) +{ + api->verbsv2 = verbs; +} + +void afb_api_v3_set_verbs_v3( + struct afb_api_v3 *api, + const struct afb_verb_v3 *verbs) +{ + api->verbsv3 = verbs; +} + +int afb_api_v3_add_verb( + struct afb_api_v3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint16_t session, + int glob) +{ + struct afb_verb_v3 *v, **vv; + char *txt; + int i; + + for (i = 0 ; i < api->count ; i++) { + v = api->verbs[i]; + if (glob == v->glob && !strcasecmp(verb, v->verb)) { + /* refuse to redefine a dynamic verb */ + errno = EEXIST; + return -1; + } + } + + vv = realloc(api->verbs, (1 + api->count) * sizeof *vv); + if (!vv) + goto oom; + api->verbs = vv; + + v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0)); + if (!v) + goto oom; + + v->callback = callback; + v->vcbdata = vcbdata; + v->auth = auth; + v->session = session; + v->glob = !!glob; + + txt = (char*)(v + 1); + v->verb = txt; + txt = stpcpy(txt, verb); + if (!info) + v->info = NULL; + else { + v->info = ++txt; + strcpy(txt, info); + } + + api->verbs[api->count++] = v; + return 0; +oom: + errno = ENOMEM; + return -1; +} + +int afb_api_v3_del_verb( + struct afb_api_v3 *api, + const char *verb, + void **vcbdata) +{ + struct afb_verb_v3 **v, **e, *i; + + v = api->verbs; + e = &v[api->count]; + while (v != e) { + i = *v++; + if (!strcasecmp(i->verb, verb)) { + api->count--; + if (vcbdata) + *vcbdata = i->vcbdata; + if (v != e) + *--v = *--e; + free(i); + return 0; + } + } + + errno = ENOENT; + return -1; +} + +int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api) +{ + int rc = 0; + if (desc->verbs) + rc = afb_api_x3_set_verbs_v3(api, desc->verbs); + if (!rc && desc->onevent) + rc = afb_api_x3_on_event(api, desc->onevent); + if (!rc && desc->init) + rc = afb_api_x3_on_init(api, desc->init); + if (!rc && desc->provide_class) + rc = afb_api_x3_provide_class(api, desc->provide_class); + if (!rc && desc->require_class) + rc = afb_api_x3_require_class(api, desc->require_class); + if (!rc && desc->require_api) + rc = afb_api_x3_require_api(api, desc->require_api, 1); + return rc; +} + +static int init_binding(void *closure, struct afb_api_x3 *api) +{ + const struct afb_binding_v3 *desc = closure; + int rc = afb_api_v3_set_binding_fields(desc, api); + if (!rc && desc->preinit) + rc = desc->preinit(api); + return rc; +} + +struct afb_api_v3 *afb_api_v3_from_binding(const struct afb_binding_v3 *desc, struct afb_apiset *declare_set, struct afb_apiset * call_set) +{ + return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0); +} + diff --git a/src/afb-api-v3.h b/src/afb-api-v3.h new file mode 100644 index 00000000..33649f35 --- /dev/null +++ b/src/afb-api-v3.h @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2016, 2017, 2018 "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_apiset; +struct afb_api_v3; +struct afb_api_x3; +struct afb_auth; +struct afb_req_x2; +struct afb_verb_v2; +struct afb_verb_v3; +struct afb_binding_v3; +struct afb_xreq; +struct json_object; +struct afb_export; + +extern struct afb_api_v3 *afb_api_v3_create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const char *info, + int noconcurrency, + int (*preinit)(void*, struct afb_api_x3 *), + void *closure, + int copy_info +); + +extern struct afb_api_v3 *afb_api_v3_from_binding( + const struct afb_binding_v3 *desc, + struct afb_apiset *declare_set, + struct afb_apiset * call_set); + +extern int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api); + +extern struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api); +extern void afb_api_v3_unref(struct afb_api_v3 *api); + +extern struct afb_export *afb_api_v3_export(struct afb_api_v3 *api); + +extern void afb_api_v3_set_verbs_v2( + struct afb_api_v3 *api, + const struct afb_verb_v2 *verbs); + +extern void afb_api_v3_set_verbs_v3( + struct afb_api_v3 *api, + const struct afb_verb_v3 *verbs); + +extern int afb_api_v3_add_verb( + struct afb_api_v3 *api, + const char *verb, + const char *info, + void (*callback)(struct afb_req_x2 *req), + void *vcbdata, + const struct afb_auth *auth, + uint16_t session, + int glob); + +extern int afb_api_v3_del_verb( + struct afb_api_v3 *api, + const char *verb, + void **vcbdata); + +extern void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq); +extern struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname); + diff --git a/src/afb-api-ws.c b/src/afb-api-ws.c index 190c2fd8..c1ccd329 100644 --- a/src/afb-api-ws.c +++ b/src/afb-api-ws.c @@ -34,6 +34,7 @@ #include "afb-systemd.h" #include "afb-api.h" #include "afb-apiset.h" +#include "afb-api-ws.h" #include "afb-stub-ws.h" #include "verbose.h" #include "fdev.h" @@ -72,7 +73,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_api_is_valid_name(api->api, 1)) { + if (api->api == NULL || !afb_api_is_valid_name(api->api)) { errno = EINVAL; goto error2; } @@ -219,7 +220,7 @@ static struct fdev *api_ws_socket_fdev(const char *path, int server) /**********************************************************************************/ -int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong) +int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong) { struct api_ws *apiws; struct afb_stub_ws *stubws; @@ -234,12 +235,12 @@ int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int stron if (!apiws->fdev) goto error2; - stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, apiset); + stubws = afb_stub_ws_create_client(apiws->fdev, apiws->api, call_set); if (!stubws) { ERROR("can't setup client ws service to %s", apiws->path); goto error3; } - if (afb_stub_ws_client_add(stubws, apiset) < 0) { + if (afb_stub_ws_client_add(stubws, declare_set) < 0) { ERROR("can't add the client to the apiset for service %s", apiws->path); goto error3; } @@ -253,14 +254,14 @@ error: return -!!strong; } -int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_ws_add_client(path, apiset, 1); + return afb_api_ws_add_client(path, declare_set, call_set, 1); } -int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_ws_add_client(path, apiset, 0); + return afb_api_ws_add_client(path, declare_set, call_set, 0); } static int api_ws_server_accept_client(struct api_ws *apiws, struct fdev *fdev) @@ -329,7 +330,7 @@ static int api_ws_server_connect(struct api_ws *apiws) } /* create the service */ -int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) +int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) { int rc; struct api_ws *apiws; @@ -340,7 +341,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) goto error; /* check api name */ - if (!afb_apiset_lookup(apiset, apiws->api, 1)) { + if (!afb_apiset_lookup(call_set, apiws->api, 1)) { ERROR("Can't provide ws-server for %s: API %s doesn't exist", path, apiws->api); goto error2; } @@ -350,7 +351,7 @@ int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset) if (rc < 0) goto error2; - apiws->apiset = afb_apiset_addref(apiset); + apiws->apiset = afb_apiset_addref(call_set); return 0; error2: diff --git a/src/afb-api-ws.h b/src/afb-api-ws.h index 123efb73..812cff59 100644 --- a/src/afb-api-ws.h +++ b/src/afb-api-ws.h @@ -20,10 +20,10 @@ struct afb_apiset; -extern int afb_api_ws_add_client(const char *path, struct afb_apiset *apiset, int strong); -extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *apiset); -extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *apiset); +extern int afb_api_ws_add_client(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int strong); +extern int afb_api_ws_add_client_strong(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); +extern int afb_api_ws_add_client_weak(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); -extern int afb_api_ws_add_server(const char *path, struct afb_apiset *apiset); +extern int afb_api_ws_add_server(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-api.c b/src/afb-api.c index 54ee5945..de603d3e 100644 --- a/src/afb-api.c +++ b/src/afb-api.c @@ -29,7 +29,7 @@ * Checks wether 'name' is a valid API name. * @return 1 if valid, 0 otherwise */ -int afb_api_is_valid_name(const char *name, int hookable) +int afb_api_is_valid_name(const char *name) { unsigned char c; @@ -60,6 +60,6 @@ int afb_api_is_valid_name(const char *name, int hookable) } c = (unsigned char)*++name; } while(c != 0); - return !hookable || afb_api_is_hookable(name); + return 1; } diff --git a/src/afb-api.h b/src/afb-api.h index 3f2e7f15..d03aaca5 100644 --- a/src/afb-api.h +++ b/src/afb-api.h @@ -24,24 +24,21 @@ struct json_object; struct afb_api_itf { void (*call)(void *closure, struct afb_xreq *xreq); - int (*service_start)(void *closure, int share_session, int onneed, struct afb_apiset *apiset); + int (*service_start)(void *closure, int share_session, int onneed); void (*update_hooks)(void *closure); - int (*get_verbosity)(void *closure); - void (*set_verbosity)(void *closure, int level); + int (*get_logmask)(void *closure); + void (*set_logmask)(void *closure, int level); struct json_object *(*describe)(void *closure); void (*unref)(void *closure); }; -struct afb_api +struct afb_api_item { void *closure; struct afb_api_itf *itf; const void *group; }; -extern int afb_api_is_valid_name(const char *name, int hookable); +extern int afb_api_is_valid_name(const char *name); -#define AFB_API_UNHOOKABLE_PREFIX_CHAR '$' -#define AFB_API_UNHOOKABLE_PREFIX_STRING "$" -#define afb_api_is_hookable(api) ((api)[0] != AFB_API_UNHOOKABLE_PREFIX_CHAR) diff --git a/src/afb-apiset.c b/src/afb-apiset.c index 8d76bbfe..af5a8652 100644 --- a/src/afb-apiset.c +++ b/src/afb-apiset.c @@ -1,6 +1,5 @@ /* * Copyright (C) 2016, 2017, 2018 "IoT.bzh" - * Author "Fulup Ar Foll" * Author José Bollo <jose.bollo@iot.bzh> * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,14 +31,68 @@ #define INCR 8 /* CAUTION: must be a power of 2 */ +struct afb_apiset; +struct api_desc; +struct api_class; +struct api_alias; +struct api_depend; + +/** + * array of items + */ +struct api_array { + int count; /* count of items */ + union { + void **anys; + struct api_desc **apis; + struct api_class **classes; + struct api_alias **aliases; + struct api_depend **depends; + }; +}; + /** * Internal description of an api */ struct api_desc { - int status; - const char *name; /**< name of the api */ - struct afb_api api; /**< handler of the api */ + struct api_desc *next; + const char *name; /**< name of the api */ + int status; /**< initialisation status */ + struct afb_api_item api; /**< handler of the api */ + struct { + struct api_array classes; + struct api_array apis; + } require; +}; + +/** + * internal description of aliases + */ +struct api_alias +{ + struct api_alias *next; + struct api_desc *api; + char name[1]; +}; + +/** + * + */ +struct api_class +{ + struct api_class *next; + struct api_array providers; + char name[1]; +}; + +/** + * + */ +struct api_depend +{ + struct afb_apiset *set; + char name[1]; }; /** @@ -47,15 +100,133 @@ struct api_desc */ struct afb_apiset { - struct api_desc *apis; /**< description of apis */ + struct api_array apis; /**< the apis */ + struct api_alias *aliases; /**< the aliases */ struct afb_apiset *subset; /**< subset if any */ - int count; /**< count of apis in the set */ + struct { + int (*callback)(void*, struct afb_apiset*, const char*); /* not found handler */ + void *closure; + void (*cleanup)(void*); + } onlack; /** not found handler */ int timeout; /**< the timeout in second for the apiset */ int refcount; /**< reference count for freeing resources */ char name[1]; /**< name of the apiset */ }; /** + * global apis + */ +static struct api_desc *all_apis; + +/** + * global classes + */ +static struct api_class *all_classes; + +/** + * Ensure enough room in 'array' for 'count' items + */ +static int api_array_ensure_count(struct api_array *array, int count) +{ + int c; + void **anys; + + c = (count + INCR - 1) & ~(INCR - 1); + anys = realloc(array->anys, c * sizeof *anys); + if (!anys) { + errno = ENOMEM; + return -1; + } + + array->count = count; + array->anys = anys; + return 0; +} + +/** + * Insert in 'array' the item 'any' at the 'index' + */ +static int api_array_insert(struct api_array *array, void *any, int index) +{ + int n = array->count; + + if (api_array_ensure_count(array, n + 1) < 0) + return -1; + + while (index < n) { + array->anys[n] = array->anys[n - 1]; + n--; + } + + array->anys[index] = any; + return 0; +} + +/** + * Add the item 'any' to the 'array' + */ +static int api_array_add(struct api_array *array, void *any) +{ + int i, n = array->count; + + for (i = 0 ; i < n ; i++) { + if (array->anys[i] == any) + return 0; + } + + if (api_array_ensure_count(array, n + 1) < 0) + return -1; + + array->anys[n] = any; + return 0; +} + +/** + * Delete the 'api' from the 'array' + * Returns 1 if delete or 0 if not found + */ +static int api_array_del(struct api_array *array, void *any) +{ + int i = array->count; + while (i) { + if (array->anys[--i] == any) { + array->anys[i] = array->anys[--array->count]; + return 1; + } + } + return 0; +} + +/** + * Search the class of 'name' and return it. + * In case where the class of 'namle' isn't found, it returns + * NULL when 'create' is null or a fresh created instance if 'create' isn't + * zero (but NULL on allocation failure). + */ +static struct api_class *class_search(const char *name, int create) +{ + struct api_class *c; + + for (c= all_classes ; c ; c = c->next) { + if (!strcasecmp(name, c->name)) + return c; + } + + if (!create) + return NULL; + + c = calloc(1, strlen(name) + sizeof *c); + if (!c) + errno = ENOMEM; + else { + strcpy(c->name, name); + c->next = all_classes; + all_classes = c; + } + return c; +} + +/** * Search the api of 'name'. * @param set the api set * @param name the api name to search @@ -65,20 +236,16 @@ static struct api_desc *search(struct afb_apiset *set, const char *name) { int i, c, up, lo; struct api_desc *a; + struct api_alias *aliases; /* dichotomic search of the api */ /* initial slice */ lo = 0; - up = set->count; - for (;;) { - /* check remaining slice */ - if (lo >= up) { - /* not found */ - return NULL; - } + up = set->apis.count; + while (lo < up) { /* check the mid of the slice */ i = (lo + up) >> 1; - a = &set->apis[i]; + a = set->apis.apis[i]; c = strcasecmp(a->name, name); if (c == 0) { /* found */ @@ -90,6 +257,37 @@ static struct api_desc *search(struct afb_apiset *set, const char *name) else up = i; } + + /* linear search of aliases */ + aliases = set->aliases; + for(;;) { + if (!aliases) + break; + c = strcasecmp(aliases->name, name); + if (!c) + return aliases->api; + if (c > 0) + break; + aliases = aliases->next; + } + return NULL; +} + +/** + * Search the api of 'name' in the apiset and in its subsets. + * @param set the api set + * @param name the api name to search + * @return the descriptor if found or NULL otherwise + */ +static struct api_desc *searchrec(struct afb_apiset *set, const char *name) +{ + struct api_desc *result; + + do { + result = search(set, name); + } while (result == NULL && (set = set->subset) != NULL); + + return result; } /** @@ -111,9 +309,24 @@ struct afb_apiset *afb_apiset_addref(struct afb_apiset *set) */ void afb_apiset_unref(struct afb_apiset *set) { + struct api_alias *a; + struct api_desc *d; + if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) { afb_apiset_unref(set->subset); - free(set->apis); + if (set->onlack.cleanup) + set->onlack.cleanup(set->onlack.closure); + while((a = set->aliases)) { + set->aliases = a->next; + free(a); + } + while (set->apis.count) { + d = set->apis.apis[--set->apis.count]; + if (d->api.itf->unref) + d->api.itf->unref(d->api.closure); + free(d); + } + free(set->apis.apis); free(set); } } @@ -128,22 +341,49 @@ struct afb_apiset *afb_apiset_create(const char *name, int timeout) { struct afb_apiset *set; - set = malloc((name ? strlen(name) : 0) + sizeof *set); + set = calloc(1, (name ? strlen(name) : 0) + sizeof *set); if (set) { - set->apis = malloc(INCR * sizeof *set->apis); - set->count = 0; set->timeout = timeout; set->refcount = 1; - set->subset = NULL; if (name) strcpy(set->name, name); - else - set->name[0] = 0; } return set; } /** + * Create an apiset being the last subset of 'set' + * @param set the set to extend with the created subset (can be NULL) + * @param name the name of the created apiset (can be NULL) + * @param timeout the default timeout in seconds for the created apiset + * @return the created apiset or NULL in case of error + */ +struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout) +{ + if (set) + while (set->subset) + set = set->subset; + return afb_apiset_create_subset_first(set, name, timeout); +} + +/** + * Create an apiset being the first subset of 'set' + * @param set the set to extend with the created subset (can be NULL) + * @param name the name of the created apiset (can be NULL) + * @param timeout the default timeout in seconds for the created apiset + * @return the created apiset or NULL in case of error + */ +struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout) +{ + struct afb_apiset *result = afb_apiset_create(name, timeout); + if (result && set) { + result->subset = set->subset; + set->subset = result; + } + return result; +} + +/** * the name of the apiset * @param set the api set * @return the name of the set @@ -200,6 +440,15 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset) afb_apiset_unref(tmp); } +void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*)) +{ + if (set->onlack.cleanup) + set->onlack.cleanup(set->onlack.closure); + set->onlack.callback = callback; + set->onlack.closure = closure; + set->onlack.cleanup = cleanup; +} + /** * Adds the api of 'name' described by 'api'. * @param set the api set @@ -210,52 +459,117 @@ void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset) * - EEXIST if name already registered * - ENOMEM when out of memory */ -int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api) +int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api) { - struct api_desc *apis; + struct api_desc *desc; int i, c; - /* check previously existing plugin */ - 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; - goto error; - } + /* check whether it exists already */ + if (search(set, name)) { + ERROR("api of name %s already exists", name); + errno = EEXIST; + goto error; + } + + /* search insertion place */ + for (i = 0 ; i < set->apis.count ; i++) { + c = strcasecmp(set->apis.apis[i]->name, name); if (c > 0) break; } - /* allocates enough memory */ - c = (set->count + INCR) & ~(INCR - 1); - apis = realloc(set->apis, ((unsigned)c) * sizeof * apis); - if (apis == NULL) { - ERROR("out of memory"); - errno = ENOMEM; + /* allocates memory */ + desc = calloc(1, sizeof *desc); + if (!desc) + goto oom; + + desc->status = -1; + desc->api = api; + desc->name = name; + + if (api_array_insert(&set->apis, desc, i) < 0) { + free(desc); goto error; } - set->apis = apis; - /* copy higher part of the array */ - apis += i; - if (i != set->count) - memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis); - - /* record the plugin */ - apis->status = -1; - apis->api = api; - apis->name = name; - set->count++; + desc->next = all_apis; + all_apis = desc; INFO("API %s added", name); return 0; +oom: + ERROR("out of memory"); + errno = ENOMEM; +error: + return -1; +} + +/** + * Adds a the 'alias' name to the api of 'name'. + * @params set the api set + * @param name the name of the api to alias + * @param alias the aliased name to add to the api of name + * @returns 0 in case of success or -1 in case + * of error with errno set: + * - ENOENT if the api doesn't exist + * - EEXIST if name (of alias) already registered + * - ENOMEM when out of memory + */ +int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias) +{ + struct api_desc *api; + struct api_alias *ali, **pali; + + /* check alias doesn't already exist */ + if (search(set, alias)) { + ERROR("api of name %s already exists", alias); + errno = EEXIST; + goto error; + } + + /* check aliased api exists */ + api = search(set, name); + if (api == NULL) { + ERROR("api of name %s doesn't exists", name); + errno = ENOENT; + goto error; + } + + /* allocates and init the struct */ + ali = malloc(sizeof *ali + strlen(alias)); + if (ali == NULL) { + ERROR("out of memory"); + errno = ENOMEM; + goto error; + } + ali->api = api; + strcpy(ali->name, alias); + + /* insert the alias in the sorted order */ + pali = &set->aliases; + while(*pali && strcmp((*pali)->name, alias) < 0) + pali = &(*pali)->next; + ali->next = *pali; + *pali = ali; + return 0; error: return -1; } +int afb_apiset_is_alias(struct afb_apiset *set, const char *name) +{ + struct api_desc *api = searchrec(set, name); + return api && strcasecmp(api->name, name); +} + +const char *afb_apiset_unalias(struct afb_apiset *set, const char *name) +{ + struct api_desc *api = searchrec(set, name); + return api ? api->name : NULL; +} + /** * Delete from the 'set' the api of 'name'. * @param set the set to be changed @@ -264,28 +578,72 @@ error: */ int afb_apiset_del(struct afb_apiset *set, const char *name) { - struct api_desc *i, *e; - int c; + struct api_class *cla; + struct api_alias *ali, **pali; + struct api_desc *desc, **pdesc, *odesc; + int i, c; + + /* search the alias */ + pali = &set->aliases; + while ((ali = *pali)) { + c = strcasecmp(ali->name, name); + if (!c) { + *pali = ali->next; + free(ali); + return 0; + } + if (c > 0) + break; + pali = &ali->next; + } /* search the api */ - i = set->apis; - e = i + set->count; - while (i != e) { - c = strcasecmp(i->name, name); + for (i = 0 ; i < set->apis.count ; i++) { + desc = set->apis.apis[i]; + c = strcasecmp(desc->name, name); if (c == 0) { - if (i->api.itf->unref) - i->api.itf->unref(i->api.closure); - set->count--; - e--; - while (i != e) { - i[0] = i[1]; + /* remove from classes */ + for (cla = all_classes ; cla ; cla = cla->next) + api_array_del(&cla->providers, desc); + + /* unlink from the whole set and their requires */ + pdesc = &all_apis; + while ((odesc = *pdesc) != desc) { + pdesc = &odesc->next; + } + *pdesc = odesc = desc->next; + while (odesc) { + odesc = odesc->next; + } + + /* remove references from classes */ + free(desc->require.classes.classes); + + /* drop the aliases */ + pali = &set->aliases; + while ((ali = *pali)) { + if (ali->api != desc) + pali = &ali->next; + else { + *pali = ali->next; + free(ali); + } + } + + /* unref the api */ + if (desc->api.itf->unref) + desc->api.itf->unref(desc->api.closure); + + set->apis.count--; + while(i < set->apis.count) { + set->apis.apis[i] = set->apis.apis[i + 1]; i++; } + free(desc); return 0; } if (c > 0) break; - i++; } errno = ENOENT; return -1; @@ -300,8 +658,21 @@ int afb_apiset_del(struct afb_apiset *set, const char *name) */ static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec) { - struct api_desc *i = search(set, name); - return i || !rec || !set->subset ? i : lookup(set->subset, name, rec); + struct api_desc *result; + + result = search(set, name); + while (!result) { + /* lacking the api, try onlack behaviour */ + if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) { + result = search(set, name); + if (result) + break; + } + if (!rec || !(set = set->subset)) + break; + result = search(set, name); + } + return result; } /** @@ -311,7 +682,7 @@ static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec * @param rec if not zero look also recursively in subsets * @return the api pointer in case of success or NULL in case of error */ -const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec) +const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec) { struct api_desc *i; @@ -322,6 +693,78 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name return NULL; } +static int start_api(struct api_desc *api, int share_session, int onneed); + +/** + * Start the apis of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_apis(struct api_array *array, int share_session) +{ + int i, rc = 0, rc2; + + i = array->count; + while (i) { + rc2 = start_api(array->apis[--i], share_session, 1); + if (rc2 < 0) { + rc = rc2; + } + } + return rc; +} + +/** + * Start the class 'cla' (start the apis that provide it). + * The attribute 'share_session' is sent to the start function. + */ +static int start_class(struct api_class *cla, int share_session) +{ + return start_array_apis(&cla->providers, share_session); +} + +/** + * Start the classes of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_classes(struct api_array *array, int share_session) +{ + int i, rc = 0, rc2; + + i = array->count; + while (i) { + rc2 = start_class(array->classes[--i], share_session); + if (rc2 < 0) { + rc = rc2; + } + } + return rc; +} + +/** + * Start the depends of the 'array' + * The attribute 'share_session' is sent to the start function. + */ +static int start_array_depends(struct api_array *array, int share_session) +{ + struct api_desc *api; + int i, rc = 0, rc2; + + i = array->count; + while (i) { + i--; + api = searchrec(array->depends[i]->set, array->depends[i]->name); + if (!api) + rc = -1; + else { + rc2 = start_api(api, share_session, 1); + if (rc2 < 0) { + rc = rc2; + } + } + } + return rc; +} + /** * Starts the service 'api'. * @param api the api @@ -331,7 +774,7 @@ const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name * must be a service * @return a positive number on success */ -static int start_api(struct afb_apiset *set, struct api_desc *api, int share_session, int onneed) +static int start_api(struct api_desc *api, int share_session, int onneed) { int rc; @@ -343,9 +786,11 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses } INFO("API %s starting...", api->name); + rc = start_array_classes(&api->require.classes, share_session); + rc = start_array_depends(&api->require.apis, share_session); if (api->api.itf->service_start) { api->status = EBUSY; - rc = api->api.itf->service_start(api->api.closure, share_session, onneed, set); + rc = api->api.itf->service_start(api->api.closure, share_session, onneed); if (rc < 0) { api->status = errno ?: ECANCELED; ERROR("The api %s failed to start (%d)", api->name, rc); @@ -369,13 +814,13 @@ static int start_api(struct afb_apiset *set, struct api_desc *api, int share_ses * @param rec if not zero look also recursively in subsets * @return 0 in case of success or -1 in case of error */ -const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec) +const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec) { struct api_desc *i; i = lookup(set, name, rec); if (i) - return i->status && start_api(set, i, 1, 1) ? NULL : &i->api; + return i->status && start_api(i, 1, 1) ? NULL : &i->api; errno = ENOENT; return NULL; } @@ -394,14 +839,14 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share { struct api_desc *a; - a = search(set, name); + a = searchrec(set, name); if (!a) { ERROR("can't find service %s", name); errno = ENOENT; return -1; } - return start_api(set, a, share_session, onneed); + return start_api(a, share_session, onneed); } /** @@ -414,18 +859,19 @@ int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) { int rc; - struct api_desc *i, *e; + int i; - i = set->apis; - e = &set->apis[set->count]; - while (i != e) { - rc = start_api(set, i, share_session, 1); - if (rc < 0) - return rc; - i++; + while (set) { + i = 0; + while (i < set->apis.count) { + rc = start_api(set->apis.apis[i], share_session, 1); + if (rc < 0) + return rc; + i++; + } + set = set->subset; } - - return set->subset ? afb_apiset_start_all_services(set->subset, share_session) : 0; + return 0; } /** @@ -435,65 +881,66 @@ int afb_apiset_start_all_services(struct afb_apiset *set, int share_session) */ void afb_apiset_update_hooks(struct afb_apiset *set, const char *name) { - const struct api_desc *i, *e; + struct api_desc **i, **e, *d; if (!name) { - i = set->apis; - e = &set->apis[set->count]; + i = set->apis.apis; + e = &set->apis.apis[set->apis.count]; + while (i != e) { + d = *i++; + if (d->api.itf->update_hooks) + d->api.itf->update_hooks(d->api.closure); + } } else { - i = search(set, name); - e = &i[!!i]; - } - while (i != e) { - if (i->api.itf->update_hooks) - i->api.itf->update_hooks(i->api.closure); - i++; + d = searchrec(set, name); + if (d && d->api.itf->update_hooks) + d->api.itf->update_hooks(d->api.closure); } } /** - * Set the verbosity level of the 'api' + * Set the logmask of the 'api' to 'mask' * @param set the api set * @param name the api to set (NULL set all) */ -void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level) +void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask) { - const struct api_desc *i, *e; + int i; + struct api_desc *d; if (!name) { - i = set->apis; - e = &set->apis[set->count]; + for (i = 0 ; i < set->apis.count ; i++) { + d = set->apis.apis[i];; + if (d->api.itf->set_logmask) + d->api.itf->set_logmask(d->api.closure, mask); + } } else { - i = search(set, name); - e = &i[!!i]; - } - while (i != e) { - if (i->api.itf->set_verbosity) - i->api.itf->set_verbosity(i->api.closure, level); - i++; + d = searchrec(set, name); + if (d && d->api.itf->set_logmask) + d->api.itf->set_logmask(d->api.closure, mask); } } /** - * Get the verbosity level of the 'api' + * Get the logmask level of the 'api' * @param set the api set * @param name the api to get - * @return the verbosity level or -1 in case of error + * @return the logmask level or -1 in case of error */ -int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name) +int afb_apiset_get_logmask(struct afb_apiset *set, const char *name) { const struct api_desc *i; - i = name ? search(set, name) : NULL; + i = name ? searchrec(set, name) : NULL; if (!i) { errno = ENOENT; return -1; } - if (!i->api.itf->get_verbosity) - return verbosity; + if (!i->api.itf->get_logmask) + return logmask; - return i->api.itf->get_verbosity(i->api.closure); + return i->api.itf->get_logmask(i->api.closure); } /** @@ -506,36 +953,79 @@ struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name { const struct api_desc *i; - i = name ? search(set, name) : NULL; + i = name ? searchrec(set, name) : NULL; return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL; } +struct get_names { + union { + struct { + size_t count; + size_t size; + }; + struct { + const char **ptr; + char *data; + }; + }; + int type; +}; + +static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias) +{ + struct get_names *gc = closure; + if ((1 + isalias) & gc->type) { + gc->size += strlen(name); + gc->count++; + } +} + +static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias) +{ + struct get_names *gc = closure; + if ((1 + isalias) & gc->type) { + *gc->ptr++ = gc->data; + gc->data = stpcpy(gc->data, name) + 1; + } +} + +#if !defined(APISET_NO_SORT) +static int get_names_sortcb(const void *a, const void *b) +{ + return strcasecmp(*(const char **)a, *(const char **)b); +} +#endif + /** * Get the list of api names * @param set the api set + * @param rec recursive + * @param type expected type: 1 names, 3 names+aliases, 2 aliases * @return a NULL terminated array of api names. Must be freed. */ -const char **afb_apiset_get_names(struct afb_apiset *set) +const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type) { + struct get_names gc; size_t size; - char *dest; const char **names; - int i; - size = set->count * (1 + sizeof(*names)) + sizeof(*names); - for (i = 0 ; i < set->count ; i++) - size += strlen(set->apis[i].name); + gc.count = gc.size = 0; + gc.type = type >= 1 && type <= 3 ? type : 1; + afb_apiset_enum(set, rec, get_names_count, &gc); + size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names); names = malloc(size); + if (!names) errno = ENOMEM; else { - dest = (void*)&names[set->count+1]; - for (i = 0 ; i < set->count ; i++) { - names[i] = dest; - dest = stpcpy(dest, set->apis[i].name) + 1; - } - names[i] = NULL; + gc.data = (char*)&names[gc.count + 1]; + gc.ptr = names; + afb_apiset_enum(set, rec, get_names_value, &gc); +#if !defined(APISET_NO_SORT) + qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb); +#endif + *gc.ptr = NULL; } return names; } @@ -543,24 +1033,97 @@ const char **afb_apiset_get_names(struct afb_apiset *set) /** * Enumerate the api names to a callback. * @param set the api set + * @param rec should the enumeration be recursive * @param callback the function to call for each name * @param closure the closure for the callback */ -void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure) +void afb_apiset_enum( + struct afb_apiset *set, + int rec, + void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias), + void *closure) { + int i; struct afb_apiset *iset; - struct api_desc *i, *e; + struct api_desc *d; + struct api_alias *a; iset = set; while (iset) { - i = iset->apis; - e = &i[iset->count]; - while (i != e) { - if (lookup(set, i->name, 1) == i) - callback(iset, i->name, closure); - i++; + for (i = 0 ; i < set->apis.count ; i++) { + d = set->apis.apis[i];; + if (searchrec(set, d->name) == d) + callback(closure, iset, d->name, 0); + } + a = iset->aliases; + while (a) { + if (searchrec(set, a->name) == a->api) + callback(closure, iset, a->name, 1); + a = a->next; } iset = rec ? iset->subset : NULL; } } +/** + * Declare that the api of 'name' requires the api of name 'required'. + * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset. + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required) +{ + struct api_desc *a; + struct api_depend *d; + int rc = -1; + + a = searchrec(set, name); + if (!a) + errno = ENOENT; + else { + d = malloc(strlen(required) + sizeof *d); + if (!d) + errno = ENOMEM; + else { + d->set = set; + strcpy(d->name, required); + rc = api_array_add(&a->require.apis, d); + } + } + return rc; +} + +/** + * Declare that the api of name 'apiname' requires the class of name 'classname'. + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname) +{ + struct api_desc *a = searchrec(set, apiname); + struct api_class *c = class_search(classname, 1); + return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1); +} + +/** + * Declare that the api of name 'apiname' provides the class of name 'classname' + * Returns 0 if the declaration successed or -1 in case of failure + * (ENOMEM: allocation failure, ENOENT: api name not found) + */ +int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname) +{ + struct api_desc *a = searchrec(set, apiname); + struct api_class *c = class_search(classname, 1); + return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1); +} + +/** + * Start any API that provides the class of name 'classname' + * The attribute 'share_session' is sent to the start function. + */ +int afb_apiset_class_start(const char *classname, int share_session) +{ + struct api_class *cla = class_search(classname, 0); + return cla ? start_class(cla, share_session) : (errno = ENOENT, -1); +} + diff --git a/src/afb-apiset.h b/src/afb-apiset.h index 55068dd3..fc8bc266 100644 --- a/src/afb-apiset.h +++ b/src/afb-apiset.h @@ -17,28 +17,57 @@ #pragma once -struct afb_api; +struct afb_api_item; struct afb_apiset; struct json_object; +extern struct afb_apiset *afb_apiset_create(const char *name, int timeout); +extern struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout); +extern struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout); 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); + extern const char *afb_apiset_name(struct afb_apiset *set); + extern int afb_apiset_timeout_get(struct afb_apiset *set); extern void afb_apiset_timeout_set(struct afb_apiset *set, int to); + +extern void afb_apiset_onlack_set( + struct afb_apiset *set, + int (*callback)(void *closure, struct afb_apiset *set, const char *name), + void *closure, + void (*cleanup)(void*closure)); + extern void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset); extern struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set); -extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api); + +extern int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api); extern int afb_apiset_del(struct afb_apiset *set, const char *name); -extern const struct afb_api *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec); -extern const struct afb_api *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec); + +extern int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias); +extern int afb_apiset_is_alias(struct afb_apiset *set, const char *name); +extern const char *afb_apiset_unalias(struct afb_apiset *set, const char *name); + +extern const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec); +extern const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec); + 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 void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask); +extern int afb_apiset_get_logmask(struct afb_apiset *set, const char *name); + extern struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name); -extern const char **afb_apiset_get_names(struct afb_apiset *set); -extern void afb_apiset_enum(struct afb_apiset *set, int rec, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure); +extern const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type); +extern void afb_apiset_enum( + struct afb_apiset *set, + int rec, + void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias), + void *closure); + +extern int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required); +extern int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname); +extern int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname); +extern int afb_apiset_class_start(const char *classname, int share_session); diff --git a/src/afb-auth.c b/src/afb-auth.c index 47a98d5a..4a3c445f 100644 --- a/src/afb-auth.c +++ b/src/afb-auth.c @@ -22,7 +22,7 @@ #include <json-c/json.h> #include <afb/afb-auth.h> -#include <afb/afb-session-v2.h> +#include <afb/afb-session-x2.h> #include "afb-auth.h" #include "afb-context.h" @@ -60,56 +60,10 @@ int afb_auth_check(struct afb_xreq *xreq, const struct afb_auth *auth) } } -/*********************************************************************************/ -#ifdef BACKEND_PERMISSION_IS_CYNARA - -#include <pthread.h> -#include <cynara-client.h> - -static cynara *handle; -static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; - -int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission) -{ - int rc; - - if (!xreq->cred) { - /* case of permission for self */ - return 1; - } - if (!permission) { - ERROR("Got a null permission!"); - return 0; - } - - /* cynara isn't reentrant */ - pthread_mutex_lock(&mutex); - - /* lazy initialisation */ - if (!handle) { - rc = cynara_initialize(&handle, NULL); - if (rc != CYNARA_API_SUCCESS) { - handle = NULL; - ERROR("cynara initialisation failed with code %d", rc); - return 0; - } - } - - /* query cynara permission */ - rc = cynara_check(handle, xreq->cred->label, afb_context_uuid(&xreq->context), xreq->cred->user, permission); - - pthread_mutex_unlock(&mutex); - return rc == CYNARA_API_ACCESS_ALLOWED; -} - -/*********************************************************************************/ -#else int afb_auth_has_permission(struct afb_xreq *xreq, const char *permission) { - WARNING("Granting permission %s by default of backend", permission ?: "(null)"); - return !!permission; + return afb_cred_has_permission(xreq->cred, permission, afb_context_uuid(&xreq->context)); } -#endif /*********************************************************************************/ @@ -180,17 +134,17 @@ struct json_object *afb_auth_json_v2(const struct afb_auth *auth, int session) { struct json_object *result = NULL; - if (session & AFB_SESSION_CLOSE_V2) + if (session & AFB_SESSION_CLOSE_X2) result = addperm_key_valstr(result, "session", "close"); - if (session & AFB_SESSION_CHECK_V2) + if (session & AFB_SESSION_CHECK_X2) result = addperm_key_valstr(result, "session", "check"); - if (session & AFB_SESSION_REFRESH_V2) + if (session & AFB_SESSION_REFRESH_X2) result = addperm_key_valstr(result, "token", "refresh"); - if (session & AFB_SESSION_LOA_MASK_V2) - result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_V2); + if (session & AFB_SESSION_LOA_MASK_X2) + result = addperm_key_valint(result, "LOA", session & AFB_SESSION_LOA_MASK_X2); if (auth) result = addauth(result, auth); diff --git a/src/afb-autoset.c b/src/afb-autoset.c new file mode 100644 index 00000000..102830cb --- /dev/null +++ b/src/afb-autoset.c @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <stdint.h> +#include <string.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> + +#include "verbose.h" +#include "afb-api-ws.h" +#include "afb-api-so.h" +#include "afb-apiset.h" +#include "afb-autoset.h" + +static void cleanup(void *closure) +{ + struct afb_apiset *call_set = closure; + afb_apiset_unref(call_set); +} + +static int onlack(void *closure, struct afb_apiset *set, const char *name, int (*create)(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set)) +{ + struct afb_apiset *call_set = closure; + char *path; + const char *base; + size_t lbase, lname; + + base = afb_apiset_name(set); + lbase = strlen(base); + lname = strlen(name); + + path = alloca(2 + lbase + lname); + memcpy(path, base, lbase); + path[lbase] = '/'; + memcpy(&path[lbase + 1], name, lname + 1); + + return create(path, set, call_set); +} + +static int add(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set, int (*callback)(void *, struct afb_apiset *, const char*)) +{ + struct afb_apiset *ownset; + + /* create a sub-apiset */ + ownset = afb_apiset_create_subset_last(declare_set, path, 3600); + if (!ownset) { + ERROR("Can't create apiset autoset-ws %s", path); + return -1; + } + + /* set the onlack behaviour on this set */ + afb_apiset_onlack_set(ownset, callback, afb_apiset_addref(call_set), cleanup); + return 0; +} + +static int create_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return afb_api_ws_add_client(path, declare_set, call_set, 0) >= 0; +} + +static int onlack_ws(void *closure, struct afb_apiset *set, const char *name) +{ + return onlack(closure, set, name, create_ws); +} + +int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return add(path, declare_set, call_set, onlack_ws); +} + +static int create_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return afb_api_so_add_binding(path, declare_set, call_set) >= 0; +} + +static int onlack_so(void *closure, struct afb_apiset *set, const char *name) +{ + return onlack(closure, set, name, create_so); +} + +int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set) +{ + return add(path, declare_set, call_set, onlack_so); +} diff --git a/src/afb-autoset.h b/src/afb-autoset.h new file mode 100644 index 00000000..50fdec1a --- /dev/null +++ b/src/afb-autoset.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2016, 2017, 2018 "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_apiset; + +extern int afb_autoset_add_ws(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); +extern int afb_autoset_add_so(const char *path, struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-calls.c b/src/afb-calls.c new file mode 100644 index 00000000..73b89bf0 --- /dev/null +++ b/src/afb-calls.c @@ -0,0 +1,818 @@ +/* + * Copyright (C) 2016, 2017, 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#include <json-c/json.h> + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> + +#include "afb-calls.h" +#include "afb-cred.h" +#include "afb-evt.h" +#include "afb-export.h" +#include "afb-hook.h" +#include "afb-msg-json.h" +#include "afb-session.h" +#include "afb-xreq.h" + +#include "jobs.h" +#include "verbose.h" + +#define CALLFLAGS (afb_req_x2_subcall_api_session|afb_req_x2_subcall_catch_events) +#define LEGACY_SUBCALLFLAGS (afb_req_x2_subcall_pass_events|afb_req_x2_subcall_on_behalf) + + +/************************************************************************/ + +struct modes +{ + unsigned hooked: 1; + unsigned sync: 1; + unsigned legacy: 1; +}; + +#define mode_sync ((struct modes){ .hooked=0, .sync=1, .legacy=0 }) +#define mode_async ((struct modes){ .hooked=0, .sync=0, .legacy=0 }) +#define mode_legacy_sync ((struct modes){ .hooked=0, .sync=1, .legacy=1 }) +#define mode_legacy_async ((struct modes){ .hooked=0, .sync=0, .legacy=1 }) +#define mode_hooked_sync ((struct modes){ .hooked=1, .sync=1, .legacy=0 }) +#define mode_hooked_async ((struct modes){ .hooked=1, .sync=0, .legacy=0 }) +#define mode_hooked_legacy_sync ((struct modes){ .hooked=1, .sync=1, .legacy=1 }) +#define mode_hooked_legacy_async ((struct modes){ .hooked=1, .sync=0, .legacy=1 }) + +union callback { + void *any; + union { + void (*legacy_v1)(void*, int, struct json_object*); + void (*legacy_v2)(void*, int, struct json_object*, struct afb_req_x1); + void (*legacy_v3)(void*, int, struct json_object*, struct afb_req_x2*); + void (*x3)(void*, struct json_object*, const char*, const char *, struct afb_req_x2*); + } subcall; + union { + void (*legacy_v12)(void*, int, struct json_object*); + void (*legacy_v3)(void*, int, struct json_object*, struct afb_api_x3*); + void (*x3)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*); + } call; +}; + +struct callreq +{ + struct afb_xreq xreq; + + struct afb_export *export; + + struct modes mode; + + int flags; + + union { + struct { + struct jobloop *jobloop; + int returned; + int status; + struct json_object **object; + char **error; + char **info; + }; + struct { + union callback callback; + void *closure; + union { + void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*); + void (*legacy_final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*); + }; + }; + }; +}; + +/******************************************************************************/ + +static int store_reply( + struct json_object *iobject, const char *ierror, const char *iinfo, + struct json_object **sobject, char **serror, char **sinfo) +{ + if (serror) { + if (!ierror) + *serror = NULL; + else if (!(*serror = strdup(ierror))) { + ERROR("can't report error %s", ierror); + json_object_put(iobject); + iobject = NULL; + iinfo = NULL; + } + } + + if (sobject) + *sobject = iobject; + else + json_object_put(iobject); + + if (sinfo) { + if (!iinfo) + *sinfo = NULL; + else if (!(*sinfo = strdup(iinfo))) + ERROR("can't report info %s", iinfo); + } + + return -!!ierror; +} + +/******************************************************************************/ + +static void sync_leave(struct callreq *callreq) +{ + struct jobloop *jobloop = __atomic_exchange_n(&callreq->jobloop, NULL, __ATOMIC_RELAXED); + if (jobloop) + jobs_leave(jobloop); +} + +static void sync_enter(int signum, void *closure, struct jobloop *jobloop) +{ + struct callreq *callreq = closure; + if (!signum) { + callreq->jobloop = jobloop; + afb_export_process_xreq(callreq->export, &callreq->xreq); + } else { + afb_xreq_reply(&callreq->xreq, NULL, "internal-error", NULL); + } +} + +/******************************************************************************/ + +static void callreq_destroy_cb(struct afb_xreq *xreq) +{ + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + afb_context_disconnect(&callreq->xreq.context); + json_object_put(callreq->xreq.json); + afb_cred_unref(callreq->xreq.cred); + free(callreq); +} + +static void callreq_reply_cb(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) +{ + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + /* centralized hooking */ + if (callreq->mode.hooked) { + if (callreq->mode.sync) { + if (callreq->xreq.caller) + afb_hook_xreq_subcallsync_result(callreq->xreq.caller, -!!error, object, error, info); + else + afb_hook_api_callsync_result(callreq->export, -!!error, object, error, info); + } else { + if (callreq->xreq.caller) + afb_hook_xreq_subcall_result(callreq->xreq.caller, object, error, info); + else + afb_hook_api_call_result(callreq->export, object, error, info); + } + } + + /* true report of the result */ + if (callreq->mode.sync) { + callreq->returned = 1; + if (callreq->mode.legacy) { + callreq->status = -!!error; + if (callreq->object) + *callreq->object = afb_msg_json_reply(object, error, info, NULL); + else + json_object_put(object); + } else { + callreq->status = store_reply(object, error, info, + callreq->object, callreq->error, callreq->info); + } + sync_leave(callreq); + } else { + if (callreq->mode.legacy) { + object = afb_msg_json_reply(object, error, info, NULL); + callreq->legacy_final(callreq->closure, -!!error, object, callreq->callback, callreq->export, callreq->xreq.caller); + } else { + callreq->final(callreq->closure, object, error, info, callreq->callback, callreq->export, callreq->xreq.caller); + } + json_object_put(object); + } +} + +static int callreq_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) +{ + int rc = 0, rc2; + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + if (callreq->flags & afb_req_x2_subcall_pass_events) + rc = afb_xreq_subscribe(callreq->xreq.caller, event); + if (callreq->flags & afb_req_x2_subcall_catch_events) { + rc2 = afb_export_subscribe(callreq->export, event); + if (rc2 < 0) + rc = rc2; + } + return rc; +} + +static int callreq_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) +{ + int rc = 0, rc2; + struct callreq *callreq = CONTAINER_OF_XREQ(struct callreq, xreq); + + if (callreq->flags & afb_req_x2_subcall_pass_events) + rc = afb_xreq_unsubscribe(callreq->xreq.caller, event); + if (callreq->flags & afb_req_x2_subcall_catch_events) { + rc2 = afb_export_unsubscribe(callreq->export, event); + if (rc2 < 0) + rc = rc2; + } + return rc; +} + +/******************************************************************************/ + +const struct afb_xreq_query_itf afb_calls_xreq_itf = { + .unref = callreq_destroy_cb, + .reply = callreq_reply_cb, + .subscribe = callreq_subscribe_cb, + .unsubscribe = callreq_unsubscribe_cb +}; + +/******************************************************************************/ + +static struct callreq *callreq_create( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct modes mode) +{ + struct callreq *callreq; + size_t lenapi, lenverb; + char *api2, *verb2; + + lenapi = 1 + strlen(api); + lenverb = 1 + strlen(verb); + callreq = malloc(lenapi + lenverb + sizeof *callreq); + if (!callreq) { + ERROR("out of memory"); + json_object_put(args); + errno = ENOMEM; + } else { + afb_xreq_init(&callreq->xreq, &afb_calls_xreq_itf); + callreq->xreq.context.validated = 1; + api2 = (char*)&callreq[1]; + callreq->xreq.request.called_api = memcpy(api2, api, lenapi);; + verb2 = &api2[lenapi]; + callreq->xreq.request.called_verb = memcpy(verb2, verb, lenverb); + callreq->xreq.json = args; + callreq->mode = mode; + if (caller) { + export = afb_export_from_api_x3(caller->request.api); + if (flags & afb_req_x2_subcall_on_behalf) + callreq->xreq.cred = afb_cred_addref(caller->cred); + callreq->xreq.caller = caller; + afb_xreq_unhooked_addref(caller); + } + if (caller && (flags & afb_req_x2_subcall_api_session)) + afb_context_subinit(&callreq->xreq.context, &caller->context); + else + afb_export_context_init(export, &callreq->xreq.context); + callreq->export = export; + callreq->flags = flags; + } + return callreq; +} + +/******************************************************************************/ + +static int do_sync( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info, + struct modes mode) +{ + struct callreq *callreq; + int rc; + + /* allocates the request */ + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + if (!callreq) + goto interr; + + /* initializes the request */ + callreq->jobloop = NULL; + callreq->returned = 0; + callreq->status = 0; + callreq->object = object; + callreq->error = error; + callreq->info = info; + + afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ + + rc = jobs_enter(NULL, 0, sync_enter, callreq); + if (rc >= 0 && callreq->returned) { + rc = callreq->status; + afb_xreq_unhooked_unref(&callreq->xreq); + return rc; + } + + afb_xreq_unhooked_unref(&callreq->xreq); +interr: + return store_reply(NULL, "internal-error", NULL, object, info, error); +} + +/******************************************************************************/ + +static void do_async( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void *callback, + void *closure, + void (*final)(void*, struct json_object*, const char*, const char*, union callback, struct afb_export*,struct afb_xreq*), + struct modes mode) +{ + struct callreq *callreq; + + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + + if (!callreq) + final(closure, NULL, "internal-error", NULL, (union callback){ .any = callback }, export, caller); + else { + callreq->callback.any = callback; + callreq->closure = closure; + callreq->final = final; + + afb_export_process_xreq(callreq->export, &callreq->xreq); + } +} + +/******************************************************************************/ + +static void final_call( + void *closure, + struct json_object *object, + const char *error, + const char *info, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.x3) + callback.call.x3(closure, object, error, info, afb_export_to_api_x3(export)); +} + +static void final_subcall( + void *closure, + struct json_object *object, + const char *error, + const char *info, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.x3) + callback.subcall.x3(closure, object, error, info, xreq_to_req_x2(caller)); +} + +/******************************************************************************/ + +void afb_calls_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) +{ + do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_async); +} + +void afb_calls_hooked_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_call, mode_hooked_async); +} + +int afb_calls_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) +{ + return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_sync); +} + +int afb_calls_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) +{ + afb_hook_api_callsync(export, api, verb, args); + return do_sync(export, NULL, api, verb, args, CALLFLAGS, object, error, info, mode_hooked_sync); +} + +void afb_calls_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_async); +} + +void afb_calls_hooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + afb_hook_xreq_subcall(xreq, api, verb, args, flags); + do_async(NULL, xreq, api, verb, args, flags, callback, closure, final_subcall, mode_hooked_async); +} + +int afb_calls_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_sync); +} + +int afb_calls_hooked_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + afb_hook_xreq_subcallsync(xreq, api, verb, args, flags); + return do_sync(NULL, xreq, api, verb, args, flags, object, error, info, mode_hooked_sync); +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +static int do_legacy_sync( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + struct modes mode) +{ + struct callreq *callreq; + int rc; + + /* allocates the request */ + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + if (!callreq) + goto interr; + + /* initializes the request */ + callreq->jobloop = NULL; + callreq->returned = 0; + callreq->status = 0; + callreq->object = object; + + afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ + + rc = jobs_enter(NULL, 0, sync_enter, callreq); + if (rc >= 0 && callreq->returned) { + rc = callreq->status; + afb_xreq_unhooked_unref(&callreq->xreq); + return rc; + } + + afb_xreq_unhooked_unref(&callreq->xreq); +interr: + if (object) + *object = afb_msg_json_internal_error(); + return -1; +} + +/******************************************************************************/ + +static void do_legacy_async( + struct afb_export *export, + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void *callback, + void *closure, + void (*final)(void*, int, struct json_object*, union callback, struct afb_export*,struct afb_xreq*), + struct modes mode) +{ + struct callreq *callreq; + struct json_object *ie; + + callreq = callreq_create(export, caller, api, verb, args, flags, mode); + + if (!callreq) { + ie = afb_msg_json_internal_error(); + final(closure, -1, ie, (union callback){ .any = callback }, export, caller); + json_object_put(ie); + } else { + callreq->callback.any = callback; + callreq->closure = closure; + callreq->legacy_final = final; + + afb_export_process_xreq(callreq->export, &callreq->xreq); + } +} + +/******************************************************************************/ + +static void final_legacy_call_v12( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.legacy_v12) + callback.call.legacy_v12(closure, status, object); +} + +static void final_legacy_call_v3( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.call.legacy_v3) + callback.call.legacy_v3(closure, status, object, afb_export_to_api_x3(export)); +} + +/******************************************************************************/ + +void afb_calls_legacy_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_legacy_async); +} + +void afb_calls_legacy_hooked_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v12, mode_hooked_legacy_async); +} + +void afb_calls_legacy_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure) +{ + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_legacy_async); +} + +void afb_calls_legacy_hooked_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure) +{ + afb_hook_api_call(export, api, verb, args); + do_legacy_async(export, NULL, api, verb, args, CALLFLAGS, callback, closure, final_legacy_call_v3, mode_hooked_legacy_async); +} + +int afb_calls_legacy_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, result, mode_legacy_sync); +} + +int afb_calls_legacy_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + int rc; + struct json_object *object; + + afb_hook_api_callsync(export, api, verb, args); + rc = do_legacy_sync(export, NULL, api, verb, args, CALLFLAGS, &object, mode_hooked_legacy_sync); + if (result) + *result = object; + else + json_object_put(object); + return rc; +} + +/******************************************************************************/ + +static void final_legacy_subcall_v1( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v1) + callback.subcall.legacy_v1(closure, status, object); +} + +static void final_legacy_subcall_v2( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v2) + callback.subcall.legacy_v2(closure, status, object, xreq_to_req_x1(caller)); +} + +static void final_legacy_subcall_v3( + void *closure, + int status, + struct json_object *object, + union callback callback, + struct afb_export *export, + struct afb_xreq *caller) +{ + if (callback.subcall.legacy_v3) + callback.subcall.legacy_v3(closure, status, object, xreq_to_req_x2(caller)); +} + +/******************************************************************************/ + +void afb_calls_legacy_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v1, mode_hooked_legacy_async); +} + +void afb_calls_legacy_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v2, mode_hooked_legacy_async); +} + +void afb_calls_legacy_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure) +{ + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_legacy_async); +} + +void afb_calls_legacy_hooked_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure) +{ + afb_hook_xreq_subcall(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + do_legacy_async(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, callback, closure, final_legacy_subcall_v3, mode_hooked_legacy_async); +} + +int afb_calls_legacy_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_legacy_sync); +} + +int afb_calls_legacy_hooked_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result) +{ + afb_hook_xreq_subcallsync(caller, api, verb, args, LEGACY_SUBCALLFLAGS); + return do_legacy_sync(NULL, caller, api, verb, args, LEGACY_SUBCALLFLAGS, result, mode_hooked_legacy_sync); +} diff --git a/src/afb-calls.h b/src/afb-calls.h new file mode 100644 index 00000000..15b71bf2 --- /dev/null +++ b/src/afb-calls.h @@ -0,0 +1,235 @@ +/* + * Copyright (C) 2016, 2017, 2018 "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 json_object; + +struct afb_export; +struct afb_xreq; + +struct afb_api_x3; +struct afb_req_x1; +struct afb_req_x2; + +/******************************************************************************/ + +extern +void afb_calls_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure); + +extern +void afb_calls_hooked_call( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure); + +extern +int afb_calls_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); + +extern +int afb_calls_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info); + +extern +void afb_calls_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure); + +extern +void afb_calls_hooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure); + +extern +int afb_calls_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); + +extern +int afb_calls_hooked_subcall_sync( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info); + +/******************************************************************************/ + +extern +void afb_calls_legacy_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_hooked_call_v12( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure); + +extern +void afb_calls_legacy_hooked_call_v3( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_api_x3 *), + void *closure); + +extern +int afb_calls_legacy_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +extern +int afb_calls_legacy_hooked_call_sync( + struct afb_export *export, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +/******************************************************************************/ + +extern +void afb_calls_legacy_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v1( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*), + void *closure); + +extern +void afb_calls_legacy_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v2( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x1), + void *closure); + +extern +void afb_calls_legacy_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure); + +extern +void afb_calls_legacy_hooked_subcall_v3( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), + void *closure); + +extern +int afb_calls_legacy_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); + +extern +int afb_calls_legacy_hooked_subcall_sync( + struct afb_xreq *caller, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **result); diff --git a/src/afb-config.c b/src/afb-config.c index 2a6f931f..f3f48fd6 100644 --- a/src/afb-config.c +++ b/src/afb-config.c @@ -23,6 +23,7 @@ #include <getopt.h> #include <limits.h> #include <unistd.h> +#include <ctype.h> #include <json-c/json.h> @@ -30,8 +31,6 @@ #include "afb-config.h" #include "afb-hook.h" -#include <afb/afb-binding-v1.h> - #if !defined(BINDING_INSTALL_DIR) #error "you should define BINDING_INSTALL_DIR" #endif @@ -51,17 +50,25 @@ # define HAS_DBUS 0 #endif -// default -#define DEFLT_CNTX_TIMEOUT 32000000 // default Client Connection - // Timeout: few more than one year -#define DEFLT_API_TIMEOUT 20 // default Plugin API Timeout [0=NoLimit - // for Debug Only] -#define DEFLT_CACHE_TIMEOUT 100000 // default Static File Chache - // [Client Side Cache - // 100000~=1day] -#define CTX_NBCLIENTS 10 // allow a default of 10 authenticated - // clients +/** + * The default timeout of sessions in seconds + */ +#define DEFAULT_SESSION_TIMEOUT 32000000 + +/** + * The default timeout of api calls in seconds + */ +#define DEFAULT_API_TIMEOUT 20 + +/** + * The default timeout of cache in seconds + */ +#define DEFAULT_CACHE_TIMEOUT 100000 +/** + * The default maximum count of sessions + */ +#define DEFAULT_MAX_SESSION_COUNT 200 // Define command line option #define SET_BACKGROUND 2 @@ -81,14 +88,15 @@ #define SET_WEAK_LDPATH 16 #define NO_LDPATH 17 +#if defined(KEEP_LEGACY_MODE) #define SET_MODE 18 +#endif #if HAS_DBUS # define DBUS_CLIENT 20 # define DBUS_SERVICE 21 #endif -#define SO_BINDING 22 #define SET_SESSIONMAX 23 @@ -99,11 +107,18 @@ #define SET_NO_HTTPD 28 +#define AUTO_WS 'a' +#define AUTO_LINK 'A' +#define SO_BINDING 'b' #define ADD_CALL 'c' +#if !defined(REMOVE_LEGACY_TRACE) #define SET_TRACEDITF 'D' +#endif #define SET_TRACEEVT 'E' #define SET_EXEC 'e' #define DISPLAY_HELP 'h' +#define SET_LOG 'l' +#define SET_TRACEAPI 'I' #if HAS_MONITORING # define SET_MONITORING 'M' #endif @@ -111,7 +126,9 @@ #define SET_TCP_PORT 'p' #define SET_QUIET 'q' #define SET_RNDTOKEN 'r' +#if !defined(REMOVE_LEGACY_TRACE) #define SET_TRACESVC 'S' +#endif #define SET_TRACESES 's' #define SET_TRACEREQ 'T' #define SET_AUTH_TOKEN 't' @@ -121,7 +138,15 @@ #define SET_WORK_DIR 'w' const char shortopts[] = - "c:D:E:ehn:p:qrS:s:T:t:u:Vvw:" + "a:A:b:c:" +#if !defined(REMOVE_LEGACY_TRACE) + "D:" +#endif + "E:ehl:n:p:qr" +#if !defined(REMOVE_LEGACY_TRACE) + "S:" +#endif + "s:T:t:u:Vvw:" #if HAS_MONITORING "M" #endif @@ -140,6 +165,7 @@ static AFB_options cliOptions[] = { /* *INDENT-OFF* */ {SET_VERBOSE, 0, "verbose", "Verbose Mode, repeat to increase verbosity"}, {SET_QUIET, 0, "quiet", "Quiet Mode, repeat to decrease verbosity"}, + {SET_LOG, 1, "log", "tune log level"}, {SET_FORGROUND, 0, "foreground", "Get all in foreground mode"}, {SET_BACKGROUND, 0, "daemon", "Get all in background mode"}, @@ -172,7 +198,9 @@ static AFB_options cliOptions[] = { {DISPLAY_VERSION, 0, "version", "Display version and copyright"}, {DISPLAY_HELP, 0, "help", "Display this help"}, +#if defined(KEEP_LEGACY_MODE) {SET_MODE, 1, "mode", "Set the mode: either local, remote or global"}, +#endif #if HAS_DBUS {DBUS_CLIENT, 1, "dbus-client", "Bind to an afb service through dbus"}, @@ -181,13 +209,19 @@ static AFB_options cliOptions[] = { {WS_CLIENT, 1, "ws-client", "Bind to an afb service through websocket"}, {WS_SERVICE, 1, "ws-server", "Provides an afb service through websockets"}, + {AUTO_WS, 1, "auto-ws", "Automatic bind on need to remote service through websocket"}, + {AUTO_LINK, 1, "auto-link", "Automatic load on need to binding shared objects"}, + {SET_SESSIONMAX, 1, "session-max", "Max count of session simultaneously [default 10]"}, {SET_TRACEREQ, 1, "tracereq", "Log the requests: no, common, extra, all"}, - {SET_TRACEDITF, 1, "traceditf", "Log the requests: no, common, extra, all"}, - {SET_TRACESVC, 1, "tracesvc", "Log the requests: no, all"}, - {SET_TRACEEVT, 1, "traceevt", "Log the requests: no, common, extra, all"}, +#if !defined(REMOVE_LEGACY_TRACE) + {SET_TRACEDITF, 1, "traceditf", "Log the daemons: no, common, all"}, + {SET_TRACESVC, 1, "tracesvc", "Log the services: no, all"}, +#endif + {SET_TRACEEVT, 1, "traceevt", "Log the events: no, common, extra, all"}, {SET_TRACESES, 1, "traceses", "Log the sessions: no, all"}, + {SET_TRACEAPI, 1, "traceapi", "Log the apis: no, common, api, event, all"}, {ADD_CALL, 1, "call", "call at start format of val: API/VERB:json-args"}, @@ -216,19 +250,20 @@ static struct enumdesc tracereq_desc[] = { { NULL, 0 } }; +#if !defined(REMOVE_LEGACY_TRACE) static struct enumdesc traceditf_desc[] = { { "no", 0 }, - { "common", afb_hook_flags_ditf_common }, - { "extra", afb_hook_flags_ditf_extra }, - { "all", afb_hook_flags_ditf_all }, + { "common", afb_hook_flags_api_ditf_common }, + { "all", afb_hook_flags_api_ditf_all }, { NULL, 0 } }; static struct enumdesc tracesvc_desc[] = { { "no", 0 }, - { "all", afb_hook_flags_svc_all }, + { "all", afb_hook_flags_api_svc_all }, { NULL, 0 } }; +#endif static struct enumdesc traceevt_desc[] = { { "no", 0 }, @@ -245,12 +280,25 @@ static struct enumdesc traceses_desc[] = { { NULL, 0 } }; +static struct enumdesc traceapi_desc[] = { + { "no", 0 }, + { "common", afb_hook_flags_api_common }, + { "api", afb_hook_flags_api_api|afb_hook_flag_api_start }, + { "event", afb_hook_flags_api_event|afb_hook_flag_api_start }, + { "all", afb_hook_flags_api_all }, + { NULL, 0 } +}; + +#if defined(KEEP_LEGACY_MODE) +#include <afb/afb-binding-v1.h> + static struct enumdesc mode_desc[] = { { "local", AFB_MODE_LOCAL }, { "remote", AFB_MODE_REMOTE }, { "global", AFB_MODE_GLOBAL }, { NULL, 0 } }; +#endif /*---------------------------------------------------------- | printversion @@ -453,6 +501,53 @@ static char **make_exec(char **argv) } /*--------------------------------------------------------- + | set the log levels + +--------------------------------------------------------- */ + +static void set_log(char *args) +{ + char o = 0, s, *p, *i = args; + int lvl; + + for(;;) switch (*i) { + case 0: + return; + case '+': + case '-': + o = *i; + /*@fallthrough@*/ + case ' ': + case ',': + i++; + break; + default: + p = i; + while (isalpha(*p)) p++; + s = *p; + *p = 0; + lvl = verbose_level_of_name(i); + if (lvl < 0) { + i = strdupa(p); + *p = s; + ERROR("Bad log name '%s' in %s", i, args); + exit(1); + } + *p = s; + i = p; + if (o == '-') + verbose_sub(lvl); + else { + if (!o) { + verbose_clear(); + o = '+'; + } + verbose_add(lvl); + } + break; + } +} + +/*--------------------------------------------------------- | Parse option and launch action +--------------------------------------------------------- */ @@ -479,23 +574,27 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) { switch (optc) { case SET_VERBOSE: - verbosity++; + verbose_inc(); break; case SET_QUIET: - verbosity--; + verbose_dec(); + break; + + case SET_LOG: + set_log(argvalstr(optc)); break; case SET_TCP_PORT: - config->httpdPort = argvalintdec(optc, 1024, 32767); + config->http_port = argvalintdec(optc, 1024, 32767); break; case SET_APITIMEOUT: - config->apiTimeout = argvalintdec(optc, 0, INT_MAX); + config->api_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_CNTXTIMEOUT: - config->cntxTimeout = argvalintdec(optc, 0, INT_MAX); + config->session_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_ROOT_DIR: @@ -557,11 +656,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) break; case SET_CACHE_TIMEOUT: - config->cacheTimeout = argvalintdec(optc, 0, INT_MAX); + config->cache_timeout = argvalintdec(optc, 0, INT_MAX); break; case SET_SESSIONMAX: - config->nbSessionMax = argvalintdec(optc, 1, INT_MAX); + config->max_session_count = argvalintdec(optc, 1, INT_MAX); break; case SET_FORGROUND: @@ -578,9 +677,11 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) config->name = argvalstr(optc); break; +#if defined(KEEP_LEGACY_MODE) case SET_MODE: config->mode = argvalenum(optc, mode_desc); break; +#endif #if HAS_DBUS case DBUS_CLIENT: @@ -604,10 +705,19 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) list_add(&config->so_bindings, argvalstr(optc)); break; + case AUTO_WS: + list_add(&config->auto_ws, argvalstr(optc)); + break; + + case AUTO_LINK: + list_add(&config->auto_link, argvalstr(optc)); + break; + case SET_TRACEREQ: config->tracereq = argvalenum(optc, tracereq_desc); break; +#if !defined(REMOVE_LEGACY_TRACE) case SET_TRACEDITF: config->traceditf = argvalenum(optc, traceditf_desc); break; @@ -615,6 +725,7 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) case SET_TRACESVC: config->tracesvc = argvalenum(optc, tracesvc_desc); break; +#endif case SET_TRACEEVT: config->traceevt = argvalenum(optc, traceevt_desc); @@ -624,9 +735,13 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) config->traceses = argvalenum(optc, traceses_desc); break; + case SET_TRACEAPI: + config->traceapi = argvalenum(optc, traceapi_desc); + break; + case SET_NO_HTTPD: noarg(optc); - config->noHttpd = 1; + config->no_httpd = 1; break; case SET_EXEC: @@ -663,28 +778,28 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config) static void fulfill_config(struct afb_config *config) { // default HTTP port - if (config->httpdPort == 0) - config->httpdPort = 1234; + if (config->http_port == 0) + config->http_port = 1234; // default binding API timeout - if (config->apiTimeout == 0) - config->apiTimeout = DEFLT_API_TIMEOUT; + if (config->api_timeout == 0) + config->api_timeout = DEFAULT_API_TIMEOUT; // default AUTH_TOKEN if (config->random_token) config->token = NULL; // cache timeout default one hour - if (config->cacheTimeout == 0) - config->cacheTimeout = DEFLT_CACHE_TIMEOUT; + if (config->cache_timeout == 0) + config->cache_timeout = DEFAULT_CACHE_TIMEOUT; // cache timeout default one hour - if (config->cntxTimeout == 0) - config->cntxTimeout = DEFLT_CNTX_TIMEOUT; + if (config->session_timeout == 0) + config->session_timeout = DEFAULT_SESSION_TIMEOUT; // max count of sessions - if (config->nbSessionMax == 0) - config->nbSessionMax = CTX_NBCLIENTS; + if (config->max_session_count == 0) + config->max_session_count = DEFAULT_MAX_SESSION_COUNT; /* set directories */ if (config->workdir == NULL) @@ -717,6 +832,10 @@ static void fulfill_config(struct afb_config *config) strncpy(config->console, config->uploaddir, 512); strncat(config->console, "/AFB-console.out", 512); } + +#if !defined(REMOVE_LEGACY_TRACE) + config->traceapi |= config->traceditf | config->tracesvc; +#endif } void afb_config_dump(struct afb_config *config) @@ -761,21 +880,26 @@ void afb_config_dump(struct afb_config *config) V(exec) - D(httpdPort) - D(cacheTimeout) - D(apiTimeout) - D(cntxTimeout) - D(nbSessionMax) + D(http_port) + D(cache_timeout) + D(api_timeout) + D(session_timeout) + D(max_session_count) +#if defined(KEEP_LEGACY_MODE) E(mode,mode_desc) +#endif E(tracereq,tracereq_desc) +#if !defined(REMOVE_LEGACY_TRACE) E(traceditf,traceditf_desc) E(tracesvc,tracesvc_desc) +#endif E(traceevt,traceevt_desc) E(traceses,traceses_desc) + E(traceapi,traceapi_desc) B(no_ldpaths) - B(noHttpd) + B(no_httpd) B(background) #if HAS_MONITORING B(monitoring) @@ -823,10 +947,13 @@ static void on_environment_enum(int *to, const char *name, struct enumdesc *desc static void parse_environment(struct afb_config *config) { on_environment_enum(&config->tracereq, "AFB_TRACEREQ", tracereq_desc); +#if !defined(REMOVE_LEGACY_TRACE) on_environment_enum(&config->traceditf, "AFB_TRACEDITF", traceditf_desc); on_environment_enum(&config->tracesvc, "AFB_TRACESVC", tracesvc_desc); +#endif on_environment_enum(&config->traceevt, "AFB_TRACEEVT", traceevt_desc); on_environment_enum(&config->traceses, "AFB_TRACESES", traceses_desc); + on_environment_enum(&config->traceapi, "AFB_TRACEAPI", traceapi_desc); on_environment_list(&config->ldpaths, "AFB_LDPATHS"); } @@ -839,7 +966,7 @@ struct afb_config *afb_config_parse_arguments(int argc, char **argv) parse_environment(result); parse_arguments(argc, argv, result); fulfill_config(result); - if (verbosity >= 3) + if (verbose_wants(Log_Level_Info)) afb_config_dump(result); return result; } @@ -895,21 +1022,26 @@ struct json_object *afb_config_json(struct afb_config *config) V(exec) - D(httpdPort) - D(cacheTimeout) - D(apiTimeout) - D(cntxTimeout) - D(nbSessionMax) + D(http_port) + D(cache_timeout) + D(api_timeout) + D(session_timeout) + D(max_session_count) +#if defined(KEEP_LEGACY_MODE) E(mode,mode_desc) +#endif E(tracereq,tracereq_desc) +#if !defined(REMOVE_LEGACY_TRACE) E(traceditf,traceditf_desc) E(tracesvc,tracesvc_desc) +#endif E(traceevt,traceevt_desc) E(traceses,traceses_desc) + E(traceapi,traceapi_desc) B(no_ldpaths) - B(noHttpd) + B(no_httpd) B(background) #if HAS_MONITORING B(monitoring) diff --git a/src/afb-config.h b/src/afb-config.h index 89b1f78e..30fd398c 100644 --- a/src/afb-config.h +++ b/src/afb-config.h @@ -22,22 +22,27 @@ struct json_object; * other definitions --------------------------------------------------- */ +/** + * list of configuration values + */ struct afb_config_list { struct afb_config_list *next; char *value; }; -// main config structure +/** + * main config structure + */ struct afb_config { - char *console; // console device name (can be a file or a tty) - char *rootdir; // base dir for files - char *roothttp; // directory for http files - char *rootbase; // Angular HTML5 base URL - char *rootapi; // Base URL for REST APIs - char *workdir; // where to run the program - char *uploaddir; // where to store transient files - char *token; // initial authentication token [default NULL no session] - char *name; /* name to set to the daemon */ + char *console; /*< console device name (can be a file or a tty) */ + char *rootdir; /*< base dir for files */ + char *roothttp; /*< directory for http files */ + char *rootbase; /*< Angular HTML5 base URL */ + char *rootapi; /*< Base URL for REST APIs */ + char *workdir; /*< where to run the program */ + char *uploaddir; /*< where to store transient files */ + char *token; /*< initial authentication token [default NULL no session] */ + char *name; /*< name to set to the daemon */ struct afb_config_list *aliases; #if defined(WITH_DBUS_TRANSPARENCY) @@ -50,32 +55,39 @@ struct afb_config { struct afb_config_list *ldpaths; struct afb_config_list *weak_ldpaths; struct afb_config_list *calls; + struct afb_config_list *auto_ws; + struct afb_config_list *auto_link; char **exec; /* integers */ - int httpdPort; - int cacheTimeout; - int apiTimeout; - int cntxTimeout; // Client Session Context timeout - int nbSessionMax; // max count of sessions + int http_port; + int cache_timeout; + int api_timeout; + int session_timeout; /*< session timeout */ + int max_session_count; /*< max count of sessions */ /* enums */ +#if defined(KEEP_LEGACY_MODE) int mode; // mode of listening +#endif int tracereq; +#if !defined(REMOVE_LEGACY_TRACE) int traceditf; int tracesvc; +#endif int traceevt; int traceses; + int traceapi; /* booleans */ - unsigned no_ldpaths: 1; /* disable default ldpaths */ - unsigned noHttpd: 1; - unsigned background: 1; /* run in backround mode */ + unsigned no_ldpaths: 1; /**< disable default ldpaths */ + unsigned no_httpd: 1; + unsigned background: 1; /**< run in backround mode */ + unsigned random_token: 1; /**< expects a random token */ #if defined(WITH_MONITORING_OPTION) - unsigned monitoring: 1; /* activates monitoring */ + unsigned monitoring: 1; /**< activates monitoring */ #endif - unsigned random_token: 1; /* expects a random token */ }; extern struct afb_config *afb_config_parse_arguments(int argc, char **argv); diff --git a/src/afb-context.c b/src/afb-context.c index 13733ce6..6b3d6e9d 100644 --- a/src/afb-context.c +++ b/src/afb-context.c @@ -21,6 +21,7 @@ #include <assert.h> #include <stdlib.h> #include <stdint.h> +#include <errno.h> #include "afb-session.h" #include "afb-context.h" @@ -184,10 +185,12 @@ static inline unsigned ptr2loa(void *ptr) int afb_context_change_loa(struct afb_context *context, unsigned loa) { - if (!context->validated || loa > 7) - return 0; + if (!context->validated || loa > 7) { + errno = EINVAL; + return -1; + } - return 0 <= afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL); + return afb_session_set_cookie(context->session, loa_key(context), loa2ptr(loa), NULL); } unsigned afb_context_get_loa(struct afb_context *context) @@ -195,5 +198,3 @@ unsigned afb_context_get_loa(struct afb_context *context) assert(context->session != NULL); return ptr2loa(afb_session_get_cookie(context->session, loa_key(context))); } - - diff --git a/src/afb-cred.c b/src/afb-cred.c index f09d4441..b7b3175e 100644 --- a/src/afb-cred.c +++ b/src/afb-cred.c @@ -18,6 +18,7 @@ #define _GNU_SOURCE #include <stdlib.h> +#include <stdio.h> #include <unistd.h> #include <string.h> #include <errno.h> @@ -26,6 +27,8 @@ #include <sys/socket.h> #include "afb-cred.h" +#include "verbose.h" + #define MAX_LABEL_LENGTH 1024 @@ -46,6 +49,10 @@ # define DEFAULT_PEERCRED_PID 0 /* no process */ #endif +static char on_behalf_credential_permission[] = "urn:AGL:permission:*:partner:on-behalf-credentials"; +static char export_format[] = "%x:%x:%x-%s"; +static char import_format[] = "%x:%x:%x-%n"; + static struct afb_cred *current; static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *label, size_t size) @@ -70,6 +77,7 @@ static struct afb_cred *mkcred(uid_t uid, gid_t gid, pid_t pid, const char *labe cred->uid = uid; cred->gid = gid; cred->pid = pid; + cred->exported = NULL; dest = (char*)(&cred[1]); cred->user = dest; while(i) @@ -175,3 +183,105 @@ struct afb_cred *afb_cred_current() return afb_cred_addref(current); } +const char *afb_cred_export(struct afb_cred *cred) +{ + int rc; + + if (!cred->exported) { + rc = asprintf((char**)&cred->exported, + export_format, + (int)cred->uid, + (int)cred->gid, + (int)cred->pid, + cred->label); + if (rc < 0) { + errno = ENOMEM; + cred->exported = NULL; + } + } + return cred->exported; +} + +struct afb_cred *afb_cred_import(const char *string) +{ + struct afb_cred *cred; + int rc, uid, gid, pid, pos; + + rc = sscanf(string, import_format, &uid, &gid, &pid, &pos); + if (rc == 3) + cred = afb_cred_create((uid_t)uid, (gid_t)gid, (pid_t)pid, &string[pos]); + else { + errno = EINVAL; + cred = NULL; + } + return cred; +} + +struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported) + +{ + struct afb_cred *imported; + if (exported) { + if (afb_cred_has_permission(cred, on_behalf_credential_permission, context)) { + imported = afb_cred_import(exported); + if (imported) + return imported; + ERROR("Can't import on behalf credentials: %m"); + } else { + ERROR("On behalf credentials refused"); + } + } + return afb_cred_addref(cred); +} + +/*********************************************************************************/ +#ifdef BACKEND_PERMISSION_IS_CYNARA + +#include <pthread.h> +#include <cynara-client.h> + +static cynara *handle; +static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; + +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context) +{ + int rc; + + if (!cred) { + /* case of permission for self */ + return 1; + } + if (!permission) { + ERROR("Got a null permission!"); + return 0; + } + + /* cynara isn't reentrant */ + pthread_mutex_lock(&mutex); + + /* lazy initialisation */ + if (!handle) { + rc = cynara_initialize(&handle, NULL); + if (rc != CYNARA_API_SUCCESS) { + handle = NULL; + ERROR("cynara initialisation failed with code %d", rc); + return 0; + } + } + + /* query cynara permission */ + rc = cynara_check(handle, cred->label, context ?: "", cred->user, permission); + + pthread_mutex_unlock(&mutex); + return rc == CYNARA_API_ACCESS_ALLOWED; +} + +/*********************************************************************************/ +#else +int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context) +{ + WARNING("Granting permission %s by default of backend", permission ?: "(null)"); + return !!permission; +} +#endif + diff --git a/src/afb-cred.h b/src/afb-cred.h index 7ee4723c..614fa4bc 100644 --- a/src/afb-cred.h +++ b/src/afb-cred.h @@ -28,6 +28,7 @@ struct afb_cred const char *user; const char *label; const char *id; + const char *exported; }; extern struct afb_cred *afb_cred_current(); @@ -36,4 +37,10 @@ extern struct afb_cred *afb_cred_create_for_socket(int fd); extern struct afb_cred *afb_cred_addref(struct afb_cred *cred); extern void afb_cred_unref(struct afb_cred *cred); +extern int afb_cred_has_permission(struct afb_cred *cred, const char *permission, const char *context); + +extern const char *afb_cred_export(struct afb_cred *cred); +extern struct afb_cred *afb_cred_import(const char *string); + +extern struct afb_cred *afb_cred_mixed_on_behalf_import(struct afb_cred *cred, const char *context, const char *exported); diff --git a/src/afb-evt.c b/src/afb-evt.c index 6b94ce8c..ed3e4672 100644 --- a/src/afb-evt.c +++ b/src/afb-evt.c @@ -24,8 +24,8 @@ #include <pthread.h> #include <json-c/json.h> -#include <afb/afb-eventid-itf.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2-itf.h> +#include <afb/afb-event-x1.h> #include "afb-evt.h" #include "afb-hook.h" @@ -50,8 +50,8 @@ struct afb_evt_listener { /* head of the list of events listened */ struct afb_evt_watch *watchs; - /* mutex of the listener */ - pthread_mutex_t mutex; + /* rwlock of the listener */ + pthread_rwlock_t rwlock; /* count of reference to the listener */ int refcount; @@ -63,7 +63,7 @@ struct afb_evt_listener { struct afb_evtid { /* interface */ - struct afb_eventid eventid; + struct afb_event_x2 eventid; /* next event */ struct afb_evtid *next; @@ -71,8 +71,8 @@ struct afb_evtid { /* head of the list of listeners watching the event */ struct afb_evt_watch *watchs; - /* mutex of the event */ - pthread_mutex_t mutex; + /* rwlock of the event */ + pthread_rwlock_t rwlock; /* hooking */ int hookflags; @@ -109,7 +109,7 @@ struct afb_evt_watch { }; /* the interface for events */ -static struct afb_eventid_itf afb_evt_eventid_itf = { +static struct afb_event_x2_itf afb_evt_event_x2_itf = { .broadcast = (void*)afb_evt_evtid_broadcast, .push = (void*)afb_evt_evtid_push, .unref = (void*)afb_evt_evtid_unref, @@ -118,7 +118,7 @@ static struct afb_eventid_itf afb_evt_eventid_itf = { }; /* the interface for events */ -static struct afb_eventid_itf afb_evt_hooked_eventid_itf = { +static struct afb_event_x2_itf afb_evt_hooked_eventid_itf = { .broadcast = (void*)afb_evt_evtid_hooked_broadcast, .push = (void*)afb_evt_evtid_hooked_push, .unref = (void*)afb_evt_evtid_hooked_unref, @@ -127,11 +127,11 @@ static struct afb_eventid_itf afb_evt_hooked_eventid_itf = { }; /* head of the list of listeners */ -static pthread_mutex_t listeners_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t listeners_rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_evt_listener *listeners = NULL; /* handling id of events */ -static pthread_mutex_t events_mutex = PTHREAD_MUTEX_INITIALIZER; +static pthread_rwlock_t events_rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_evtid *evtids = NULL; static int event_id_counter = 0; static int event_id_wrapped = 0; @@ -147,7 +147,8 @@ static int broadcast(const char *event, struct json_object *obj, int id) struct afb_evt_listener *listener; result = 0; - pthread_mutex_lock(&listeners_mutex); + + pthread_rwlock_rdlock(&listeners_rwlock); listener = listeners; while(listener) { if (listener->itf->broadcast != NULL) { @@ -156,7 +157,7 @@ static int broadcast(const char *event, struct json_object *obj, int id) } listener = listener->next; } - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); json_object_put(obj); return result; } @@ -228,7 +229,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) struct afb_evt_listener *listener; result = 0; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_rdlock(&evtid->rwlock); watch = evtid->watchs; while(watch) { listener = watch->listener; @@ -239,7 +240,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) } watch = watch->next_by_evtid; } - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); json_object_put(obj); return result; } @@ -252,6 +253,7 @@ int afb_evt_evtid_push(struct afb_evtid *evtid, struct json_object *obj) */ int afb_evt_evtid_hooked_push(struct afb_evtid *evtid, struct json_object *obj) { + int result; /* lease the object */ @@ -319,7 +321,7 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname) goto error; /* allocates the id */ - pthread_mutex_lock(&events_mutex); + pthread_rwlock_wrlock(&events_rwlock); do { if (++event_id_counter < 0) { event_id_wrapped = 1; @@ -335,15 +337,16 @@ struct afb_evtid *afb_evt_evtid_create(const char *fullname) /* initialize the event */ memcpy(evtid->fullname, fullname, len + 1); evtid->next = evtids; + evtid->refcount = 1; evtid->watchs = NULL; evtid->id = event_id_counter; - pthread_mutex_init(&evtid->mutex, NULL); + pthread_rwlock_init(&evtid->rwlock, NULL); evtids = evtid; evtid->hookflags = afb_hook_flags_evt(evtid->fullname); - evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf; + evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf; if (evtid->hookflags & afb_hook_flag_evt_create) afb_hook_evt_create(evtid->fullname, evtid->id); - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); /* returns the event */ return evtid; @@ -402,14 +405,14 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid) if (!__atomic_sub_fetch(&evtid->refcount, 1, __ATOMIC_RELAXED)) { /* unlinks the event if valid! */ - pthread_mutex_lock(&events_mutex); + pthread_rwlock_wrlock(&events_rwlock); found = 0; prv = &evtids; while (*prv && !(found = (*prv == evtid))) prv = &(*prv)->next; if (found) *prv = evtid->next; - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); /* destroys the event */ if (!found) @@ -418,15 +421,15 @@ void afb_evt_evtid_unref(struct afb_evtid *evtid) /* removes all watchers */ while(evtid->watchs != NULL) { listener = evtid->watchs->listener; - pthread_mutex_lock(&listener->mutex); - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&listener->rwlock); + pthread_rwlock_wrlock(&evtid->rwlock); remove_watch(evtid->watchs); - pthread_mutex_unlock(&evtid->mutex); - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&evtid->rwlock); + pthread_rwlock_unlock(&listener->rwlock); } /* free */ - pthread_mutex_destroy(&evtid->mutex); + pthread_rwlock_destroy(&evtid->rwlock); free(evtid); } } @@ -489,7 +492,7 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, struct afb_evt_listener *listener; /* search if an instance already exists */ - pthread_mutex_lock(&listeners_mutex); + pthread_rwlock_wrlock(&listeners_rwlock); listener = listeners; while (listener != NULL) { if (listener->itf == itf && listener->closure == closure) { @@ -507,12 +510,12 @@ struct afb_evt_listener *afb_evt_listener_create(const struct afb_evt_itf *itf, listener->closure = closure; listener->watchs = NULL; listener->refcount = 1; - pthread_mutex_init(&listener->mutex, NULL); + pthread_rwlock_init(&listener->rwlock, NULL); listener->next = listeners; listeners = listener; } found: - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); return listener; } @@ -537,25 +540,25 @@ void afb_evt_listener_unref(struct afb_evt_listener *listener) if (!__atomic_sub_fetch(&listener->refcount, 1, __ATOMIC_RELAXED)) { /* unlink the listener */ - pthread_mutex_lock(&listeners_mutex); + pthread_rwlock_wrlock(&listeners_rwlock); prv = &listeners; while (*prv != listener) prv = &(*prv)->next; *prv = listener->next; - pthread_mutex_unlock(&listeners_mutex); + pthread_rwlock_unlock(&listeners_rwlock); /* remove the watchers */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); while (listener->watchs != NULL) { evtid = listener->watchs->evtid; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&evtid->rwlock); remove_watch(listener->watchs); - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); /* free the listener */ - pthread_mutex_destroy(&listener->mutex); + pthread_rwlock_destroy(&listener->rwlock); free(listener); } } @@ -575,7 +578,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid } /* search the existing watch for the listener */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); watch = listener->watchs; while(watch != NULL) { if (watch->evtid == evtid) @@ -586,7 +589,7 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid /* not found, allocate a new */ watch = malloc(sizeof *watch); if (watch == NULL) { - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); errno = ENOMEM; return -1; } @@ -597,16 +600,16 @@ int afb_evt_watch_add_evtid(struct afb_evt_listener *listener, struct afb_evtid watch->listener = listener; watch->next_by_listener = listener->watchs; listener->watchs = watch; - pthread_mutex_lock(&evtid->mutex); + pthread_rwlock_wrlock(&evtid->rwlock); watch->next_by_evtid = evtid->watchs; evtid->watchs = watch; - pthread_mutex_unlock(&evtid->mutex); + pthread_rwlock_unlock(&evtid->rwlock); found: if (watch->activity == 0 && listener->itf->add != NULL) listener->itf->add(listener->closure, evtid->fullname, evtid->id); watch->activity++; - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); return 0; } @@ -620,7 +623,7 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid struct afb_evt_watch *watch; /* search the existing watch */ - pthread_mutex_lock(&listener->mutex); + pthread_rwlock_wrlock(&listener->rwlock); watch = listener->watchs; while(watch != NULL) { if (watch->evtid == evtid) { @@ -629,12 +632,12 @@ int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb_evtid if (watch->activity == 0 && listener->itf->remove != NULL) listener->itf->remove(listener->closure, evtid->fullname, evtid->id); } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); return 0; } watch = watch->next_by_listener; } - pthread_mutex_unlock(&listener->mutex); + pthread_rwlock_unlock(&listener->rwlock); errno = ENOENT; return -1; } @@ -646,20 +649,20 @@ void afb_evt_update_hooks() { struct afb_evtid *evtid; - pthread_mutex_lock(&events_mutex); + pthread_rwlock_rdlock(&events_rwlock); for (evtid = evtids ; evtid ; evtid = evtid->next) { evtid->hookflags = afb_hook_flags_evt(evtid->fullname); - evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_eventid_itf; + evtid->eventid.itf = evtid->hookflags ? &afb_evt_hooked_eventid_itf : &afb_evt_event_x2_itf; } - pthread_mutex_unlock(&events_mutex); + pthread_rwlock_unlock(&events_rwlock); } -inline struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid) +inline struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid) { return (struct afb_evtid*)eventid; } -inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid) +inline struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid) { return &evtid->eventid; } @@ -668,35 +671,35 @@ inline struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid) * Creates an event of 'fullname' and returns it. * Returns an event with closure==NULL in case of error. */ -struct afb_eventid *afb_evt_eventid_create(const char *fullname) +struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname) { - return afb_evt_eventid_from_evtid(afb_evt_evtid_create(fullname)); + return afb_evt_event_x2_from_evtid(afb_evt_evtid_create(fullname)); } /* * Creates an event of name 'prefix'/'name' and returns it. * Returns an event with closure==NULL in case of error. */ -struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name) +struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name) { - return afb_evt_eventid_from_evtid(afb_evt_evtid_create2(prefix, name)); + return afb_evt_event_x2_from_evtid(afb_evt_evtid_create2(prefix, name)); } /* * Returns the fullname of the 'eventid' */ -const char *afb_evt_eventid_fullname(struct afb_eventid *eventid) +const char *afb_evt_event_x2_fullname(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); return evtid ? evtid->fullname : NULL; } /* * Returns the id of the 'eventid' */ -int afb_evt_eventid_id(struct afb_eventid *eventid) +int afb_evt_event_x2_id(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); return evtid ? evtid->id : 0; } @@ -704,9 +707,9 @@ int afb_evt_eventid_id(struct afb_eventid *eventid) * Makes the 'listener' watching 'eventid' * Returns 0 in case of success or else -1. */ -int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid) +int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); /* check parameter */ if (!evtid) { @@ -722,9 +725,9 @@ int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_even * Avoids the 'listener' to watch 'eventid' * Returns 0 in case of success or else -1. */ -int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid) +int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); /* check parameter */ if (!evtid) { @@ -736,41 +739,41 @@ int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_e return afb_evt_watch_sub_evtid(listener, evtid); } -int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object) +int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) return afb_evt_evtid_hooked_push(evtid, object); json_object_put(object); return 0; } -int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object) +int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) return afb_evt_evtid_push(evtid, object); json_object_put(object); return 0; } -struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid) +struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid) { return evtid - ? (struct afb_event){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid } - : (struct afb_event){ .itf = NULL, .closure = NULL }; + ? (struct afb_event_x1){ .itf = &afb_evt_hooked_eventid_itf, .closure = &evtid->eventid } + : (struct afb_event_x1){ .itf = NULL, .closure = NULL }; } -void afb_evt_eventid_unref(struct afb_eventid *eventid) +void afb_evt_event_x2_unref(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) afb_evt_evtid_unref(evtid); } -struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid) +struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid) { - struct afb_evtid *evtid = afb_evt_eventid_to_evtid(eventid); + struct afb_evtid *evtid = afb_evt_event_x2_to_evtid(eventid); if (evtid) afb_evt_evtid_addref(evtid); return eventid; diff --git a/src/afb-evt.h b/src/afb-evt.h index c3999df2..ceb1b1b9 100644 --- a/src/afb-evt.h +++ b/src/afb-evt.h @@ -17,8 +17,8 @@ #pragma once -struct afb_event; -struct afb_eventid; +struct afb_event_x1; +struct afb_event_x2; struct afb_evtid; struct afb_session; struct json_object; @@ -66,20 +66,20 @@ extern int afb_evt_watch_sub_evtid(struct afb_evt_listener *listener, struct afb extern void afb_evt_update_hooks(); -extern struct afb_eventid *afb_evt_eventid_create(const char *fullname); -extern struct afb_eventid *afb_evt_eventid_create2(const char *prefix, const char *name); -extern const char *afb_evt_eventid_fullname(struct afb_eventid *eventid); -extern int afb_evt_eventid_id(struct afb_eventid *eventid); -extern struct afb_eventid *afb_evt_eventid_addref(struct afb_eventid *eventid); -extern void afb_evt_eventid_unref(struct afb_eventid *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_create(const char *fullname); +extern struct afb_event_x2 *afb_evt_event_x2_create2(const char *prefix, const char *name); +extern const char *afb_evt_event_x2_fullname(struct afb_event_x2 *event); +extern int afb_evt_event_x2_id(struct afb_event_x2 *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_addref(struct afb_event_x2 *eventid); +extern void afb_evt_event_x2_unref(struct afb_event_x2 *eventid); -extern int afb_evt_eventid_push(struct afb_eventid *eventid, struct json_object *object); -extern int afb_evt_eventid_unhooked_push(struct afb_eventid *eventid, struct json_object *object); +extern int afb_evt_event_x2_push(struct afb_event_x2 *eventid, struct json_object *object); +extern int afb_evt_event_x2_unhooked_push(struct afb_event_x2 *eventid, struct json_object *object); -extern int afb_evt_eventid_add_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid); -extern int afb_evt_eventid_remove_watch(struct afb_evt_listener *listener, struct afb_eventid *eventid); +extern int afb_evt_event_x2_add_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid); +extern int afb_evt_event_x2_remove_watch(struct afb_evt_listener *listener, struct afb_event_x2 *eventid); -extern struct afb_evtid *afb_evt_eventid_to_evtid(struct afb_eventid *eventid); -extern struct afb_eventid *afb_evt_eventid_from_evtid(struct afb_evtid *evtid); -extern struct afb_event afb_evt_event_from_evtid(struct afb_evtid *evtid); +extern struct afb_evtid *afb_evt_event_x2_to_evtid(struct afb_event_x2 *eventid); +extern struct afb_event_x2 *afb_evt_event_x2_from_evtid(struct afb_evtid *evtid); +extern struct afb_event_x1 afb_evt_event_from_evtid(struct afb_evtid *evtid); diff --git a/src/afb-export.c b/src/afb-export.c index 12adf08d..fbf77f86 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -20,6 +20,8 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <fnmatch.h> +#include <ctype.h> #include <json-c/json.h> @@ -28,7 +30,11 @@ #include "afb-api.h" #include "afb-apiset.h" -#include "afb-api-dyn.h" +#if defined(WITH_LEGACY_BINDING_V1) +#include "afb-api-so-v1.h" +#endif +#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-common.h" #include "afb-systemd.h" #include "afb-cred.h" @@ -38,20 +44,48 @@ #include "afb-msg-json.h" #include "afb-session.h" #include "afb-xreq.h" +#include "afb-calls.h" #include "jobs.h" #include "verbose.h" /************************************************************************* - * internal types and structures + * internal types ************************************************************************/ +/* + * structure for handling events + */ +struct event_handler +{ + /* link to the next event handler of the list */ + struct event_handler *next; + + /* function to call on the case of the event */ + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*); + + /* closure for the callback */ + void *closure; + + /* the handled pattern */ + char pattern[1]; +}; + +/* + * Actually supported versions + */ enum afb_api_version { - Api_Version_Dyn = 0, + Api_Version_None = 0, +#if defined(WITH_LEGACY_BINDING_V1) Api_Version_1 = 1, +#endif Api_Version_2 = 2, + Api_Version_3 = 3 }; +/* + * The states of exported APIs + */ enum afb_api_state { Api_State_Pre_Init, @@ -59,13 +93,16 @@ enum afb_api_state Api_State_Run }; +/* + * structure of the exported API + */ struct afb_export { /* keep it first */ - struct afb_dynapi dynapi; + struct afb_api_x3 api; - /* name of the api */ - char *apiname; + /* reference count */ + int refcount; /* version of the api */ unsigned version: 4; @@ -73,124 +110,157 @@ struct afb_export /* current state */ unsigned state: 4; + /* declared */ + unsigned declared: 1; + + /* unsealed */ + unsigned unsealed: 1; + /* hooking flags */ int hookditf; int hooksvc; - /* dynamic api */ - struct afb_api_dyn *apidyn; - /* session for service */ struct afb_session *session; - /* apiset for service */ - struct afb_apiset *apiset; + /* apiset the API is declared in */ + struct afb_apiset *declare_set; + + /* apiset for calls */ + struct afb_apiset *call_set; /* event listener for service or NULL */ struct afb_evt_listener *listener; + /* event handler list */ + struct event_handler *event_handlers; + + /* internal descriptors */ + union { +#if defined(WITH_LEGACY_BINDING_V1) + struct afb_binding_v1 *v1; +#endif + const struct afb_binding_v2 *v2; + struct afb_api_v3 *v3; + } desc; + /* start function */ union { - int (*v1)(struct afb_service); +#if defined(WITH_LEGACY_BINDING_V1) + int (*v1)(struct afb_service_x1); +#endif int (*v2)(); - int (*vdyn)(struct afb_dynapi *dynapi); + int (*v3)(struct afb_api_x3 *api); } init; /* event handling */ - union { - void (*v12)(const char *event, struct json_object *object); - void (*vdyn)(struct afb_dynapi *dynapi, const char *event, struct json_object *object); - } on_event; + void (*on_any_event_v12)(const char *event, struct json_object *object); + void (*on_any_event_v3)(struct afb_api_x3 *api, const char *event, struct json_object *object); /* exported data */ union { +#if defined(WITH_LEGACY_BINDING_V1) struct afb_binding_interface_v1 v1; +#endif struct afb_binding_data_v2 *v2; } export; + + /* initial name */ + char name[1]; }; -/************************************************************************************************************/ +/*****************************************************************************/ + +static inline struct afb_api_x3 *to_api_x3(struct afb_export *export) +{ + return (struct afb_api_x3*)export; +} -static inline struct afb_dynapi *to_dynapi(struct afb_export *export) +static inline struct afb_export *from_api_x3(struct afb_api_x3 *api) { - return (struct afb_dynapi*)export; + return (struct afb_export*)api; } -static inline struct afb_export *from_dynapi(struct afb_dynapi *dynapi) +struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api) { - return (struct afb_export*)dynapi; + return from_api_x3(api); } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export) +{ + return to_api_x3(export); +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D I T F - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /********************************************** * normal flow **********************************************/ -static void vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { char *p; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, function, fmt, args); else { - verbose(level, file, line, function, "[API %s] %s", export->apiname, p); + verbose(level, file, line, function, "[API %s] %s", export->api.apiname, p); free(p); } } -static void old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args) +static void legacy_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) { vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_eventid *eventid_make_cb(void *closure, const char *name) +static struct afb_event_x2 *event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->apiname, name); + ERROR("[API %s] Bad call to 'afb_daemon_event_make(%s)', must not be in PreInit", export->api.apiname, name); errno = EINVAL; return NULL; } /* create the event */ - return afb_evt_eventid_create2(export->apiname, name); + return afb_evt_event_x2_create2(export->api.apiname, name); } -static struct afb_event event_make_cb(void *closure, const char *name) +static struct afb_event_x1 legacy_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_eventid *eventid = eventid_make_cb(closure, name); - return afb_evt_event_from_evtid(afb_evt_eventid_to_evtid(eventid)); + struct afb_event_x2 *event = event_x2_make_cb(closure, name); + return afb_evt_event_from_evtid(afb_evt_event_x2_to_evtid(event)); } -static int event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { size_t plen, nlen; char *event; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); /* check daemon state */ if (export->state == Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->apiname, name, json_object_to_json_string(object)); + ERROR("[API %s] Bad call to 'afb_daemon_event_broadcast(%s, %s)', must not be in PreInit", export->api.apiname, name, json_object_to_json_string(object)); errno = EINVAL; return 0; } /* makes the event name */ - plen = strlen(export->apiname); + plen = strlen(export->api.apiname); nlen = strlen(name); event = alloca(nlen + plen + 2); - memcpy(event, export->apiname, plen); + memcpy(event, export->api.apiname, plen); event[plen] = '/'; memcpy(event + plen + 1, name, nlen + 1); @@ -198,190 +268,218 @@ static int event_broadcast_cb(void *closure, const char *name, struct json_objec return afb_evt_broadcast(event, object); } -static int rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static int rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { return afb_common_rootdir_open_locale(filename, flags, locale); } -static int queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static int queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { return jobs_queue(group, timeout, callback, argument); } -static struct afb_req unstore_req_cb(void *closure, struct afb_stored_req *sreq) +static struct afb_req_x1 legacy_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) { return afb_xreq_unstore(sreq); } -static int require_api_cb(void *closure, const char *name, int initialized) -{ - struct afb_export *export = closure; - if (export->state != Api_State_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_require(%s, %d)', must be in Init", export->apiname, name, initialized); - errno = EINVAL; - return -1; +static int require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) +{ + struct afb_export *export = from_api_x3(closure); + int rc, rc2; + char *iter, *end, save; + + /* scan the names in a local copy */ + rc = 0; + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + /* check the required api */ + if (export->state == Api_State_Pre_Init) + rc2 = afb_apiset_require(export->declare_set, export->api.apiname, name); + else + rc2 = -!((initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->call_set, iter, 1)); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; } - return -!(initialized ? afb_apiset_lookup_started : afb_apiset_lookup)(export->apiset, name, 1); } -static int rename_api_cb(void *closure, const char *name) +static int add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) { - struct afb_export *export = closure; - if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_daemon_rename(%s)', must be in PreInit", export->apiname, name); - errno = EINVAL; - return -1; - } - if (!afb_api_is_valid_name(name, 1)) { - ERROR("[API %s] Can't rename to %s: bad API name", export->apiname, name); + struct afb_export *export = from_api_x3(closure); + if (!afb_api_is_valid_name(aliasname)) { + ERROR("[API %s] Can't add alias to %s: bad API name", export->api.apiname, aliasname); errno = EINVAL; return -1; } - NOTICE("[API %s] renamed to [API %s]", export->apiname, name); - afb_export_rename(export, name); + NOTICE("[API %s] aliasing [API %s] to [API %s]", export->api.apiname, apiname?:"<null>", aliasname); + afb_export_add_alias(export, apiname, aliasname); return 0; } -static int api_new_api_cb( - void *closure, +static struct afb_api_x3 *api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - struct afb_export *export = closure; - return afb_api_dyn_add(export->apiset, api, info, noconcurrency, preinit, preinit_closure); + struct afb_export *export = from_api_x3(closure); + struct afb_api_v3 *apiv3 = afb_api_v3_create(export->declare_set, export->call_set, api, info, noconcurrency, preinit, preinit_closure, 1); + return apiv3 ? to_api_x3(afb_api_v3_export(apiv3)) : NULL; } /********************************************** * hooked flow **********************************************/ -static void hooked_vverbose_cb(void *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hooked_vverbose_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); va_list ap; va_copy(ap, args); vverbose_cb(closure, level, file, line, function, fmt, args); - afb_hook_ditf_vverbose(export, level, file, line, function, fmt, ap); + afb_hook_api_vverbose(export, level, file, line, function, fmt, ap); va_end(ap); } -static void hooked_old_vverbose_cb(void *closure, int level, const char *file, int line, const char *fmt, va_list args) +static void legacy_hooked_vverbose_v1_cb(struct afb_api_x3 *closure, int level, const char *file, int line, const char *fmt, va_list args) { hooked_vverbose_cb(closure, level, file, line, NULL, fmt, args); } -static struct afb_eventid *hooked_eventid_make_cb(void *closure, const char *name) +static struct afb_event_x2 *hooked_event_x2_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_export *export = closure; - struct afb_eventid *r = eventid_make_cb(closure, name); - afb_hook_ditf_event_make(export, name, r); + struct afb_export *export = from_api_x3(closure); + struct afb_event_x2 *r = event_x2_make_cb(closure, name); + afb_hook_api_event_make(export, name, r); return r; } -static struct afb_event hooked_event_make_cb(void *closure, const char *name) +static struct afb_event_x1 legacy_hooked_event_x1_make_cb(struct afb_api_x3 *closure, const char *name) { - struct afb_eventid *eventid = hooked_eventid_make_cb(closure, name); - return (struct afb_event){ .itf = eventid ? eventid->itf : NULL, .closure = eventid }; + struct afb_event_x2 *event = hooked_event_x2_make_cb(closure, name); + struct afb_event_x1 e; + e.closure = event; + e.itf = event ? event->itf : NULL; + return e; } -static int hooked_event_broadcast_cb(void *closure, const char *name, struct json_object *object) +static int hooked_event_broadcast_cb(struct afb_api_x3 *closure, const char *name, struct json_object *object) { int r; - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); json_object_get(object); - afb_hook_ditf_event_broadcast_before(export, name, json_object_get(object)); + afb_hook_api_event_broadcast_before(export, name, json_object_get(object)); r = event_broadcast_cb(closure, name, object); - afb_hook_ditf_event_broadcast_after(export, name, object, r); + afb_hook_api_event_broadcast_after(export, name, object, r); json_object_put(object); return r; } -static struct sd_event *hooked_get_event_loop(void *closure) +static struct sd_event *hooked_get_event_loop(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_event *r = afb_systemd_get_event_loop(); - return afb_hook_ditf_get_event_loop(export, r); + return afb_hook_api_get_event_loop(export, r); } -static struct sd_bus *hooked_get_user_bus(void *closure) +static struct sd_bus *hooked_get_user_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_bus *r = afb_systemd_get_user_bus(); - return afb_hook_ditf_get_user_bus(export, r); + return afb_hook_api_get_user_bus(export, r); } -static struct sd_bus *hooked_get_system_bus(void *closure) +static struct sd_bus *hooked_get_system_bus(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); struct sd_bus *r = afb_systemd_get_system_bus(); - return afb_hook_ditf_get_system_bus(export, r); + return afb_hook_api_get_system_bus(export, r); } -static int hooked_rootdir_get_fd(void *closure) +static int hooked_rootdir_get_fd(struct afb_api_x3 *closure) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = afb_common_rootdir_get_fd(); - return afb_hook_ditf_rootdir_get_fd(export, r); + return afb_hook_api_rootdir_get_fd(export, r); } -static int hooked_rootdir_open_locale_cb(void *closure, const char *filename, int flags, const char *locale) +static int hooked_rootdir_open_locale_cb(struct afb_api_x3 *closure, const char *filename, int flags, const char *locale) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = rootdir_open_locale_cb(closure, filename, flags, locale); - return afb_hook_ditf_rootdir_open_locale(export, filename, flags, locale, r); + return afb_hook_api_rootdir_open_locale(export, filename, flags, locale, r); } -static int hooked_queue_job_cb(void *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) +static int hooked_queue_job_cb(struct afb_api_x3 *closure, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout) { - struct afb_export *export = closure; + struct afb_export *export = from_api_x3(closure); int r = queue_job_cb(closure, callback, argument, group, timeout); - return afb_hook_ditf_queue_job(export, callback, argument, group, timeout, r); + return afb_hook_api_queue_job(export, callback, argument, group, timeout, r); } -static struct afb_req hooked_unstore_req_cb(void *closure, struct afb_stored_req *sreq) +static struct afb_req_x1 legacy_hooked_unstore_req_cb(struct afb_api_x3 *closure, struct afb_stored_req *sreq) { - struct afb_export *export = closure; - afb_hook_ditf_unstore_req(export, sreq); - return unstore_req_cb(closure, sreq); + struct afb_export *export = from_api_x3(closure); + afb_hook_api_legacy_unstore_req(export, sreq); + return legacy_unstore_req_cb(closure, sreq); } -static int hooked_require_api_cb(void *closure, const char *name, int initialized) +static int hooked_require_api_cb(struct afb_api_x3 *closure, const char *name, int initialized) { int result; - struct afb_export *export = closure; - afb_hook_ditf_require_api(export, name, initialized); + struct afb_export *export = from_api_x3(closure); + afb_hook_api_require_api(export, name, initialized); result = require_api_cb(closure, name, initialized); - return afb_hook_ditf_require_api_result(export, name, initialized, result); + return afb_hook_api_require_api_result(export, name, initialized, result); } -static int hooked_rename_api_cb(void *closure, const char *name) +static int hooked_add_alias_cb(struct afb_api_x3 *closure, const char *apiname, const char *aliasname) { - struct afb_export *export = closure; - const char *oldname = export->apiname; - int result = rename_api_cb(closure, name); - return afb_hook_ditf_rename_api(export, oldname, name, result); + struct afb_export *export = from_api_x3(closure); + int result = add_alias_cb(closure, apiname, aliasname); + return afb_hook_api_add_alias(export, apiname, aliasname, result); } -static int hooked_api_new_api_cb( - void *closure, +static struct afb_api_x3 *hooked_api_new_api_cb( + struct afb_api_x3 *closure, const char *api, const char *info, int noconcurrency, - int (*preinit)(void*, struct afb_dynapi *), + int (*preinit)(void*, struct afb_api_x3 *), void *preinit_closure) { - /* TODO */ - return api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + struct afb_api_x3 *result; + struct afb_export *export = from_api_x3(closure); + afb_hook_api_new_api_before(export, api, info, noconcurrency); + result = api_new_api_cb(closure, api, info, noconcurrency, preinit, preinit_closure); + afb_hook_api_new_api_after(export, -!result, api); + return result; } + /********************************************** * vectors **********************************************/ -static const struct afb_daemon_itf daemon_itf = { - .vverbose_v1 = old_vverbose_cb, +static const struct afb_daemon_itf_x1 daemon_itf = { + .vverbose_v1 = legacy_vverbose_v1_cb, .vverbose_v2 = vverbose_cb, - .event_make = event_make_cb, + .event_make = legacy_event_x1_make_cb, .event_broadcast = event_broadcast_cb, .get_event_loop = afb_systemd_get_event_loop, .get_user_bus = afb_systemd_get_user_bus, @@ -389,16 +487,16 @@ static const struct afb_daemon_itf daemon_itf = { .rootdir_get_fd = afb_common_rootdir_get_fd, .rootdir_open_locale = rootdir_open_locale_cb, .queue_job = queue_job_cb, - .unstore_req = unstore_req_cb, + .unstore_req = legacy_unstore_req_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb, + .add_alias = add_alias_cb, .new_api = api_new_api_cb, }; -static const struct afb_daemon_itf hooked_daemon_itf = { - .vverbose_v1 = hooked_old_vverbose_cb, +static const struct afb_daemon_itf_x1 hooked_daemon_itf = { + .vverbose_v1 = legacy_hooked_vverbose_v1_cb, .vverbose_v2 = hooked_vverbose_cb, - .event_make = hooked_event_make_cb, + .event_make = legacy_hooked_event_x1_make_cb, .event_broadcast = hooked_event_broadcast_cb, .get_event_loop = hooked_get_event_loop, .get_user_bus = hooked_get_user_bus, @@ -406,422 +504,185 @@ static const struct afb_daemon_itf hooked_daemon_itf = { .rootdir_get_fd = hooked_rootdir_get_fd, .rootdir_open_locale = hooked_rootdir_open_locale_cb, .queue_job = hooked_queue_job_cb, - .unstore_req = hooked_unstore_req_cb, + .unstore_req = legacy_hooked_unstore_req_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .new_api = hooked_api_new_api_cb, }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /* the common session for services sharing their session */ static struct afb_session *common_session; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ - -/* - * Structure for requests initiated by the service - */ -struct call_req -{ - struct afb_xreq xreq; - - struct afb_export *export; - - /* the args */ - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *closure; - - /* sync */ - struct jobloop *jobloop; - struct json_object *result; - int status; -}; - -/* - * destroys the call_req - */ -static void callreq_destroy(struct afb_xreq *xreq) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - - afb_context_disconnect(&callreq->xreq.context); - json_object_put(callreq->xreq.json); - afb_cred_unref(callreq->xreq.cred); - free(callreq); -} - -static void callreq_reply_async(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback) - callreq->callback(callreq->closure, status, obj); - json_object_put(obj); -} - -static void callreq_reply_async_dynapi(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - if (callreq->callback_dynapi) - callreq->callback_dynapi(callreq->closure, status, obj, to_dynapi(callreq->export)); - json_object_put(obj); -} + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -static void callreq_sync_leave(struct call_req *callreq) -{ - struct jobloop *jobloop = callreq->jobloop; - - if (jobloop) { - callreq->jobloop = NULL; - jobs_leave(jobloop); - } -} - -static void callreq_reply_sync(struct afb_xreq *xreq, int status, json_object *obj) -{ - struct call_req *callreq = CONTAINER_OF_XREQ(struct call_req, xreq); - callreq->status = status; - callreq->result = obj; - callreq_sync_leave(callreq); -} - -static void callreq_sync_enter(int signum, void *closure, struct jobloop *jobloop) +static void call_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char *error, const char *info, struct afb_api_x3*), + void *closure) { - struct call_req *callreq = closure; - - if (!signum) { - callreq->jobloop = jobloop; - afb_xreq_process(&callreq->xreq, callreq->export->apiset); - } else { - callreq->result = afb_msg_json_internal_error(); - callreq->status = -1; - callreq_sync_leave(callreq); - } + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call(export, api, verb, args, callback, closure); } -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_async_dynapi_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_async_dynapi -}; - -/* interface for requests of services */ -const struct afb_xreq_query_itf afb_export_xreq_sync_itf = { - .unref = callreq_destroy, - .reply = callreq_reply_sync -}; - -/* - * create an call_req - */ -static struct call_req *callreq_create( - struct afb_export *export, +static int call_sync_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - const struct afb_xreq_query_itf *itf) -{ - struct call_req *callreq; - size_t lenapi, lenverb; - char *copy; - - /* allocates the request */ - lenapi = 1 + strlen(api); - lenverb = 1 + strlen(verb); - callreq = malloc(lenapi + lenverb + sizeof *callreq); - if (callreq != NULL) { - /* initialises the request */ - afb_xreq_init(&callreq->xreq, itf); - afb_context_init(&callreq->xreq.context, export->session, NULL); - callreq->xreq.context.validated = 1; - copy = (char*)&callreq[1]; - memcpy(copy, api, lenapi); - callreq->xreq.request.api = copy; - copy = ©[lenapi]; - memcpy(copy, verb, lenverb); - callreq->xreq.request.verb = copy; - callreq->xreq.listener = export->listener; - callreq->xreq.json = args; - callreq->export = export; - } - return callreq; + struct json_object **object, + char **error, + char **info) +{ + struct afb_export *export = from_api_x3(apix3); + return afb_calls_call_sync(export, api, verb, args, object, error, info); } -/* - * Initiates a call for the service - */ -static void svc_call( - void *closure, +static void legacy_call_v12( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), - void *cbclosure) + void *closure) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_call_v12(export, api, verb, args, callback, closure); } -static void svc_call_dynapi( - struct afb_dynapi *dynapi, +static void legacy_call_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), - void *cbclosure) -{ - struct afb_export *export = from_dynapi(dynapi); - struct call_req *callreq; - struct json_object *ierr; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_async_dynapi_itf); - if (callreq == NULL) { - ERROR("out of memory"); - json_object_put(args); - ierr = afb_msg_json_internal_error(); - if (callback) - callback(cbclosure, -1, ierr, to_dynapi(export)); - json_object_put(ierr); - return; - } - - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback_dynapi = callback; - callreq->closure = cbclosure; - - /* terminates and frees ressources if needed */ - afb_xreq_process(&callreq->xreq, export->apiset); + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_call_v3(export, api, verb, args, callback, closure); } -static int svc_call_sync( - void *closure, +static int legacy_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct call_req *callreq; - struct json_object *resu; - int rc; - - /* allocates the request */ - callreq = callreq_create(export, api, verb, args, &afb_export_xreq_sync_itf); - if (callreq == NULL) { - ERROR("out of memory"); - errno = ENOMEM; - json_object_put(args); - resu = afb_msg_json_internal_error(); - rc = -1; - } else { - /* initialises the request */ - callreq->jobloop = NULL; - callreq->callback = NULL; - callreq->result = NULL; - callreq->status = 0; - afb_xreq_unhooked_addref(&callreq->xreq); /* avoid early callreq destruction */ - rc = jobs_enter(NULL, 0, callreq_sync_enter, callreq); - if (rc >= 0) - rc = callreq->status; - resu = (rc >= 0 || callreq->result) ? callreq->result : afb_msg_json_internal_error(); - afb_xreq_unhooked_unref(&callreq->xreq); - } - if (result) - *result = resu; - else - json_object_put(resu); - return rc; + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_call_sync(export, api, verb, args, result); } -struct hooked_call -{ - struct afb_export *export; - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_dynapi)(void*, int, struct json_object*, struct afb_dynapi*); - }; - void *cbclosure; -}; - -static void svc_hooked_call_result(void *closure, int status, struct json_object *result) +static void hooked_call_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_api_x3*), + void *closure) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback(hc->cbclosure, status, result); - free(hc); + struct afb_export *export = from_api_x3(apix3); + afb_calls_hooked_call(export, api, verb, args, callback, closure); } -static void svc_hooked_call_dynapi_result(void *closure, int status, struct json_object *result, struct afb_dynapi *dynapi) +static int hooked_call_sync_x3( + struct afb_api_x3 *apix3, + const char *api, + const char *verb, + struct json_object *args, + struct json_object **object, + char **error, + char **info) { - struct hooked_call *hc = closure; - afb_hook_svc_call_result(hc->export, status, result); - hc->callback_dynapi(hc->cbclosure, status, result, dynapi); - free(hc); + struct afb_export *export = from_api_x3(apix3); + return afb_calls_hooked_call_sync(export, api, verb, args, object, error, info); } -static void svc_hooked_call( - void *closure, +static void legacy_hooked_call_v12( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), - void *cbclosure) + void *closure) { - struct afb_export *export = closure; - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_result; - cbclosure = hc; - } - } - svc_call(closure, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v12(export, api, verb, args, callback, closure); } -static void svc_hooked_call_dynapi( - struct afb_dynapi *dynapi, +static void legacy_hooked_call_x3( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_dynapi*), - void *cbclosure) + void (*callback)(void*, int, struct json_object*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = from_dynapi(dynapi); - struct hooked_call *hc; - - if (export->hooksvc & afb_hook_flag_svc_call) - afb_hook_svc_call(export, api, verb, args); - - if (export->hooksvc & afb_hook_flag_svc_call_result) { - hc = malloc(sizeof *hc); - if (!hc) - WARNING("allocation failed"); - else { - hc->export = export; - hc->callback_dynapi = callback; - hc->cbclosure = cbclosure; - callback = svc_hooked_call_dynapi_result; - cbclosure = hc; - } - } - svc_call_dynapi(dynapi, api, verb, args, callback, cbclosure); + struct afb_export *export = from_api_x3(apix3); + afb_calls_legacy_hooked_call_v3(export, api, verb, args, callback, closure); } -static int svc_hooked_call_sync( - void *closure, +static int legacy_hooked_call_sync( + struct afb_api_x3 *apix3, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - struct afb_export *export = closure; - struct json_object *resu; - int rc; - - if (export->hooksvc & afb_hook_flag_svc_callsync) - afb_hook_svc_callsync(export, api, verb, args); - - rc = svc_call_sync(closure, api, verb, args, &resu); - - if (export->hooksvc & afb_hook_flag_svc_callsync_result) - afb_hook_svc_callsync_result(export, rc, resu); - - if (result) - *result = resu; - else - json_object_put(resu); - - return rc; + struct afb_export *export = from_api_x3(apix3); + return afb_calls_legacy_hooked_call_sync(export, api, verb, args, result); } /* the interface for services */ -static const struct afb_service_itf service_itf = { - .call = svc_call, - .call_sync = svc_call_sync +static const struct afb_service_itf_x1 service_itf = { + .call = legacy_call_v12, + .call_sync = legacy_call_sync }; /* the interface for services */ -static const struct afb_service_itf hooked_service_itf = { - .call = svc_hooked_call, - .call_sync = svc_hooked_call_sync +static const struct afb_service_itf_x1 hooked_service_itf = { + .call = legacy_hooked_call_v12, + .call_sync = legacy_hooked_call_sync }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** F R O M D Y N A P I - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ static int api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) { - afb_api_dyn_set_verbs_v2(export->apidyn, verbs); + if (export->unsealed) { + afb_api_v3_set_verbs_v2(export->desc.v3, verbs); return 0; } @@ -829,115 +690,292 @@ static int api_set_verbs_v2_cb( return -1; } +static int api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } + + afb_api_v3_set_verbs_v3(export->desc.v3, verbs); + return 0; +} + static int api_add_verb_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const char *verb, const char *info, - void (*callback)(struct afb_request *request), + void (*callback)(struct afb_req_x2 *req), void *vcbdata, const struct afb_auth *auth, - uint32_t session) + uint32_t session, + int glob) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_add_verb(export->apidyn, verb, info, callback, vcbdata, auth, session); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_add_verb(export->desc.v3, verb, info, callback, vcbdata, auth, (uint16_t)session, glob); } -static int api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int api_del_verb_cb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - if (export->apidyn) - return afb_api_dyn_sub_verb(export->apidyn, verb); + if (!export->unsealed) { + errno = EPERM; + return -1; + } - errno = EPERM; - return -1; + return afb_api_v3_del_verb(export->desc.v3, verb, vcbdata); } static int api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { - struct afb_export *export = from_dynapi(dynapi); - return afb_export_handle_events_vdyn(export, onevent); + struct afb_export *export = from_api_x3(api); + return afb_export_handle_events_v3(export, onevent); } static int api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); - return afb_export_handle_init_vdyn(export, oninit); + return afb_export_handle_init_v3(export, oninit); } static void api_seal_cb( - struct afb_dynapi *dynapi) + struct afb_api_x3 *api) +{ + struct afb_export *export = from_api_x3(api); + + export->unsealed = 0; +} + +static int event_handler_add_cb( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_add(export, pattern, callback, closure); +} + +static int event_handler_del_cb( + struct afb_api_x3 *api, + const char *pattern, + void **closure) +{ + struct afb_export *export = from_api_x3(api); + + return afb_export_event_handler_del(export, pattern, closure); +} + +static int class_provide_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_provide_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } +} + +static int class_require_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + + int rc = 0, rc2; + char *iter, *end, save; + + iter = strdupa(name); + for(;;) { + /* skip any space */ + save = *iter; + while(isspace(save)) + save = *++iter; + if (!save) /* at end? */ + return rc; + + /* search for the end */ + end = iter; + while (save && !isspace(save)) + save = *++end; + *end = 0; + + rc2 = afb_apiset_require_class(export->declare_set, api->apiname, iter); + if (rc2 < 0) + rc = rc2; + + *end = save; + iter = end; + } +} + +static int delete_api_cb(struct afb_api_x3 *api) { - struct afb_export *export = from_dynapi(dynapi); + struct afb_export *export = from_api_x3(api); + + if (!export->unsealed) { + errno = EPERM; + return -1; + } - export->apidyn = NULL; + afb_export_undeclare(export); + afb_export_unref(export); + return 0; } static int hooked_api_set_verbs_v2_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const struct afb_verb_v2 *verbs) { - /* TODO */ - return api_set_verbs_v2_cb(dynapi, verbs); + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v2_cb(api, verbs); + return afb_hook_api_api_set_verbs_v2(export, result, verbs); +} + +static int hooked_api_set_verbs_v3_cb( + struct afb_api_x3 *api, + const struct afb_verb_v3 *verbs) +{ + struct afb_export *export = from_api_x3(api); + int result = api_set_verbs_v3_cb(api, verbs); + return afb_hook_api_api_set_verbs_v3(export, result, verbs); } static int hooked_api_add_verb_cb( - struct afb_dynapi *dynapi, + struct afb_api_x3 *api, const char *verb, const char *info, - void (*callback)(struct afb_request *request), + void (*callback)(struct afb_req_x2 *req), void *vcbdata, const struct afb_auth *auth, - uint32_t session) + uint32_t session, + int glob) { - /* TODO */ - return api_add_verb_cb(dynapi, verb, info, callback, vcbdata, auth, session); + struct afb_export *export = from_api_x3(api); + int result = api_add_verb_cb(api, verb, info, callback, vcbdata, auth, session, glob); + return afb_hook_api_api_add_verb(export, result, verb, info, glob); } -static int hooked_api_sub_verb_cb( - struct afb_dynapi *dynapi, - const char *verb) +static int hooked_api_del_verb_cb( + struct afb_api_x3 *api, + const char *verb, + void **vcbdata) { - /* TODO */ - return api_sub_verb_cb(dynapi, verb); + struct afb_export *export = from_api_x3(api); + int result = api_del_verb_cb(api, verb, vcbdata); + return afb_hook_api_api_del_verb(export, result, verb); } static int hooked_api_set_on_event_cb( - struct afb_dynapi *dynapi, - void (*onevent)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) + struct afb_api_x3 *api, + void (*onevent)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { - /* TODO */ - return api_set_on_event_cb(dynapi, onevent); + struct afb_export *export = from_api_x3(api); + int result = api_set_on_event_cb(api, onevent); + return afb_hook_api_api_set_on_event(export, result); } static int hooked_api_set_on_init_cb( - struct afb_dynapi *dynapi, - int (*oninit)(struct afb_dynapi *dynapi)) + struct afb_api_x3 *api, + int (*oninit)(struct afb_api_x3 *api)) { - /* TODO */ - return api_set_on_init_cb(dynapi, oninit); + struct afb_export *export = from_api_x3(api); + int result = api_set_on_init_cb(api, oninit); + return afb_hook_api_api_set_on_init(export, result); } static void hooked_api_seal_cb( - struct afb_dynapi *dynapi) + struct afb_api_x3 *api) { - /* TODO */ - api_seal_cb(dynapi); + struct afb_export *export = from_api_x3(api); + afb_hook_api_api_seal(export); + api_seal_cb(api); } -static const struct afb_dynapi_itf dynapi_itf = { +static int hooked_event_handler_add_cb( + struct afb_api_x3 *api, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + struct afb_export *export = from_api_x3(api); + int result = event_handler_add_cb(api, pattern, callback, closure); + return afb_hook_api_event_handler_add(export, result, pattern); +} + +static int hooked_event_handler_del_cb( + struct afb_api_x3 *api, + const char *pattern, + void **closure) +{ + struct afb_export *export = from_api_x3(api); + int result = event_handler_del_cb(api, pattern, closure); + return afb_hook_api_event_handler_del(export, result, pattern); +} + +static int hooked_class_provide_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + int result = class_provide_cb(api, name); + return afb_hook_api_class_provide(export, result, name); +} + +static int hooked_class_require_cb(struct afb_api_x3 *api, const char *name) +{ + struct afb_export *export = from_api_x3(api); + int result = class_require_cb(api, name); + return afb_hook_api_class_require(export, result, name); +} + +static int hooked_delete_api_cb(struct afb_api_x3 *api) +{ + struct afb_export *export = afb_export_addref(from_api_x3(api)); + int result = delete_api_cb(api); + result = afb_hook_api_delete_api(export, result); + afb_export_unref(export); + return result; +} + +static const struct afb_api_x3_itf api_x3_itf = { .vverbose = (void*)vverbose_cb, @@ -949,24 +987,35 @@ static const struct afb_dynapi_itf dynapi_itf = { .queue_job = queue_job_cb, .require_api = require_api_cb, - .rename_api = rename_api_cb, + .add_alias = add_alias_cb, .event_broadcast = event_broadcast_cb, - .eventid_make = eventid_make_cb, + .event_make = event_x2_make_cb, - .call = svc_call_dynapi, - .call_sync = svc_call_sync, + .legacy_call = legacy_call_x3, + .legacy_call_sync = legacy_call_sync, .api_new_api = api_new_api_cb, .api_set_verbs_v2 = api_set_verbs_v2_cb, .api_add_verb = api_add_verb_cb, - .api_sub_verb = api_sub_verb_cb, + .api_del_verb = api_del_verb_cb, .api_set_on_event = api_set_on_event_cb, .api_set_on_init = api_set_on_init_cb, .api_seal = api_seal_cb, + .api_set_verbs_v3 = api_set_verbs_v3_cb, + .event_handler_add = event_handler_add_cb, + .event_handler_del = event_handler_del_cb, + + .call = call_x3, + .call_sync = call_sync_x3, + + .class_provide = class_provide_cb, + .class_require = class_require_cb, + + .delete_api = delete_api_cb, }; -static const struct afb_dynapi_itf hooked_dynapi_itf = { +static const struct afb_api_x3_itf hooked_api_x3_itf = { .vverbose = hooked_vverbose_cb, @@ -978,86 +1027,187 @@ static const struct afb_dynapi_itf hooked_dynapi_itf = { .queue_job = hooked_queue_job_cb, .require_api = hooked_require_api_cb, - .rename_api = hooked_rename_api_cb, + .add_alias = hooked_add_alias_cb, .event_broadcast = hooked_event_broadcast_cb, - .eventid_make = hooked_eventid_make_cb, + .event_make = hooked_event_x2_make_cb, - .call = svc_hooked_call_dynapi, - .call_sync = svc_hooked_call_sync, + .legacy_call = legacy_hooked_call_x3, + .legacy_call_sync = legacy_hooked_call_sync, .api_new_api = hooked_api_new_api_cb, .api_set_verbs_v2 = hooked_api_set_verbs_v2_cb, .api_add_verb = hooked_api_add_verb_cb, - .api_sub_verb = hooked_api_sub_verb_cb, + .api_del_verb = hooked_api_del_verb_cb, .api_set_on_event = hooked_api_set_on_event_cb, .api_set_on_init = hooked_api_set_on_init_cb, .api_seal = hooked_api_seal_cb, + .api_set_verbs_v3 = hooked_api_set_verbs_v3_cb, + .event_handler_add = hooked_event_handler_add_cb, + .event_handler_del = hooked_event_handler_del_cb, + + .call = hooked_call_x3, + .call_sync = hooked_call_sync_x3, + + .class_provide = hooked_class_provide_cb, + .class_require = hooked_class_require_cb, + + .delete_api = hooked_delete_api_cb, }; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - F R O M S V C - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + L I S T E N E R S + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ /* * Propagates the event to the service */ -static void export_on_event_v12(void *closure, const char *event, int eventid, struct json_object *object) -{ - struct afb_export *export = closure; +static void listener_of_events(void *closure, const char *event, int eventid, struct json_object *object) +{ + struct event_handler *handler; + struct afb_export *export = from_api_x3(closure); + + /* hook the event before */ + if (export->hooksvc & afb_hook_flag_api_on_event) + afb_hook_api_on_event_before(export, event, eventid, object); + + /* transmit to specific handlers */ + /* search the handler */ + handler = export->event_handlers; + while (handler) { + if (fnmatch(handler->pattern, event, 0)) { + if (!(export->hooksvc & afb_hook_flag_api_on_event_handler)) + handler->callback(handler->closure, event, object, to_api_x3(export)); + else { + afb_hook_api_on_event_handler_before(export, event, eventid, object, handler->pattern); + handler->callback(handler->closure, event, object, to_api_x3(export)); + afb_hook_api_on_event_handler_after(export, event, eventid, object, handler->pattern); + } + } + handler = handler->next; + } + + /* transmit to default handler */ + if (export->on_any_event_v3) + export->on_any_event_v3(to_api_x3(export), event, object); + else if (export->on_any_event_v12) + export->on_any_event_v12(event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.v12(event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, object); + /* hook the event after */ + if (export->hooksvc & afb_hook_flag_api_on_event) + afb_hook_api_on_event_after(export, event, eventid, object); json_object_put(object); } /* the interface for events */ -static const struct afb_evt_itf evt_v12_itf = { - .broadcast = export_on_event_v12, - .push = export_on_event_v12 +static const struct afb_evt_itf evt_itf = { + .broadcast = listener_of_events, + .push = listener_of_events }; -/* - * Propagates the event to the service - */ -static void export_on_event_vdyn(void *closure, const char *event, int eventid, struct json_object *object) +/* ensure an existing listener */ +static int ensure_listener(struct afb_export *export) { - struct afb_export *export = closure; + if (!export->listener) { + export->listener = afb_evt_listener_create(&evt_itf, export); + if (export->listener == NULL) + return -1; + } + return 0; +} - if (export->hooksvc & afb_hook_flag_svc_on_event_before) - afb_hook_svc_on_event_before(export, event, eventid, object); - export->on_event.vdyn(to_dynapi(export), event, object); - if (export->hooksvc & afb_hook_flag_svc_on_event_after) - afb_hook_svc_on_event_after(export, event, eventid, object); - json_object_put(object); +int afb_export_event_handler_add( + struct afb_export *export, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure) +{ + int rc; + struct event_handler *handler, **previous; + + rc = ensure_listener(export); + if (rc < 0) + return rc; + + /* search the handler */ + previous = &export->event_handlers; + while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) + previous = &handler->next; + + /* error if found */ + if (handler) { + ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); + errno = EEXIST; + return -1; + } + + /* create the event */ + handler = malloc(strlen(pattern) + strlen(pattern)); + if (!handler) { + ERROR("[API %s] can't allocate event handler %s", export->api.apiname, pattern); + errno = ENOMEM; + return -1; + } + + /* init and record */ + handler->next = NULL; + handler->callback = callback; + handler->closure = closure; + strcpy(handler->pattern, pattern); + export->event_handlers = handler; + + return 0; } -/* the interface for events */ -static const struct afb_evt_itf evt_vdyn_itf = { - .broadcast = export_on_event_vdyn, - .push = export_on_event_vdyn -}; +int afb_export_event_handler_del( + struct afb_export *export, + const char *pattern, + void **closure) +{ + struct event_handler *handler, **previous; + + /* search the handler */ + previous = &export->event_handlers; + while ((handler = *previous) && strcasecmp(handler->pattern, pattern)) + previous = &handler->next; -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* + /* error if found */ + if (!handler) { + ERROR("[API %s] event handler %s already exists", export->api.apiname, pattern); + errno = ENOENT; + return -1; + } + + /* remove the found event */ + if (closure) + *closure = handler->closure; + + *previous = handler->next; + free(handler); + return 0; +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** M E R G E D - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, enum afb_api_version version) +static struct afb_export *create( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + enum afb_api_version version) { struct afb_export *export; @@ -1067,96 +1217,179 @@ static struct afb_export *create(struct afb_apiset *apiset, const char *apiname, if (common_session == NULL) return NULL; } - export = calloc(1, sizeof *export); + export = calloc(1, sizeof *export + strlen(apiname)); if (!export) errno = ENOMEM; else { - memset(export, 0, sizeof *export); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; + export->refcount = 1; + strcpy(export->name, apiname); + export->api.apiname = export->name; export->version = version; export->state = Api_State_Pre_Init; export->session = afb_session_addref(common_session); - export->apiset = afb_apiset_addref(apiset); + export->declare_set = afb_apiset_addref(declare_set); + export->call_set = afb_apiset_addref(call_set); } return export; } +struct afb_export *afb_export_addref(struct afb_export *export) +{ + if (export) + __atomic_add_fetch(&export->refcount, 1, __ATOMIC_RELAXED); + return export; +} + +void afb_export_unref(struct afb_export *export) +{ + if (export && !__atomic_sub_fetch(&export->refcount, 1, __ATOMIC_RELAXED)) + afb_export_destroy(export); +} + void afb_export_destroy(struct afb_export *export) { + struct event_handler *handler; + if (export) { + while ((handler = export->event_handlers)) { + export->event_handlers = handler->next; + free(handler); + } if (export->listener != NULL) afb_evt_listener_unref(export->listener); afb_session_unref(export->session); - afb_apiset_unref(export->apiset); - free(export->apiname); + afb_apiset_unref(export->declare_set); + afb_apiset_unref(export->call_set); + if (export->api.apiname != export->name) + free((void*)export->api.apiname); free(export); } } -struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)) +struct afb_export *afb_export_create_none_for_path( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *path, + int (*creator)(void*, struct afb_api_x3*), + void *closure) { - struct afb_export *export = create(apiset, apiname, Api_Version_1); + struct afb_export *export = create(declare_set, call_set, path, Api_Version_None); + if (export) { + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); + if (creator && creator(closure, to_api_x3(export)) < 0) { + afb_export_unref(export); + export = NULL; + } + } + return export; +} + +#if defined(WITH_LEGACY_BINDING_V1) +struct afb_export *afb_export_create_v1( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + int (*init)(struct afb_service_x1), + void (*onevent)(const char*, struct json_object*)) +{ + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_1); if (export) { export->init.v1 = init; - export->on_event.v12 = onevent; + export->on_any_event_v12 = onevent; export->export.v1.mode = AFB_MODE_LOCAL; - export->export.v1.daemon.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->export.v1.daemon.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } +#endif -struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)) +struct afb_export *afb_export_create_v2( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const struct afb_binding_v2 *binding, + struct afb_binding_data_v2 *data, + int (*init)(), + void (*onevent)(const char*, struct json_object*)) { - struct afb_export *export = create(apiset, apiname, Api_Version_2); + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_2); if (export) { export->init.v2 = init; - export->on_event.v12 = onevent; + export->on_any_event_v12 = onevent; + export->desc.v2 = binding; export->export.v2 = data; - data->daemon.closure = export; - data->service.closure = export; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + data->daemon.closure = to_api_x3(export); + data->service.closure = to_api_x3(export); + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } -struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *apidyn) +struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + struct afb_api_v3 *apiv3) { - struct afb_export *export = create(apiset, apiname, Api_Version_Dyn); + struct afb_export *export = create(declare_set, call_set, apiname, Api_Version_3); if (export) { - export->apidyn = apidyn; - afb_export_verbosity_set(export, verbosity); - afb_export_update_hook(export); + export->unsealed = 1; + export->desc.v3 = apiv3; + afb_export_logmask_set(export, logmask); + afb_export_update_hooks(export); } return export; } -void afb_export_rename(struct afb_export *export, const char *apiname) +int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname) +{ + return afb_apiset_add_alias(export->declare_set, apiname ?: export->api.apiname, aliasname); +} + +int afb_export_rename(struct afb_export *export, const char *apiname) { - free(export->apiname); - export->apiname = strdup(apiname); - export->dynapi.apiname = export->apiname; - afb_export_update_hook(export); + char *name; + + if (export->declared) { + errno = EBUSY; + return -1; + } + + /* copy the name locally */ + name = strdup(apiname); + if (!name) { + errno = ENOMEM; + return -1; + } + + if (export->api.apiname != export->name) + free((void*)export->api.apiname); + export->api.apiname = name; + + afb_export_update_hooks(export); + return 0; } const char *afb_export_apiname(const struct afb_export *export) { - return export->apiname; + return export->api.apiname; } -void afb_export_update_hook(struct afb_export *export) +void afb_export_update_hooks(struct afb_export *export) { - export->hookditf = afb_hook_flags_ditf(export->apiname); - export->hooksvc = afb_hook_flags_svc(export->apiname); - export->dynapi.itf = export->hookditf|export->hooksvc ? &hooked_dynapi_itf : &dynapi_itf; + export->hookditf = afb_hook_flags_api(export->api.apiname); + export->hooksvc = afb_hook_flags_api(export->api.apiname); + export->api.itf = export->hookditf|export->hooksvc ? &hooked_api_x3_itf : &api_x3_itf; switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: export->export.v1.daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; break; +#endif case Api_Version_2: export->export.v2->daemon.itf = export->hookditf ? &hooked_daemon_itf : &daemon_itf; export->export.v2->service.itf = export->hooksvc ? &hooked_service_itf : &service_itf; @@ -1164,11 +1397,6 @@ void afb_export_update_hook(struct afb_export *export) } } -struct afb_binding_interface_v1 *afb_export_get_interface_v1(struct afb_export *export) -{ - return export->version == Api_Version_1 ? &export->export.v1 : NULL; -} - int afb_export_unshare_session(struct afb_export *export) { if (export->session == common_session) { @@ -1183,126 +1411,107 @@ int afb_export_unshare_session(struct afb_export *export) return 0; } -void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset) -{ - struct afb_apiset *prvset = export->apiset; - export->apiset = afb_apiset_addref(apiset); - afb_apiset_unref(prvset); -} - -struct afb_apiset *afb_export_get_apiset(struct afb_export *export) -{ - return export->apiset; -} - int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)) { /* check version */ switch (export->version) { - case Api_Version_1: case Api_Version_2: break; +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: +#endif + case Api_Version_2: + break; default: - ERROR("invalid version 12 for API %s", export->apiname); + ERROR("invalid version 12 for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.v12 = on_event; - } else { - export->on_event.v12 = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_v12_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v12 = on_event; + return ensure_listener(export); } -int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)) +int afb_export_handle_events_v3(struct afb_export *export, void (*on_event)(struct afb_api_x3 *api, const char *event, struct json_object *object)) { /* check version */ switch (export->version) { - case Api_Version_Dyn: break; + case Api_Version_3: break; default: - ERROR("invalid version Dyn for API %s", export->apiname); + ERROR("invalid version Dyn for API %s", export->api.apiname); errno = EINVAL; return -1; } - /* set the event handler */ - if (!on_event) { - if (export->listener) { - afb_evt_listener_unref(export->listener); - export->listener = NULL; - } - export->on_event.vdyn = on_event; - } else { - export->on_event.vdyn = on_event; - if (!export->listener) { - export->listener = afb_evt_listener_create(&evt_vdyn_itf, export); - if (export->listener == NULL) - return -1; - } - } - return 0; + export->on_any_event_v3 = on_event; + return ensure_listener(export); } -int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)) +int afb_export_handle_init_v3(struct afb_export *export, int (*oninit)(struct afb_api_x3 *api)) { if (export->state != Api_State_Pre_Init) { - ERROR("[API %s] Bad call to 'afb_dynapi_on_init', must be in PreInit", export->apiname); + ERROR("[API %s] Bad call to 'afb_api_x3_on_init', must be in PreInit", export->api.apiname); errno = EINVAL; return -1; } - export->init.vdyn = oninit; + export->init.v3 = oninit; return 0; } +#if defined(WITH_LEGACY_BINDING_V1) /* * Starts a new service (v1) */ struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)) { - return regfun(&export->export.v1); + return export->desc.v1 = regfun(&export->export.v1); } +#endif -int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure) +int afb_export_preinit_x3( + struct afb_export *export, + int (*preinit)(void*, struct afb_api_x3*), + void *closure) { - return preinit(closure, to_dynapi(export)); + return preinit(closure, to_api_x3(export)); } -int afb_export_verbosity_get(const struct afb_export *export) +int afb_export_logmask_get(const struct afb_export *export) { - return export->dynapi.verbosity; + return export->api.logmask; } -void afb_export_verbosity_set(struct afb_export *export, int level) +void afb_export_logmask_set(struct afb_export *export, int mask) { - export->dynapi.verbosity = level; + export->api.logmask = mask; switch (export->version) { - case Api_Version_1: export->export.v1.verbosity = level; break; - case Api_Version_2: export->export.v2->verbosity = level; break; +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: export->export.v1.verbosity = verbosity_from_mask(mask); break; +#endif + case Api_Version_2: export->export.v2->verbosity = verbosity_from_mask(mask); break; } } -/************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* +void *afb_export_userdata_get(const struct afb_export *export) +{ + return export->api.userdata; +} + +void afb_export_userdata_set(struct afb_export *export, void *data) +{ + export->api.userdata = data; +} + +/****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** N E W - ************************************************************************************************************* - ************************************************************************************************************* - ************************************************************************************************************* - *************************************************************************************************************/ + ****************************************************************************** + ****************************************************************************** + ****************************************************************************** + ******************************************************************************/ -int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset) +int afb_export_start(struct afb_export *export, int share_session, int onneed) { int rc; @@ -1313,7 +1522,7 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s goto done; /* already started: it is an error */ - ERROR("Service of API %s already started", export->apiname); + ERROR("Service of API %s already started", export->api.apiname); return -1; } @@ -1321,49 +1530,59 @@ int afb_export_start(struct afb_export *export, int share_session, int onneed, s if (!share_session) { rc = afb_export_unshare_session(export); if (rc < 0) { - ERROR("Can't unshare the session for %s", export->apiname); + ERROR("Can't unshare the session for %s", export->api.apiname); return -1; } } /* set event handling */ switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: +#endif case Api_Version_2: - rc = afb_export_handle_events_v12(export, export->on_event.v12); + if (export->on_any_event_v12) + rc = afb_export_handle_events_v12(export, export->on_any_event_v12); break; default: rc = 0; break; } if (rc < 0) { - ERROR("Can't set event handler for %s", export->apiname); + ERROR("Can't set event handler for %s", export->api.apiname); return -1; } /* Starts the service */ - if (export->hooksvc & afb_hook_flag_svc_start_before) - afb_hook_svc_start_before(export); + if (export->hooksvc & afb_hook_flag_api_start) + afb_hook_api_start_before(export); + export->state = Api_State_Init; switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) case Api_Version_1: - rc = export->init.v1 ? export->init.v1((struct afb_service){ .itf = &hooked_service_itf, .closure = export }) : 0; + rc = export->init.v1 ? export->init.v1((struct afb_service_x1){ .itf = &hooked_service_itf, .closure = to_api_x3(export) }) : 0; break; +#endif case Api_Version_2: rc = export->init.v2 ? export->init.v2() : 0; break; - case Api_Version_Dyn: - rc = export->init.vdyn ? export->init.vdyn(to_dynapi(export)) : 0; + case Api_Version_3: + rc = export->init.v3 ? export->init.v3(to_api_x3(export)) : 0; break; default: + errno = EINVAL; + rc = -1; break; } export->state = Api_State_Run; - if (export->hooksvc & afb_hook_flag_svc_start_after) - afb_hook_svc_start_after(export, rc); + + if (export->hooksvc & afb_hook_flag_api_start) + afb_hook_api_start_after(export, rc); + if (rc < 0) { /* initialisation error */ - ERROR("Initialisation of service API %s failed (%d): %m", export->apiname, rc); + ERROR("Initialisation of service API %s failed (%d): %m", export->api.apiname, rc); return rc; } @@ -1371,3 +1590,154 @@ done: return 0; } +static void api_call_cb(void *closure, struct afb_xreq *xreq) +{ + struct afb_export *export = closure; + + xreq->request.api = to_api_x3(export); + + switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: + afb_api_so_v1_process_call(export->desc.v1, xreq); + break; +#endif + case Api_Version_2: + afb_api_so_v2_process_call(export->desc.v2, xreq); + break; + case Api_Version_3: + afb_api_v3_process_call(export->desc.v3, xreq); + break; + default: + afb_xreq_reply(xreq, NULL, "bad-api-type", NULL); + break; + } +} + +static struct json_object *api_describe_cb(void *closure) +{ + struct afb_export *export = closure; + struct json_object *result; + + switch (export->version) { +#if defined(WITH_LEGACY_BINDING_V1) + case Api_Version_1: + result = afb_api_so_v1_make_description_openAPIv3(export->desc.v1, export->api.apiname); + break; +#endif + case Api_Version_2: + result = afb_api_so_v2_make_description_openAPIv3(export->desc.v2, export->api.apiname); + break; + case Api_Version_3: + result = afb_api_v3_make_description_openAPIv3(export->desc.v3, export->api.apiname); + break; + default: + result = NULL; + break; + } + return result; +} + +static int api_service_start_cb(void *closure, int share_session, int onneed) +{ + struct afb_export *export = closure; + + return afb_export_start(export, share_session, onneed); +} + +static void api_update_hooks_cb(void *closure) +{ + struct afb_export *export = closure; + + afb_export_update_hooks(export); +} + +static int api_get_logmask_cb(void *closure) +{ + struct afb_export *export = closure; + + return afb_export_logmask_get(export); +} + +static void api_set_logmask_cb(void *closure, int level) +{ + struct afb_export *export = closure; + + afb_export_logmask_set(export, level); +} + +static void api_unref_cb(void *closure) +{ + struct afb_export *export = closure; + + afb_export_unref(export); +} + +static struct afb_api_itf export_api_itf = +{ + .call = api_call_cb, + .service_start = api_service_start_cb, + .update_hooks = api_update_hooks_cb, + .get_logmask = api_get_logmask_cb, + .set_logmask = api_set_logmask_cb, + .describe = api_describe_cb, + .unref = api_unref_cb +}; + +int afb_export_declare(struct afb_export *export, + int noconcurrency) +{ + int rc; + struct afb_api_item afb_api; + + if (export->declared) + rc = 0; + else { + /* init the record structure */ + afb_api.closure = afb_export_addref(export); + afb_api.itf = &export_api_itf; + afb_api.group = noconcurrency ? export : NULL; + + /* records the binding */ + rc = afb_apiset_add(export->declare_set, export->api.apiname, afb_api); + if (rc >= 0) + export->declared = 1; + else { + ERROR("can't declare export %s to set %s, ABORTING it!", + export->api.apiname, + afb_apiset_name(export->declare_set)); + afb_export_addref(export); + } + } + + return rc; +} + +void afb_export_undeclare(struct afb_export *export) +{ + if (export->declared) { + export->declared = 0; + afb_apiset_del(export->declare_set, export->api.apiname); + } +} + +int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event) +{ + return afb_evt_event_x2_add_watch(export->listener, event); +} + +int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event) +{ + return afb_evt_event_x2_remove_watch(export->listener, event); +} + +void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq) +{ + afb_xreq_process(xreq, export->call_set); +} + +void afb_export_context_init(struct afb_export *export, struct afb_context *context) +{ + afb_context_init(context, export->session, NULL); +} + diff --git a/src/afb-export.h b/src/afb-export.h index 5acca207..c9046be8 100644 --- a/src/afb-export.h +++ b/src/afb-export.h @@ -21,36 +21,111 @@ struct json_object; struct afb_export; struct afb_apiset; -struct afb_api_dyn; +struct afb_context; +struct afb_xreq; -struct afb_service; +struct afb_binding_v2; struct afb_binding_data_v2; -struct afb_binding_interface_v1; -struct afb_dynapi; +struct afb_api_v3; +struct afb_api_x3; +struct afb_event_x2; + +extern struct afb_export *afb_export_create_none_for_path( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *path, + int (*creator)(void*, struct afb_api_x3*), + void *closure); + +extern struct afb_export *afb_export_create_v2( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + const struct afb_binding_v2 *binding, + struct afb_binding_data_v2 *data, + int (*init)(), + void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_v1(struct afb_apiset *apiset, const char *apiname, int (*init)(struct afb_service), void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_v2(struct afb_apiset *apiset, const char *apiname, struct afb_binding_data_v2 *data, int (*init)(), void (*onevent)(const char*, struct json_object*)); -extern struct afb_export *afb_export_create_vdyn(struct afb_apiset *apiset, const char *apiname, struct afb_api_dyn *dynapi); +extern struct afb_export *afb_export_create_v3(struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + struct afb_api_v3 *api); + +extern struct afb_export *afb_export_addref(struct afb_export *export); +extern void afb_export_unref(struct afb_export *export); extern void afb_export_destroy(struct afb_export *export); +extern int afb_export_declare(struct afb_export *export, int noconcurrency); +extern void afb_export_undeclare(struct afb_export *export); + extern const char *afb_export_apiname(const struct afb_export *export); -extern void afb_export_rename(struct afb_export *export, const char *apiname); -extern void afb_export_update_hook(struct afb_export *export); +extern int afb_export_add_alias(struct afb_export *export, const char *apiname, const char *aliasname); +extern int afb_export_rename(struct afb_export *export, const char *apiname); +extern void afb_export_update_hooks(struct afb_export *export); extern int afb_export_unshare_session(struct afb_export *export); -extern void afb_export_set_apiset(struct afb_export *export, struct afb_apiset *apiset); -extern struct afb_apiset *afb_export_get_apiset(struct afb_export *export); - -extern struct afb_binding_v1 *afb_export_register_v1(struct afb_export *export, struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)); -extern int afb_export_preinit_vdyn(struct afb_export *export, int (*preinit)(void*, struct afb_dynapi*), void *closure); -extern int afb_export_handle_events_v12(struct afb_export *export, void (*on_event)(const char *event, struct json_object *object)); -extern int afb_export_handle_events_vdyn(struct afb_export *export, void (*on_event)(struct afb_dynapi *dynapi, const char *event, struct json_object *object)); -extern int afb_export_handle_init_vdyn(struct afb_export *export, int (*oninit)(struct afb_dynapi *dynapi)); +extern int afb_export_preinit_x3( + struct afb_export *export, + int (*preinit)(void *,struct afb_api_x3*), + void *closure); + +extern int afb_export_handle_events_v12( + struct afb_export *export, + void (*on_event)(const char *event, struct json_object *object)); + + +extern int afb_export_handle_events_v3( + struct afb_export *export, + void (*on_event)(struct afb_api_x3 *api, const char *event, struct json_object *object)); + + +extern int afb_export_handle_init_v3( + struct afb_export *export, + int (*oninit)(struct afb_api_x3 *api)); + +extern int afb_export_start(struct afb_export *export, int share_session, int onneed); + +extern int afb_export_logmask_get(const struct afb_export *export); +extern void afb_export_logmask_set(struct afb_export *export, int mask); + +extern void *afb_export_userdata_get(const struct afb_export *export); +extern void afb_export_userdata_set(struct afb_export *export, void *data); + +extern int afb_export_event_handler_add( + struct afb_export *export, + const char *pattern, + void (*callback)(void *, const char*, struct json_object*, struct afb_api_x3*), + void *closure); + +extern int afb_export_event_handler_del( + struct afb_export *export, + const char *pattern, + void **closure); + +extern int afb_export_subscribe(struct afb_export *export, struct afb_event_x2 *event); +extern int afb_export_unsubscribe(struct afb_export *export, struct afb_event_x2 *event); +extern void afb_export_process_xreq(struct afb_export *export, struct afb_xreq *xreq); +extern void afb_export_context_init(struct afb_export *export, struct afb_context *context); +extern struct afb_export *afb_export_from_api_x3(struct afb_api_x3 *api); +extern struct afb_api_x3 *afb_export_to_api_x3(struct afb_export *export); + +#if defined(WITH_LEGACY_BINDING_V1) + +struct afb_service_x1; +struct afb_binding_interface_v1; + +extern struct afb_export *afb_export_create_v1( + struct afb_apiset *declare_set, + struct afb_apiset *call_set, + const char *apiname, + int (*init)(struct afb_service_x1), + void (*onevent)(const char*, struct json_object*)); -extern int afb_export_start(struct afb_export *export, int share_session, int onneed, struct afb_apiset *apiset); +extern struct afb_binding_v1 *afb_export_register_v1( + struct afb_export *export, + struct afb_binding_v1 *(*regfun)(const struct afb_binding_interface_v1*)); -extern int afb_export_verbosity_get(const struct afb_export *export); -extern void afb_export_verbosity_set(struct afb_export *export, int level); +#endif diff --git a/src/afb-hook.c b/src/afb-hook.c index f5868b18..75e8a691 100644 --- a/src/afb-hook.c +++ b/src/afb-hook.c @@ -27,8 +27,8 @@ #include <json-c/json.h> -#include <afb/afb-req.h> -#include <afb/afb-event.h> +#include <afb/afb-req-x1.h> +#include <afb/afb-event-x2.h> #include "afb-context.h" #include "afb-hook.h" @@ -38,10 +38,19 @@ #include "afb-export.h" #include "afb-evt.h" #include "afb-api.h" +#include "afb-msg-json.h" #include "verbose.h" #include <fnmatch.h> -#define MATCH(pattern,string) (!fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH)) +#define MATCH(pattern,string) (\ + pattern \ + ? !fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH|FNM_PERIOD) \ + : (string)[0] != '.') + +#define MATCH_API(pattern,string) MATCH(pattern,string) +#define MATCH_VERB(pattern,string) MATCH(pattern,string) +#define MATCH_EVENT(pattern,string) MATCH(pattern,string) +#define MATCH_SESSION(pattern,string) MATCH(pattern,string) /** * Definition of a hook for xreq @@ -60,24 +69,12 @@ struct afb_hook_xreq { /** * Definition of a hook for export */ -struct afb_hook_ditf { - struct afb_hook_ditf *next; /**< next hook */ +struct afb_hook_api { + struct afb_hook_api *next; /**< next hook */ unsigned refcount; /**< reference count */ unsigned flags; /**< hook flags */ char *api; /**< api hooked or NULL for any */ - struct afb_hook_ditf_itf *itf; /**< interface of hook */ - void *closure; /**< closure for callbacks */ -}; - -/** - * Definition of a hook for export - */ -struct afb_hook_svc { - struct afb_hook_svc *next; /**< next hook */ - unsigned refcount; /**< reference count */ - unsigned flags; /**< hook flags */ - char *api; /**< api hooked or NULL for any */ - struct afb_hook_svc_itf *itf; /**< interface of hook */ + struct afb_hook_api_itf *itf; /**< interface of hook */ void *closure; /**< closure for callbacks */ }; @@ -123,10 +120,7 @@ static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; static struct afb_hook_xreq *list_of_xreq_hooks = NULL; /* list of hooks for export */ -static struct afb_hook_ditf *list_of_ditf_hooks = NULL; - -/* list of hooks for export */ -static struct afb_hook_svc *list_of_svc_hooks = NULL; +static struct afb_hook_api *list_of_api_hooks = NULL; /* list of hooks for evt */ static struct afb_hook_evt *list_of_evt_hooks = NULL; @@ -225,11 +219,11 @@ static void _hook_xreq_(const struct afb_xreq *xreq, const char *format, ...) { va_list ap; va_start(ap, format); - _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.api, xreq->request.verb); + _hook_("xreq-%06d:%s/%s", format, ap, xreq->hookindex, xreq->request.called_api, xreq->request.called_verb); va_end(ap); } -static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_begin_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { if (!xreq->cred) _hook_xreq_(xreq, "BEGIN"); @@ -244,92 +238,87 @@ static void hook_xreq_begin_default_cb(void *closure, const struct afb_hookid *h ); } -static void hook_xreq_end_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_end_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "END"); } -static void hook_xreq_json_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj) +static void hook_xreq_json_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj) { _hook_xreq_(xreq, "json() -> %s", json_object_to_json_string(obj)); } -static void hook_xreq_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg) +static void hook_xreq_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg) { _hook_xreq_(xreq, "get(%s) -> { name: %s, value: %s, path: %s }", name, arg.name, arg.value, arg.path); } -static void hook_xreq_success_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info) -{ - _hook_xreq_(xreq, "success(%s, %s)", json_object_to_json_string(obj), info); -} - -static void hook_xreq_fail_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info) +static void hook_xreq_reply_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - _hook_xreq_(xreq, "fail(%s, %s)", status, info); + _hook_xreq_(xreq, "reply[%s](%s, %s)", error?:"success", json_object_to_json_string(obj), info); } -static void hook_xreq_context_get_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value) +static void hook_xreq_legacy_context_get_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value) { _hook_xreq_(xreq, "context_get() -> %p", value); } -static void hook_xreq_context_set_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) +static void hook_xreq_legacy_context_set_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) { _hook_xreq_(xreq, "context_set(%p, %p)", value, free_value); } -static void hook_xreq_addref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_addref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "addref()"); } -static void hook_xreq_unref_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_unref_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "unref()"); } -static void hook_xreq_session_close_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_session_close_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "session_close()"); } -static void hook_xreq_session_set_LOA_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result) +static void hook_xreq_session_set_LOA_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result) { _hook_xreq_(xreq, "session_set_LOA(%u) -> %d", level, result); } -static void hook_xreq_subscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_subscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result); + _hook_xreq_(xreq, "subscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result); } -static void hook_xreq_unsubscribe_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_unsubscribe_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), result); + _hook_xreq_(xreq, "unsubscribe(%s:%d) -> %d", afb_evt_event_x2_fullname(event_x2), afb_evt_event_x2_id(event_x2), result); } -static void hook_xreq_subcall_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +static void hook_xreq_subcall_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) { _hook_xreq_(xreq, "subcall(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); } -static void hook_xreq_subcall_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcall_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - _hook_xreq_(xreq, " ...subcall... -> %d: %s", status, json_object_to_json_string(result)); + _hook_xreq_(xreq, " ...subcall... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:""); } -static void hook_xreq_subcallsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +static void hook_xreq_subcallsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) { _hook_xreq_(xreq, "subcallsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); } -static void hook_xreq_subcallsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcallsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - _hook_xreq_(xreq, " ...subcallsync... -> %d: %s", status, json_object_to_json_string(result)); + _hook_xreq_(xreq, " ...subcallsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:""); } -static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void hook_xreq_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { int len; char *msg; @@ -340,105 +329,99 @@ static void hook_xreq_vverbose_default_cb(void *closure, const struct afb_hookid va_end(ap); if (len < 0) - _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt); + _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt); else { - _hook_xreq_(xreq, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg); + _hook_xreq_(xreq, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg); free(msg); } } -static void hook_xreq_store_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq) +static void hook_xreq_legacy_store_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq) { _hook_xreq_(xreq, "store() -> %p", sreq); } -static void hook_xreq_unstore_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) +static void hook_xreq_legacy_unstore_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { _hook_xreq_(xreq, "unstore()"); } -static void hook_xreq_subcall_req_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) -{ - _hook_xreq_(xreq, "subcall_req(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); -} - -static void hook_xreq_subcall_req_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) -{ - _hook_xreq_(xreq, " ...subcall_req... -> %d: %s", status, json_object_to_json_string(result)); -} - -static void hook_xreq_has_permission_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) +static void hook_xreq_has_permission_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) { _hook_xreq_(xreq, "has_permission(%s) -> %d", permission, result); } -static void hook_xreq_get_application_id_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result) +static void hook_xreq_get_application_id_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result) { _hook_xreq_(xreq, "get_application_id() -> %s", result); } -static void hook_xreq_context_make_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result) +static void hook_xreq_context_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result) { _hook_xreq_(xreq, "context_make(replace=%s, %p, %p, %p) -> %p", replace?"yes":"no", create_value, free_value, create_closure, result); } -static void hook_xreq_get_uid_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result) +static void hook_xreq_get_uid_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result) { _hook_xreq_(xreq, "get_uid() -> %d", result); } +static void hook_xreq_get_client_info_cb(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result) +{ + _hook_xreq_(xreq, "get_client_info() -> %s", json_object_to_json_string(result)); +} + static struct afb_hook_xreq_itf hook_xreq_default_itf = { - .hook_xreq_begin = hook_xreq_begin_default_cb, - .hook_xreq_end = hook_xreq_end_default_cb, - .hook_xreq_json = hook_xreq_json_default_cb, - .hook_xreq_get = hook_xreq_get_default_cb, - .hook_xreq_success = hook_xreq_success_default_cb, - .hook_xreq_fail = hook_xreq_fail_default_cb, - .hook_xreq_context_get = hook_xreq_context_get_default_cb, - .hook_xreq_context_set = hook_xreq_context_set_default_cb, - .hook_xreq_addref = hook_xreq_addref_default_cb, - .hook_xreq_unref = hook_xreq_unref_default_cb, - .hook_xreq_session_close = hook_xreq_session_close_default_cb, - .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_default_cb, - .hook_xreq_subscribe = hook_xreq_subscribe_default_cb, - .hook_xreq_unsubscribe = hook_xreq_unsubscribe_default_cb, - .hook_xreq_subcall = hook_xreq_subcall_default_cb, - .hook_xreq_subcall_result = hook_xreq_subcall_result_default_cb, - .hook_xreq_subcallsync = hook_xreq_subcallsync_default_cb, - .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_default_cb, - .hook_xreq_vverbose = hook_xreq_vverbose_default_cb, - .hook_xreq_store = hook_xreq_store_default_cb, - .hook_xreq_unstore = hook_xreq_unstore_default_cb, - .hook_xreq_subcall_req = hook_xreq_subcall_req_default_cb, - .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result_default_cb, - .hook_xreq_has_permission = hook_xreq_has_permission_default_cb, - .hook_xreq_get_application_id = hook_xreq_get_application_id_default_cb, - .hook_xreq_context_make = hook_xreq_context_make_default_cb, - .hook_xreq_get_uid = hook_xreq_get_uid_default_cb, + .hook_xreq_begin = hook_xreq_begin_cb, + .hook_xreq_end = hook_xreq_end_cb, + .hook_xreq_json = hook_xreq_json_cb, + .hook_xreq_get = hook_xreq_get_cb, + .hook_xreq_reply = hook_xreq_reply_cb, + .hook_xreq_legacy_context_get = hook_xreq_legacy_context_get_cb, + .hook_xreq_legacy_context_set = hook_xreq_legacy_context_set_cb, + .hook_xreq_addref = hook_xreq_addref_cb, + .hook_xreq_unref = hook_xreq_unref_cb, + .hook_xreq_session_close = hook_xreq_session_close_cb, + .hook_xreq_session_set_LOA = hook_xreq_session_set_LOA_cb, + .hook_xreq_subscribe = hook_xreq_subscribe_cb, + .hook_xreq_unsubscribe = hook_xreq_unsubscribe_cb, + .hook_xreq_subcall = hook_xreq_subcall_cb, + .hook_xreq_subcall_result = hook_xreq_subcall_result_cb, + .hook_xreq_subcallsync = hook_xreq_subcallsync_cb, + .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result_cb, + .hook_xreq_vverbose = hook_xreq_vverbose_cb, + .hook_xreq_legacy_store = hook_xreq_legacy_store_cb, + .hook_xreq_legacy_unstore = hook_xreq_legacy_unstore_cb, + .hook_xreq_has_permission = hook_xreq_has_permission_cb, + .hook_xreq_get_application_id = hook_xreq_get_application_id_cb, + .hook_xreq_context_make = hook_xreq_context_make_cb, + .hook_xreq_get_uid = hook_xreq_get_uid_cb, + .hook_xreq_get_client_info = hook_xreq_get_client_info_cb, }; /****************************************************************************** * section: hooks for tracing requests *****************************************************************************/ -#define _HOOK_XREQ_(what,...) \ +#define _HOOK_XREQ_2_(flag,func,...) \ struct afb_hook_xreq *hook; \ struct afb_hookid hookid; \ pthread_rwlock_rdlock(&rwlock); \ init_hookid(&hookid); \ hook = list_of_xreq_hooks; \ while (hook) { \ - if (hook->itf->hook_xreq_##what \ - && (hook->flags & afb_hook_flag_req_##what) != 0 \ + if (hook->itf->hook_xreq_##func \ + && (hook->flags & afb_hook_flag_req_##flag) != 0 \ && (!hook->session || hook->session == xreq->context.session) \ - && (!hook->api || !strcasecmp(hook->api, xreq->request.api)) \ - && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb))) { \ - hook->itf->hook_xreq_##what(hook->closure, &hookid, __VA_ARGS__); \ + && MATCH_API(hook->api, xreq->request.called_api) \ + && MATCH_VERB(hook->verb, xreq->request.called_verb)) { \ + hook->itf->hook_xreq_##func(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ } \ pthread_rwlock_unlock(&rwlock); +#define _HOOK_XREQ_(what,...) _HOOK_XREQ_2_(what,what,__VA_ARGS__) void afb_hook_xreq_begin(const struct afb_xreq *xreq) { @@ -462,25 +445,20 @@ struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, return arg; } -void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info) +void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - _HOOK_XREQ_(success, xreq, obj, info); + _HOOK_XREQ_(reply, xreq, obj, error, info); } -void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info) +void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value) { - _HOOK_XREQ_(fail, xreq, status, info); -} - -void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value) -{ - _HOOK_XREQ_(context_get, xreq, value); + _HOOK_XREQ_(legacy_context_get, xreq, value); return value; } -void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) +void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)) { - _HOOK_XREQ_(context_set, xreq, value, free_value); + _HOOK_XREQ_(legacy_context_set, xreq, value, free_value); } void afb_hook_xreq_addref(const struct afb_xreq *xreq) @@ -504,36 +482,36 @@ int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, i return result; } -int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _HOOK_XREQ_(subscribe, xreq, eventid, result); + _HOOK_XREQ_(subscribe, xreq, event_x2, result); return result; } -int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result) { - _HOOK_XREQ_(unsubscribe, xreq, eventid, result); + _HOOK_XREQ_(unsubscribe, xreq, event_x2, result); return result; } -void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags) { _HOOK_XREQ_(subcall, xreq, api, verb, args); } -void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result) +void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - _HOOK_XREQ_(subcall_result, xreq, status, result); + _HOOK_XREQ_(subcall_result, xreq, object, error, info); } -void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags) { _HOOK_XREQ_(subcallsync, xreq, api, verb, args); } -int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result) +int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - _HOOK_XREQ_(subcallsync_result, xreq, status, result); + _HOOK_XREQ_(subcallsync_result, xreq, status, object, error, info); return status; } @@ -542,24 +520,14 @@ void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char * _HOOK_XREQ_(vverbose, xreq, level, file ?: "?", line, func ?: "?", fmt, args); } -void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq) -{ - _HOOK_XREQ_(store, xreq, sreq); -} - -void afb_hook_xreq_unstore(const struct afb_xreq *xreq) -{ - _HOOK_XREQ_(unstore, xreq); -} - -void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) +void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq) { - _HOOK_XREQ_(subcall_req, xreq, api, verb, args); + _HOOK_XREQ_(legacy_store, xreq, sreq); } -void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result) +void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq) { - _HOOK_XREQ_(subcall_req_result, xreq, status, result); + _HOOK_XREQ_(legacy_unstore, xreq); } int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result) @@ -586,6 +554,12 @@ int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result) return result; } +struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result) +{ + _HOOK_XREQ_(get_client_info, xreq, result); + return result; +} + /****************************************************************************** * section: hooking xreqs *****************************************************************************/ @@ -600,21 +574,19 @@ void afb_hook_init_xreq(struct afb_xreq *xreq) /* scan hook list to get the expected flags */ flags = 0; - if (afb_api_is_hookable(xreq->request.api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_xreq_hooks; - while (hook) { - f = hook->flags & afb_hook_flags_req_all; - add = f != 0 - && (!hook->session || hook->session == xreq->context.session) - && (!hook->api || !strcasecmp(hook->api, xreq->request.api)) - && (!hook->verb || !strcasecmp(hook->verb, xreq->request.verb)); - if (add) - flags |= f; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_xreq_hooks; + while (hook) { + f = hook->flags & afb_hook_flags_req_all; + add = f != 0 + && (!hook->session || hook->session == xreq->context.session) + && MATCH_API(hook->api, xreq->request.called_api) + && MATCH_VERB(hook->verb, xreq->request.called_verb); + if (add) + flags |= f; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); /* store the hooking data */ xreq->hookflags = flags; @@ -705,40 +677,40 @@ void afb_hook_unref_xreq(struct afb_hook_xreq *hook) * section: default callbacks for tracing daemon interface *****************************************************************************/ -static void _hook_ditf_(const struct afb_export *export, const char *format, ...) +static void _hook_api_(const struct afb_export *export, const char *format, ...) { va_list ap; va_start(ap, format); - _hook_("export-%s", format, ap, afb_export_apiname(export)); + _hook_("api-%s", format, ap, afb_export_apiname(export)); va_end(ap); } -static void hook_ditf_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) +static void hook_api_event_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) { - _hook_ditf_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object)); + _hook_api_(export, "event_broadcast.before(%s, %s)....", name, json_object_to_json_string(object)); } -static void hook_ditf_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) +static void hook_api_event_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) { - _hook_ditf_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result); + _hook_api_(export, "event_broadcast.after(%s, %s) -> %d", name, json_object_to_json_string(object), result); } -static void hook_ditf_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) +static void hook_api_get_event_loop_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) { - _hook_ditf_(export, "get_event_loop() -> %p", result); + _hook_api_(export, "get_event_loop() -> %p", result); } -static void hook_ditf_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_user_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - _hook_ditf_(export, "get_user_bus() -> %p", result); + _hook_api_(export, "get_user_bus() -> %p", result); } -static void hook_ditf_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_system_bus_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - _hook_ditf_(export, "get_system_bus() -> %p", result); + _hook_api_(export, "get_system_bus() -> %p", result); } -static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hook_api_vverbose_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { int len; char *msg; @@ -749,427 +721,489 @@ static void hook_ditf_vverbose_cb(void *closure, const struct afb_hookid *hookid va_end(ap); if (len < 0) - _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, function, fmt); + _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, function, fmt); else { - _hook_ditf_(export, "vverbose(%d, %s, %d, %s) -> %s", level, file, line, function, msg); + _hook_api_(export, "vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, function, msg); free(msg); } } -static void hook_ditf_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result) +static void hook_api_event_make_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - _hook_ditf_(export, "event_make(%s) -> %s:%d", name, afb_evt_eventid_fullname(result), afb_evt_eventid_id(result)); + _hook_api_(export, "event_make(%s) -> %s:%d", name, afb_evt_event_x2_fullname(result), afb_evt_event_x2_id(result)); } -static void hook_ditf_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +static void hook_api_rootdir_get_fd_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { char path[PATH_MAX]; if (result < 0) - _hook_ditf_(export, "rootdir_get_fd() -> %d, %m", result); + _hook_api_(export, "rootdir_get_fd() -> %d, %m", result); else { sprintf(path, "/proc/self/fd/%d", result); readlink(path, path, sizeof path); - _hook_ditf_(export, "rootdir_get_fd() -> %d = %s", result, path); + _hook_api_(export, "rootdir_get_fd() -> %d = %s", result, path); } } -static void hook_ditf_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +static void hook_api_rootdir_open_locale_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { char path[PATH_MAX]; if (!locale) locale = "(null)"; if (result < 0) - _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result); + _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d, %m", filename, flags, locale, result); else { sprintf(path, "/proc/self/fd/%d", result); readlink(path, path, sizeof path); - _hook_ditf_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path); + _hook_api_(export, "rootdir_open_locale(%s, %d, %s) -> %d = %s", filename, flags, locale, result, path); } } -static void hook_ditf_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +static void hook_api_queue_job_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +{ + _hook_api_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result); +} + +static void hook_api_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +{ + _hook_api_(export, "unstore_req(%p)", sreq); +} + +static void hook_api_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +{ + _hook_api_(export, "require_api(%s, %d)...", name, initialized); +} + +static void hook_api_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +{ + _hook_api_(export, "...require_api(%s, %d) -> %d", name, initialized, result); +} + +static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result) +{ + _hook_api_(export, "add_alias(%s -> %s) -> %d", api, alias?:"<null>", result); +} + +static void hook_api_start_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + _hook_api_(export, "start.before"); +} + +static void hook_api_start_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +{ + _hook_api_(export, "start.after -> %d", status); +} + +static void hook_api_on_event_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _hook_api_(export, "on_event.before(%s, %d, %s)", event, event_x2, json_object_to_json_string(object)); +} + +static void hook_api_on_event_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _hook_api_(export, "on_event.after(%s, %d, %s)", event, event_x2, json_object_to_json_string(object)); +} + +static void hook_api_call_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + _hook_api_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); +} + +static void hook_api_call_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info) +{ + _hook_api_(export, " ...call... [%s] -> %s (%s)", error?:"success", json_object_to_json_string(object), info?:""); +} + +static void hook_api_callsync_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + _hook_api_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); +} + +static void hook_api_callsync_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) +{ + _hook_api_(export, " ...callsync... %d [%s] -> %s (%s)", status, error?:"success", json_object_to_json_string(object), info?:""); +} + +static void hook_api_new_api_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency) +{ + _hook_api_(export, "new_api.before %s (%s)%s ...", api, info?:"", noconcurrency?" no-concurrency" : ""); +} + +static void hook_api_new_api_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api) +{ + _hook_api_(export, "... new_api.after %s -> %s (%d)", api, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_verbs_v2_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) +{ + _hook_api_(export, "set_verbs_v2 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_verbs_v3_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) +{ + _hook_api_(export, "set_verbs_v3 -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_add_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob) +{ + _hook_api_(export, "add_verb(%s%s [%s]) -> %s (%d)", verb, glob?" (GLOB)":"", info?:"", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_del_verb_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb) +{ + _hook_api_(export, "del_verb(%s) -> %s (%d)", verb, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_on_event_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + _hook_api_(export, "set_on_event -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_set_on_init_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + _hook_api_(export, "set_on_init -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_api_seal_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + _hook_api_(export, "seal"); +} + +static void hook_api_event_handler_add_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + _hook_api_(export, "event_handler_add(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_event_handler_del_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + _hook_api_(export, "event_handler_del(%s) -> %s (%d)", pattern, result >= 0 ? "OK" : "ERROR", result); +} + +static void hook_api_class_provide_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) { - _hook_ditf_(export, "queue_job(%p, %p, %p, %d) -> %d", callback, argument, group, timeout, result); + _hook_api_(export, "class_provide(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_unstore_req_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +static void hook_api_class_require_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) { - _hook_ditf_(export, "unstore_req(%p)", sreq); + _hook_api_(export, "class_require(%s) -> %s (%d)", name, result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_require_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +static void hook_api_delete_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { - _hook_ditf_(export, "require_api(%s, %d)...", name, initialized); + _hook_api_(export, "delete_api -> %s (%d)", result >= 0 ? "OK" : "ERROR", result); } -static void hook_ditf_require_api_result_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +static void hook_api_on_event_handler_before_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _hook_ditf_(export, "...require_api(%s, %d) -> %d", name, initialized, result); + _hook_api_(export, "on_event_handler[%s].before(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object)); } -static void hook_ditf_rename_api_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result) +static void hook_api_on_event_handler_after_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _hook_ditf_(export, "rename_api(%s -> %s) -> %d", oldname, newname, result); + _hook_api_(export, "on_event_handler[%s].after(%s, %d, %s)", pattern, event, event_x2, json_object_to_json_string(object)); } -static struct afb_hook_ditf_itf hook_ditf_default_itf = { - .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before_cb, - .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after_cb, - .hook_ditf_get_event_loop = hook_ditf_get_event_loop_cb, - .hook_ditf_get_user_bus = hook_ditf_get_user_bus_cb, - .hook_ditf_get_system_bus = hook_ditf_get_system_bus_cb, - .hook_ditf_vverbose = hook_ditf_vverbose_cb, - .hook_ditf_event_make = hook_ditf_event_make_cb, - .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd_cb, - .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale_cb, - .hook_ditf_queue_job = hook_ditf_queue_job_cb, - .hook_ditf_unstore_req = hook_ditf_unstore_req_cb, - .hook_ditf_require_api = hook_ditf_require_api_cb, - .hook_ditf_require_api_result = hook_ditf_require_api_result_cb, - .hook_ditf_rename_api = hook_ditf_rename_api_cb +static struct afb_hook_api_itf hook_api_default_itf = { + .hook_api_event_broadcast_before = hook_api_event_broadcast_before_cb, + .hook_api_event_broadcast_after = hook_api_event_broadcast_after_cb, + .hook_api_get_event_loop = hook_api_get_event_loop_cb, + .hook_api_get_user_bus = hook_api_get_user_bus_cb, + .hook_api_get_system_bus = hook_api_get_system_bus_cb, + .hook_api_vverbose = hook_api_vverbose_cb, + .hook_api_event_make = hook_api_event_make_cb, + .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd_cb, + .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale_cb, + .hook_api_queue_job = hook_api_queue_job_cb, + .hook_api_legacy_unstore_req = hook_api_unstore_req_cb, + .hook_api_require_api = hook_api_require_api_cb, + .hook_api_require_api_result = hook_api_require_api_result_cb, + .hook_api_add_alias = hook_api_add_alias_cb, + .hook_api_start_before = hook_api_start_before_cb, + .hook_api_start_after = hook_api_start_after_cb, + .hook_api_on_event_before = hook_api_on_event_before_cb, + .hook_api_on_event_after = hook_api_on_event_after_cb, + .hook_api_call = hook_api_call_cb, + .hook_api_call_result = hook_api_call_result_cb, + .hook_api_callsync = hook_api_callsync_cb, + .hook_api_callsync_result = hook_api_callsync_result_cb, + .hook_api_new_api_before = hook_api_new_api_before_cb, + .hook_api_new_api_after = hook_api_new_api_after_cb, + .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2_cb, + .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3_cb, + .hook_api_api_add_verb = hook_api_api_add_verb_cb, + .hook_api_api_del_verb = hook_api_api_del_verb_cb, + .hook_api_api_set_on_event = hook_api_api_set_on_event_cb, + .hook_api_api_set_on_init = hook_api_api_set_on_init_cb, + .hook_api_api_seal = hook_api_api_seal_cb, + .hook_api_event_handler_add = hook_api_event_handler_add_cb, + .hook_api_event_handler_del = hook_api_event_handler_del_cb, + .hook_api_class_provide = hook_api_class_provide_cb, + .hook_api_class_require = hook_api_class_require_cb, + .hook_api_delete_api = hook_api_delete_api_cb, + .hook_api_on_event_handler_before = hook_api_on_event_handler_before_cb, + .hook_api_on_event_handler_after = hook_api_on_event_handler_after_cb, }; /****************************************************************************** * section: hooks for tracing daemon interface (export) *****************************************************************************/ -#define _HOOK_DITF_(what,...) \ - struct afb_hook_ditf *hook; \ +#define _HOOK_API_2_(flag,func,...) \ + struct afb_hook_api *hook; \ struct afb_hookid hookid; \ const char *apiname = afb_export_apiname(export); \ pthread_rwlock_rdlock(&rwlock); \ init_hookid(&hookid); \ - hook = list_of_ditf_hooks; \ + hook = list_of_api_hooks; \ while (hook) { \ - if (hook->itf->hook_ditf_##what \ - && (hook->flags & afb_hook_flag_ditf_##what) != 0 \ - && (!hook->api || !strcasecmp(hook->api, apiname))) { \ - hook->itf->hook_ditf_##what(hook->closure, &hookid, __VA_ARGS__); \ + if (hook->itf->hook_api_##func \ + && (hook->flags & afb_hook_flag_api_##flag) != 0 \ + && MATCH_API(hook->api, apiname)) { \ + hook->itf->hook_api_##func(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ } \ pthread_rwlock_unlock(&rwlock); -void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object) +#define _HOOK_API_(what,...) _HOOK_API_2_(what,what,__VA_ARGS__) + +void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object) { - _HOOK_DITF_(event_broadcast_before, export, name, object); + _HOOK_API_2_(event_broadcast, event_broadcast_before, export, name, object); } -int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result) +int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result) { - _HOOK_DITF_(event_broadcast_after, export, name, object, result); + _HOOK_API_2_(event_broadcast, event_broadcast_after, export, name, object, result); return result; } -struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result) +struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result) { - _HOOK_DITF_(get_event_loop, export, result); + _HOOK_API_(get_event_loop, export, result); return result; } -struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result) +struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result) { - _HOOK_DITF_(get_user_bus, export, result); + _HOOK_API_(get_user_bus, export, result); return result; } -struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result) +struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result) { - _HOOK_DITF_(get_system_bus, export, result); + _HOOK_API_(get_system_bus, export, result); return result; } -void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { - _HOOK_DITF_(vverbose, export, level, file, line, function, fmt, args); + _HOOK_API_(vverbose, export, level, file, line, function, fmt, args); } -struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result) +struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - _HOOK_DITF_(event_make, export, name, result); + _HOOK_API_(event_make, export, name, result); return result; } -int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result) +int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result) { - _HOOK_DITF_(rootdir_get_fd, export, result); + _HOOK_API_(rootdir_get_fd, export, result); return result; } -int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { - _HOOK_DITF_(rootdir_open_locale, export, filename, flags, locale, result); + _HOOK_API_(rootdir_open_locale, export, filename, flags, locale, result); return result; } -int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) { - _HOOK_DITF_(queue_job, export, callback, argument, group, timeout, result); + _HOOK_API_(queue_job, export, callback, argument, group, timeout, result); return result; } -void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq) +void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq) { - _HOOK_DITF_(unstore_req, export, sreq); + _HOOK_API_(legacy_unstore_req, export, sreq); } -void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized) +void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized) { - _HOOK_DITF_(require_api, export, name, initialized); + _HOOK_API_(require_api, export, name, initialized); } -int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result) +int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result) { - _HOOK_DITF_(require_api_result, export, name, initialized, result); + _HOOK_API_2_(require_api, require_api_result, export, name, initialized, result); return result; } -int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result) +int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result) { - _HOOK_DITF_(rename_api, export, oldname, newname, result); + _HOOK_API_(add_alias, export, api, alias, result); return result; } -/****************************************************************************** - * section: hooking export - *****************************************************************************/ - -int afb_hook_flags_ditf(const char *api) +void afb_hook_api_start_before(const struct afb_export *export) { - int flags; - struct afb_hook_ditf *hook; - - flags = 0; - if (!api || afb_api_is_hookable(api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_ditf_hooks; - while (hook) { - if (!api || !hook->api || !strcasecmp(hook->api, api)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); - } - return flags; + _HOOK_API_2_(start, start_before, export); } -struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure) +int afb_hook_api_start_after(const struct afb_export *export, int status) { - struct afb_hook_ditf *hook; - - /* alloc the result */ - hook = calloc(1, sizeof *hook); - if (hook == NULL) - return NULL; - - /* get a copy of the names */ - hook->api = api ? strdup(api) : NULL; - if (api && !hook->api) { - free(hook); - return NULL; - } - - /* initialise the rest */ - hook->refcount = 1; - hook->flags = flags; - hook->itf = itf ? itf : &hook_ditf_default_itf; - hook->closure = closure; + _HOOK_API_2_(start, start_after, export, status); + return status; +} - /* record the hook */ - pthread_rwlock_wrlock(&rwlock); - hook->next = list_of_ditf_hooks; - list_of_ditf_hooks = hook; - pthread_rwlock_unlock(&rwlock); +void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _HOOK_API_2_(on_event, on_event_before, export, event, event_x2, object); +} - /* returns it */ - return hook; +void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object) +{ + _HOOK_API_2_(on_event, on_event_after, export, event, event_x2, object); } -struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook) +void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - pthread_rwlock_wrlock(&rwlock); - hook->refcount++; - pthread_rwlock_unlock(&rwlock); - return hook; + _HOOK_API_(call, export, api, verb, args); } -void afb_hook_unref_ditf(struct afb_hook_ditf *hook) +void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char*error, const char *info) { - struct afb_hook_ditf **prv; + _HOOK_API_2_(call, call_result, export, object, error, info); - if (hook) { - pthread_rwlock_wrlock(&rwlock); - if (--hook->refcount) - hook = NULL; - else { - /* unlink */ - prv = &list_of_ditf_hooks; - while (*prv && *prv != hook) - prv = &(*prv)->next; - if(*prv) - *prv = hook->next; - } - pthread_rwlock_unlock(&rwlock); - if (hook) { - /* free */ - free(hook->api); - free(hook); - } - } } -/****************************************************************************** - * section: default callbacks for tracing service interface (export) - *****************************************************************************/ - -static void _hook_svc_(const struct afb_export *export, const char *format, ...) +void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - va_list ap; - va_start(ap, format); - _hook_("export-%s", format, ap, afb_export_apiname(export)); - va_end(ap); + _HOOK_API_(callsync, export, api, verb, args); } -static void hook_svc_start_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +int afb_hook_api_callsync_result(const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) { - _hook_svc_(export, "start.before"); + _HOOK_API_2_(callsync, callsync_result, export, status, object, error, info); + return status; } -static void hook_svc_start_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency) { - _hook_svc_(export, "start.after -> %d", status); + _HOOK_API_2_(new_api, new_api_before, export, api, info, noconcurrency); } -static void hook_svc_on_event_before_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api) { - _hook_svc_(export, "on_event.before(%s, %d, %s)", event, eventid, json_object_to_json_string(object)); + _HOOK_API_2_(new_api, new_api_after, export, result, api); + return result; } -static void hook_svc_on_event_after_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) { - _hook_svc_(export, "on_event.after(%s, %d, %s)", event, eventid, json_object_to_json_string(object)); + _HOOK_API_2_(api_set_verbs, api_set_verbs_v2, export, result, verbs); + return result; } -static void hook_svc_call_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) { - _hook_svc_(export, "call(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); + _HOOK_API_2_(api_set_verbs, api_set_verbs_v3, export, result, verbs); + return result; } -static void hook_svc_call_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob) { - _hook_svc_(export, " ...call... -> %d: %s", status, json_object_to_json_string(result)); + _HOOK_API_(api_add_verb, export, result, verb, info, glob); + return result; } -static void hook_svc_callsync_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb) { - _hook_svc_(export, "callsync(%s/%s, %s) ...", api, verb, json_object_to_json_string(args)); + _HOOK_API_(api_del_verb, export, result, verb); + return result; } -static void hook_svc_callsync_result_default_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_api_set_on_event(const struct afb_export *export, int result) { - _hook_svc_(export, " ...callsync... -> %d: %s", status, json_object_to_json_string(result)); + _HOOK_API_(api_set_on_event, export, result); + return result; } -static struct afb_hook_svc_itf hook_svc_default_itf = { - .hook_svc_start_before = hook_svc_start_before_default_cb, - .hook_svc_start_after = hook_svc_start_after_default_cb, - .hook_svc_on_event_before = hook_svc_on_event_before_default_cb, - .hook_svc_on_event_after = hook_svc_on_event_after_default_cb, - .hook_svc_call = hook_svc_call_default_cb, - .hook_svc_call_result = hook_svc_call_result_default_cb, - .hook_svc_callsync = hook_svc_callsync_default_cb, - .hook_svc_callsync_result = hook_svc_callsync_result_default_cb -}; - -/****************************************************************************** - * section: hooks for tracing service interface (export) - *****************************************************************************/ - -#define _HOOK_SVC_(what,...) \ - struct afb_hook_svc *hook; \ - struct afb_hookid hookid; \ - const char *apiname = afb_export_apiname(export); \ - pthread_rwlock_rdlock(&rwlock); \ - init_hookid(&hookid); \ - hook = list_of_svc_hooks; \ - while (hook) { \ - if (hook->itf->hook_svc_##what \ - && (hook->flags & afb_hook_flag_svc_##what) != 0 \ - && (!hook->api || !strcasecmp(hook->api, apiname))) { \ - hook->itf->hook_svc_##what(hook->closure, &hookid, __VA_ARGS__); \ - } \ - hook = hook->next; \ - } \ - pthread_rwlock_unlock(&rwlock); - -void afb_hook_svc_start_before(const struct afb_export *export) +int afb_hook_api_api_set_on_init(const struct afb_export *export, int result) { - _HOOK_SVC_(start_before, export); + _HOOK_API_(api_set_on_init, export, result); + return result; } -int afb_hook_svc_start_after(const struct afb_export *export, int status) +void afb_hook_api_api_seal(const struct afb_export *export) { - _HOOK_SVC_(start_after, export, status); - return status; + _HOOK_API_(api_seal, export); } -void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern) { - _HOOK_SVC_(on_event_before, export, event, eventid, object); + _HOOK_API_(event_handler_add, export, result, pattern); + return result; } - -void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object) +int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern) { - _HOOK_SVC_(on_event_after, export, event, eventid, object); + _HOOK_API_(event_handler_del, export, result, pattern); + return result; } - -void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name) { - _HOOK_SVC_(call, export, api, verb, args); + _HOOK_API_(class_provide, export, result, name); + return result; +} +int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name) +{ + _HOOK_API_(class_require, export, result, name); + return result; } -void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result) +int afb_hook_api_delete_api(const struct afb_export *export, int result) { - _HOOK_SVC_(call_result, export, status, result); + _HOOK_API_(delete_api, export, result); + return result; } -void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _HOOK_SVC_(callsync, export, api, verb, args); + _HOOK_API_2_(on_event_handler, on_event_handler_before, export, event, event_x2, object, pattern); } -int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result) +void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern) { - _HOOK_SVC_(callsync_result, export, status, result); - return status; + _HOOK_API_2_(on_event_handler, on_event_handler_after, export, event, event_x2, object, pattern); } /****************************************************************************** - * section: hooking services (export) + * section: hooking export *****************************************************************************/ -int afb_hook_flags_svc(const char *api) +int afb_hook_flags_api(const char *api) { int flags; - struct afb_hook_svc *hook; + struct afb_hook_api *hook; flags = 0; - if (!api || afb_api_is_hookable(api)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_svc_hooks; - while (hook) { - if (!api || !hook->api || !strcasecmp(hook->api, api)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_api_hooks; + while (hook) { + if (!api || MATCH_API(hook->api, api)) + flags |= hook->flags; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); return flags; } -struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure) +struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure) { - struct afb_hook_svc *hook; + struct afb_hook_api *hook; /* alloc the result */ hook = calloc(1, sizeof *hook); @@ -1186,20 +1220,20 @@ struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_ /* initialise the rest */ hook->refcount = 1; hook->flags = flags; - hook->itf = itf ? itf : &hook_svc_default_itf; + hook->itf = itf ? itf : &hook_api_default_itf; hook->closure = closure; /* record the hook */ pthread_rwlock_wrlock(&rwlock); - hook->next = list_of_svc_hooks; - list_of_svc_hooks = hook; + hook->next = list_of_api_hooks; + list_of_api_hooks = hook; pthread_rwlock_unlock(&rwlock); /* returns it */ return hook; } -struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook) +struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook) { pthread_rwlock_wrlock(&rwlock); hook->refcount++; @@ -1207,9 +1241,9 @@ struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook) return hook; } -void afb_hook_unref_svc(struct afb_hook_svc *hook) +void afb_hook_unref_api(struct afb_hook_api *hook) { - struct afb_hook_svc **prv; + struct afb_hook_api **prv; if (hook) { pthread_rwlock_wrlock(&rwlock); @@ -1217,7 +1251,7 @@ void afb_hook_unref_svc(struct afb_hook_svc *hook) hook = NULL; else { /* unlink */ - prv = &list_of_svc_hooks; + prv = &list_of_api_hooks; while (*prv && *prv != hook) prv = &(*prv)->next; if(*prv) @@ -1244,56 +1278,56 @@ static void _hook_evt_(const char *evt, int id, const char *format, ...) va_end(ap); } -static void hook_evt_create_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_create_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "create"); } -static void hook_evt_push_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) +static void hook_evt_push_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) { _hook_evt_(evt, id, "push.before(%s)", json_object_to_json_string(obj)); } -static void hook_evt_push_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) +static void hook_evt_push_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) { _hook_evt_(evt, id, "push.after(%s) -> %d", json_object_to_json_string(obj), result); } -static void hook_evt_broadcast_before_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) +static void hook_evt_broadcast_before_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj) { _hook_evt_(evt, id, "broadcast.before(%s)", json_object_to_json_string(obj)); } -static void hook_evt_broadcast_after_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) +static void hook_evt_broadcast_after_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, struct json_object *obj, int result) { _hook_evt_(evt, id, "broadcast.after(%s) -> %d", json_object_to_json_string(obj), result); } -static void hook_evt_name_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result) +static void hook_evt_name_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id, const char *result) { _hook_evt_(evt, id, "name -> %s", result); } -static void hook_evt_addref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_addref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "addref"); } -static void hook_evt_unref_default_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) +static void hook_evt_unref_cb(void *closure, const struct afb_hookid *hookid, const char *evt, int id) { _hook_evt_(evt, id, "unref"); } static struct afb_hook_evt_itf hook_evt_default_itf = { - .hook_evt_create = hook_evt_create_default_cb, - .hook_evt_push_before = hook_evt_push_before_default_cb, - .hook_evt_push_after = hook_evt_push_after_default_cb, - .hook_evt_broadcast_before = hook_evt_broadcast_before_default_cb, - .hook_evt_broadcast_after = hook_evt_broadcast_after_default_cb, - .hook_evt_name = hook_evt_name_default_cb, - .hook_evt_addref = hook_evt_addref_default_cb, - .hook_evt_unref = hook_evt_unref_default_cb + .hook_evt_create = hook_evt_create_cb, + .hook_evt_push_before = hook_evt_push_before_cb, + .hook_evt_push_after = hook_evt_push_after_cb, + .hook_evt_broadcast_before = hook_evt_broadcast_before_cb, + .hook_evt_broadcast_after = hook_evt_broadcast_after_cb, + .hook_evt_name = hook_evt_name_cb, + .hook_evt_addref = hook_evt_addref_cb, + .hook_evt_unref = hook_evt_unref_cb }; /****************************************************************************** @@ -1309,7 +1343,7 @@ static struct afb_hook_evt_itf hook_evt_default_itf = { while (hook) { \ if (hook->itf->hook_evt_##what \ && (hook->flags & afb_hook_flag_evt_##what) != 0 \ - && (!hook->pattern || MATCH(hook->pattern, evt))) { \ + && MATCH_EVENT(hook->pattern, evt)) { \ hook->itf->hook_evt_##what(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ @@ -1368,16 +1402,14 @@ int afb_hook_flags_evt(const char *name) struct afb_hook_evt *hook; flags = 0; - if (!name || afb_api_is_hookable(name)) { - pthread_rwlock_rdlock(&rwlock); - hook = list_of_evt_hooks; - while (hook) { - if (!name || !hook->pattern || MATCH(hook->pattern, name)) - flags |= hook->flags; - hook = hook->next; - } - pthread_rwlock_unlock(&rwlock); + pthread_rwlock_rdlock(&rwlock); + hook = list_of_evt_hooks; + while (hook) { + if (!name || MATCH_EVENT(hook->pattern, name)) + flags |= hook->flags; + hook = hook->next; } + pthread_rwlock_unlock(&rwlock); return flags; } @@ -1458,43 +1490,43 @@ static void _hook_session_(struct afb_session *session, const char *format, ...) va_end(ap); } -static void hook_session_create_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_create_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "create -> token=%s", afb_session_token(session)); } -static void hook_session_close_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_close_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "close"); } -static void hook_session_destroy_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_destroy_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "destroy"); } -static void hook_session_renew_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_renew_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "renew -> token=%s", afb_session_token(session)); } -static void hook_session_addref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_addref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "addref"); } -static void hook_session_unref_default_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) +static void hook_session_unref_cb(void *closure, const struct afb_hookid *hookid, struct afb_session *session) { _hook_session_(session, "unref"); } static struct afb_hook_session_itf hook_session_default_itf = { - .hook_session_create = hook_session_create_default_cb, - .hook_session_close = hook_session_close_default_cb, - .hook_session_destroy = hook_session_destroy_default_cb, - .hook_session_renew = hook_session_renew_default_cb, - .hook_session_addref = hook_session_addref_default_cb, - .hook_session_unref = hook_session_unref_default_cb + .hook_session_create = hook_session_create_cb, + .hook_session_close = hook_session_close_cb, + .hook_session_destroy = hook_session_destroy_cb, + .hook_session_renew = hook_session_renew_cb, + .hook_session_addref = hook_session_addref_cb, + .hook_session_unref = hook_session_unref_cb }; /****************************************************************************** @@ -1511,7 +1543,7 @@ static struct afb_hook_session_itf hook_session_default_itf = { while (hook) { \ if (hook->itf->hook_session_##what \ && (hook->flags & afb_hook_flag_session_##what) != 0 \ - && (!hook->pattern || MATCH(hook->pattern, (sessid?:(sessid=afb_session_uuid(session)))))) { \ + && MATCH_SESSION(hook->pattern, (sessid?:(sessid=afb_session_uuid(session))))) { \ hook->itf->hook_session_##what(hook->closure, &hookid, __VA_ARGS__); \ } \ hook = hook->next; \ @@ -1630,7 +1662,7 @@ static void _hook_global_(const char *format, ...) va_end(ap); } -static void hook_global_vverbose_default_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void hook_global_vverbose_cb(void *closure, const struct afb_hookid *hookid, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { int len; char *msg; @@ -1641,15 +1673,15 @@ static void hook_global_vverbose_default_cb(void *closure, const struct afb_hook va_end(ap); if (len < 0) - _hook_global_("vverbose(%d, %s, %d, %s) -> %s ? ? ?", level, file, line, func, fmt); + _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s ? ? ?", level, verbose_name_of_level(level), file, line, func, fmt); else { - _hook_global_("vverbose(%d, %s, %d, %s) -> %s", level, file, line, func, msg); + _hook_global_("vverbose(%d:%s, %s, %d, %s) -> %s", level, verbose_name_of_level(level), file, line, func, msg); free(msg); } } static struct afb_hook_global_itf hook_global_default_itf = { - .hook_global_vverbose = hook_global_vverbose_default_cb + .hook_global_vverbose = hook_global_vverbose_cb }; /****************************************************************************** diff --git a/src/afb-hook.h b/src/afb-hook.h index 52d83355..f315cc08 100644 --- a/src/afb-hook.h +++ b/src/afb-hook.h @@ -24,7 +24,9 @@ struct req; struct afb_context; struct json_object; struct afb_arg; -struct afb_eventid; +struct afb_event_x2; +struct afb_verb_v2; +struct afb_verb_v3; struct afb_session; struct afb_xreq; struct afb_export; @@ -32,8 +34,7 @@ struct afb_stored_req; struct sd_bus; struct sd_event; struct afb_hook_xreq; -struct afb_hook_ditf; -struct afb_hook_svc; +struct afb_hook_api; struct afb_hook_evt; struct afb_hook_session; struct afb_hook_global; @@ -56,10 +57,10 @@ struct afb_hookid #define afb_hook_flag_req_end 0x00000002 #define afb_hook_flag_req_json 0x00000004 #define afb_hook_flag_req_get 0x00000008 -#define afb_hook_flag_req_success 0x00000010 -#define afb_hook_flag_req_fail 0x00000020 -#define afb_hook_flag_req_context_get 0x00000040 -#define afb_hook_flag_req_context_set 0x00000080 +#define afb_hook_flag_req_reply 0x00000010 +#define afb_hook_flag_req_get_client_info 0x00000020 +#define afb_hook_flag_req_legacy_context_get 0x00000040 +#define afb_hook_flag_req_legacy_context_set 0x00000080 #define afb_hook_flag_req_addref 0x00000100 #define afb_hook_flag_req_unref 0x00000200 #define afb_hook_flag_req_session_close 0x00000400 @@ -71,35 +72,31 @@ struct afb_hookid #define afb_hook_flag_req_subcallsync 0x00010000 #define afb_hook_flag_req_subcallsync_result 0x00020000 #define afb_hook_flag_req_vverbose 0x00040000 -#define afb_hook_flag_req_store 0x00080000 -#define afb_hook_flag_req_unstore 0x00100000 -#define afb_hook_flag_req_subcall_req 0x00200000 -#define afb_hook_flag_req_subcall_req_result 0x00400000 -#define afb_hook_flag_req_has_permission 0x00800000 -#define afb_hook_flag_req_get_application_id 0x01000000 -#define afb_hook_flag_req_context_make 0x02000000 -#define afb_hook_flag_req_get_uid 0x04000000 +#define afb_hook_flag_req_legacy_store 0x00080000 +#define afb_hook_flag_req_legacy_unstore 0x00100000 +#define afb_hook_flag_req_has_permission 0x00200000 +#define afb_hook_flag_req_get_application_id 0x00400000 +#define afb_hook_flag_req_context_make 0x00800000 +#define afb_hook_flag_req_get_uid 0x01000000 /* common flags */ #define afb_hook_flags_req_life (afb_hook_flag_req_begin|afb_hook_flag_req_end) #define afb_hook_flags_req_args (afb_hook_flag_req_json|afb_hook_flag_req_get) -#define afb_hook_flags_req_result (afb_hook_flag_req_success|afb_hook_flag_req_fail) #define afb_hook_flags_req_session (afb_hook_flag_req_session_close|afb_hook_flag_req_session_set_LOA) #define afb_hook_flags_req_event (afb_hook_flag_req_subscribe|afb_hook_flag_req_unsubscribe) #define afb_hook_flags_req_subcalls (afb_hook_flag_req_subcall|afb_hook_flag_req_subcall_result\ - |afb_hook_flag_req_subcall_req|afb_hook_flag_req_subcall_req_result\ |afb_hook_flag_req_subcallsync|afb_hook_flag_req_subcallsync_result) #define afb_hook_flags_req_security (afb_hook_flag_req_has_permission|afb_hook_flag_req_get_application_id\ - |afb_hook_flag_req_get_uid) + |afb_hook_flag_req_get_uid|afb_hook_flag_req_get_client_info) /* extra flags */ #define afb_hook_flags_req_ref (afb_hook_flag_req_addref|afb_hook_flag_req_unref) -#define afb_hook_flags_req_context (afb_hook_flag_req_context_get|afb_hook_flag_req_context_set\ +#define afb_hook_flags_req_context (afb_hook_flag_req_legacy_context_get|afb_hook_flag_req_legacy_context_set\ |afb_hook_flag_req_context_make) -#define afb_hook_flags_req_stores (afb_hook_flag_req_store|afb_hook_flag_req_unstore) +#define afb_hook_flags_req_stores (afb_hook_flag_req_legacy_store|afb_hook_flag_req_legacy_unstore) /* predefined groups */ -#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flags_req_result\ +#define afb_hook_flags_req_common (afb_hook_flags_req_life|afb_hook_flags_req_args|afb_hook_flag_req_reply\ |afb_hook_flags_req_session|afb_hook_flags_req_event|afb_hook_flags_req_subcalls\ |afb_hook_flag_req_vverbose|afb_hook_flags_req_security) #define afb_hook_flags_req_extra (afb_hook_flags_req_common|afb_hook_flags_req_ref|afb_hook_flags_req_context\ @@ -111,29 +108,27 @@ struct afb_hook_xreq_itf { void (*hook_xreq_end)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_json)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj); void (*hook_xreq_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *name, struct afb_arg arg); - void (*hook_xreq_success)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info); - void (*hook_xreq_fail)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info); - void (*hook_xreq_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value); - void (*hook_xreq_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); + void (*hook_xreq_reply)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); + void (*hook_xreq_legacy_context_get)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value); + void (*hook_xreq_legacy_context_set)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); void (*hook_xreq_addref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_unref)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_session_close)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_session_set_LOA)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, unsigned level, int result); - void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); - void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); + void (*hook_xreq_subscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); + void (*hook_xreq_unsubscribe)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); void (*hook_xreq_subcall)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_subcall_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); void (*hook_xreq_subcallsync)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_subcallsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info); void (*hook_xreq_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args); - void (*hook_xreq_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq); - void (*hook_xreq_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); - void (*hook_xreq_subcall_req)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); - void (*hook_xreq_subcall_req_result)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result); + void (*hook_xreq_legacy_store)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_stored_req *sreq); + void (*hook_xreq_legacy_unstore)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq); void (*hook_xreq_has_permission)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result); void (*hook_xreq_get_application_id)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, char *result); void (*hook_xreq_context_make)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result); void (*hook_xreq_get_uid)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int result); + void (*hook_xreq_get_client_info)(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result); }; extern void afb_hook_init_xreq(struct afb_xreq *xreq); @@ -147,145 +142,220 @@ extern void afb_hook_xreq_begin(const struct afb_xreq *xreq); extern void afb_hook_xreq_end(const struct afb_xreq *xreq); extern struct json_object *afb_hook_xreq_json(const struct afb_xreq *xreq, struct json_object *obj); extern struct afb_arg afb_hook_xreq_get(const struct afb_xreq *xreq, const char *name, struct afb_arg arg); -extern void afb_hook_xreq_success(const struct afb_xreq *xreq, struct json_object *obj, const char *info); -extern void afb_hook_xreq_fail(const struct afb_xreq *xreq, const char *status, const char *info); -extern void *afb_hook_xreq_context_get(const struct afb_xreq *xreq, void *value); -extern void afb_hook_xreq_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); +extern void afb_hook_xreq_reply(const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); +extern void *afb_hook_xreq_legacy_context_get(const struct afb_xreq *xreq, void *value); +extern void afb_hook_xreq_legacy_context_set(const struct afb_xreq *xreq, void *value, void (*free_value)(void*)); extern void afb_hook_xreq_addref(const struct afb_xreq *xreq); extern void afb_hook_xreq_unref(const struct afb_xreq *xreq); extern void afb_hook_xreq_session_close(const struct afb_xreq *xreq); extern int afb_hook_xreq_session_set_LOA(const struct afb_xreq *xreq, unsigned level, int result); -extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); -extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_eventid *eventid, int result); -extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, int status, struct json_object *result); -extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *result); +extern int afb_hook_xreq_subscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); +extern int afb_hook_xreq_unsubscribe(const struct afb_xreq *xreq, struct afb_event_x2 *event_x2, int result); +extern void afb_hook_xreq_subcall(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags); +extern void afb_hook_xreq_subcall_result(const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); +extern void afb_hook_xreq_subcallsync(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags); +extern int afb_hook_xreq_subcallsync_result(const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info); extern void afb_hook_xreq_vverbose(const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args); -extern void afb_hook_xreq_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq); -extern void afb_hook_xreq_unstore(const struct afb_xreq *xreq); -extern void afb_hook_xreq_subcall_req(const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_xreq_subcall_req_result(const struct afb_xreq *xreq, int status, struct json_object *result); +extern void afb_hook_xreq_legacy_store(const struct afb_xreq *xreq, struct afb_stored_req *sreq); +extern void afb_hook_xreq_legacy_unstore(const struct afb_xreq *xreq); extern int afb_hook_xreq_has_permission(const struct afb_xreq *xreq, const char *permission, int result); extern char *afb_hook_xreq_get_application_id(const struct afb_xreq *xreq, char *result); extern void *afb_hook_xreq_context_make(const struct afb_xreq *xreq, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure, void *result); extern int afb_hook_xreq_get_uid(const struct afb_xreq *xreq, int result); +extern struct json_object *afb_hook_xreq_get_client_info(const struct afb_xreq *xreq, struct json_object *result); /********************************************************* -* section hooking export (daemon interface) +* section hooking apis *********************************************************/ -#define afb_hook_flag_ditf_vverbose 0x000001 -#define afb_hook_flag_ditf_event_make 0x000002 -#define afb_hook_flag_ditf_event_broadcast_before 0x000004 -#define afb_hook_flag_ditf_event_broadcast_after 0x000008 -#define afb_hook_flag_ditf_get_event_loop 0x000010 -#define afb_hook_flag_ditf_get_user_bus 0x000020 -#define afb_hook_flag_ditf_get_system_bus 0x000040 -#define afb_hook_flag_ditf_rootdir_get_fd 0x000080 -#define afb_hook_flag_ditf_rootdir_open_locale 0x000100 -#define afb_hook_flag_ditf_queue_job 0x000200 -#define afb_hook_flag_ditf_unstore_req 0x000400 -#define afb_hook_flag_ditf_require_api 0x000800 -#define afb_hook_flag_ditf_require_api_result 0x001000 -#define afb_hook_flag_ditf_rename_api 0x002000 - -#define afb_hook_flags_ditf_common (afb_hook_flag_ditf_vverbose\ - |afb_hook_flag_ditf_event_make\ - |afb_hook_flag_ditf_event_broadcast_before\ - |afb_hook_flag_ditf_event_broadcast_after\ - |afb_hook_flag_ditf_rename_api) -#define afb_hook_flags_ditf_extra (afb_hook_flag_ditf_get_event_loop\ - |afb_hook_flag_ditf_get_user_bus\ - |afb_hook_flag_ditf_get_system_bus\ - |afb_hook_flag_ditf_rootdir_get_fd\ - |afb_hook_flag_ditf_rootdir_open_locale\ - |afb_hook_flag_ditf_queue_job\ - |afb_hook_flag_ditf_unstore_req\ - |afb_hook_flag_ditf_require_api\ - |afb_hook_flag_ditf_require_api_result) - -#define afb_hook_flags_ditf_all (afb_hook_flags_ditf_common|afb_hook_flags_ditf_extra) - -struct afb_hook_ditf_itf { - void (*hook_ditf_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object); - void (*hook_ditf_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result); - void (*hook_ditf_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result); - void (*hook_ditf_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); - void (*hook_ditf_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); - void (*hook_ditf_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); - void (*hook_ditf_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result); - void (*hook_ditf_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); - void (*hook_ditf_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result); - void (*hook_ditf_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); - void (*hook_ditf_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq); - void (*hook_ditf_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized); - void (*hook_ditf_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result); - void (*hook_ditf_rename_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result); -}; +#define afb_hook_flag_api_vverbose 0x00000001 +#define afb_hook_flag_api_get_event_loop 0x00000002 +#define afb_hook_flag_api_get_user_bus 0x00000004 +#define afb_hook_flag_api_get_system_bus 0x00000008 +#define afb_hook_flag_api_rootdir_get_fd 0x00000010 +#define afb_hook_flag_api_rootdir_open_locale 0x00000020 +#define afb_hook_flag_api_queue_job 0x00000040 +#define afb_hook_flag_api_require_api 0x00000080 +#define afb_hook_flag_api_add_alias 0x00000100 +#define afb_hook_flag_api_event_broadcast 0x00000200 +#define afb_hook_flag_api_event_make 0x00000400 +#define afb_hook_flag_api_new_api 0x00000800 +#define afb_hook_flag_api_api_set_verbs 0x00001000 +#define afb_hook_flag_api_api_add_verb 0x00002000 +#define afb_hook_flag_api_api_del_verb 0x00004000 +#define afb_hook_flag_api_api_set_on_event 0x00008000 +#define afb_hook_flag_api_api_set_on_init 0x00010000 +#define afb_hook_flag_api_api_seal 0x00020000 +#define afb_hook_flag_api_event_handler_add 0x00040000 +#define afb_hook_flag_api_event_handler_del 0x00080000 +#define afb_hook_flag_api_call 0x00100000 +#define afb_hook_flag_api_callsync 0x00200000 +#define afb_hook_flag_api_class_provide 0x00400000 +#define afb_hook_flag_api_class_require 0x00800000 +#define afb_hook_flag_api_delete_api 0x01000000 +#define afb_hook_flag_api_start 0x02000000 +#define afb_hook_flag_api_on_event 0x04000000 +#define afb_hook_flag_api_legacy_unstore_req 0x08000000 +#define afb_hook_flag_api_on_event_handler 0x10000000 + +/* common flags */ +/* extra flags */ +/* predefined groups */ -extern void afb_hook_ditf_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object); -extern int afb_hook_ditf_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result); -extern struct sd_event *afb_hook_ditf_get_event_loop(const struct afb_export *export, struct sd_event *result); -extern struct sd_bus *afb_hook_ditf_get_user_bus(const struct afb_export *export, struct sd_bus *result); -extern struct sd_bus *afb_hook_ditf_get_system_bus(const struct afb_export *export, struct sd_bus *result); -extern void afb_hook_ditf_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); -extern struct afb_eventid *afb_hook_ditf_event_make(const struct afb_export *export, const char *name, struct afb_eventid *result); -extern int afb_hook_ditf_rootdir_get_fd(const struct afb_export *export, int result); -extern int afb_hook_ditf_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result); -extern int afb_hook_ditf_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); -extern void afb_hook_ditf_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq); -extern void afb_hook_ditf_require_api(const struct afb_export *export, const char *name, int initialized); -extern int afb_hook_ditf_require_api_result(const struct afb_export *export, const char *name, int initialized, int result); -extern int afb_hook_ditf_rename_api(const struct afb_export *export, const char *oldname, const char *newname, int result); - -extern int afb_hook_flags_ditf(const char *api); -extern struct afb_hook_ditf *afb_hook_create_ditf(const char *api, int flags, struct afb_hook_ditf_itf *itf, void *closure); -extern struct afb_hook_ditf *afb_hook_addref_ditf(struct afb_hook_ditf *hook); -extern void afb_hook_unref_ditf(struct afb_hook_ditf *hook); +#define afb_hook_flags_api_common (afb_hook_flag_api_vverbose\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_call\ + |afb_hook_flag_api_callsync\ + |afb_hook_flag_api_start\ + |afb_hook_flag_api_queue_job) + + +#define afb_hook_flags_api_extra (afb_hook_flag_api_get_event_loop\ + |afb_hook_flag_api_get_user_bus\ + |afb_hook_flag_api_get_system_bus\ + |afb_hook_flag_api_rootdir_get_fd\ + |afb_hook_flag_api_rootdir_open_locale\ + |afb_hook_flag_api_legacy_unstore_req) + + +#define afb_hook_flags_api_api (afb_hook_flag_api_new_api\ + |afb_hook_flag_api_api_set_verbs\ + |afb_hook_flag_api_api_add_verb\ + |afb_hook_flag_api_api_del_verb\ + |afb_hook_flag_api_api_set_on_event\ + |afb_hook_flag_api_api_set_on_init\ + |afb_hook_flag_api_api_seal\ + |afb_hook_flag_api_class_provide\ + |afb_hook_flag_api_class_require\ + |afb_hook_flag_api_require_api\ + |afb_hook_flag_api_add_alias\ + |afb_hook_flag_api_delete_api) + +#define afb_hook_flags_api_event (afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_event_handler_add\ + |afb_hook_flag_api_event_handler_del\ + |afb_hook_flag_api_on_event\ + |afb_hook_flag_api_on_event_handler) + +#define afb_hook_flags_api_all (afb_hook_flags_api_common\ + |afb_hook_flags_api_extra\ + |afb_hook_flags_api_api\ + |afb_hook_flags_api_event) /********************************************************* -* section hooking export (service interface) +*********************************************************/ +#define afb_hook_flags_api_svc_all (afb_hook_flag_api_start|afb_hook_flag_api_start\ + |afb_hook_flag_api_on_event|afb_hook_flag_api_on_event\ + |afb_hook_flag_api_call|afb_hook_flag_api_call\ + |afb_hook_flag_api_callsync|afb_hook_flag_api_callsync) + +#define afb_hook_flags_api_ditf_common (afb_hook_flag_api_vverbose\ + |afb_hook_flag_api_event_make\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_event_broadcast\ + |afb_hook_flag_api_add_alias) + +#define afb_hook_flags_api_ditf_extra (afb_hook_flag_api_get_event_loop\ + |afb_hook_flag_api_get_user_bus\ + |afb_hook_flag_api_get_system_bus\ + |afb_hook_flag_api_rootdir_get_fd\ + |afb_hook_flag_api_rootdir_open_locale\ + |afb_hook_flag_api_queue_job\ + |afb_hook_flag_api_legacy_unstore_req\ + |afb_hook_flag_api_require_api\ + |afb_hook_flag_api_require_api) + +#define afb_hook_flags_api_ditf_all (afb_hook_flags_api_ditf_common|afb_hook_flags_api_ditf_extra) +/********************************************************* *********************************************************/ -#define afb_hook_flag_svc_start_before 0x000001 -#define afb_hook_flag_svc_start_after 0x000002 -#define afb_hook_flag_svc_on_event_before 0x000004 -#define afb_hook_flag_svc_on_event_after 0x000008 -#define afb_hook_flag_svc_call 0x000010 -#define afb_hook_flag_svc_call_result 0x000020 -#define afb_hook_flag_svc_callsync 0x000040 -#define afb_hook_flag_svc_callsync_result 0x000080 - -#define afb_hook_flags_svc_all (afb_hook_flag_svc_start_before|afb_hook_flag_svc_start_after\ - |afb_hook_flag_svc_on_event_before|afb_hook_flag_svc_on_event_after\ - |afb_hook_flag_svc_call|afb_hook_flag_svc_call_result\ - |afb_hook_flag_svc_callsync|afb_hook_flag_svc_callsync_result) - -struct afb_hook_svc_itf { - void (*hook_svc_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); - void (*hook_svc_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status); - void (*hook_svc_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object); - void (*hook_svc_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int eventid, struct json_object *object); - void (*hook_svc_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); - void (*hook_svc_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result); - void (*hook_svc_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); - void (*hook_svc_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result); -}; -extern void afb_hook_svc_start_before(const struct afb_export *export); -extern int afb_hook_svc_start_after(const struct afb_export *export, int status); -extern void afb_hook_svc_on_event_before(const struct afb_export *export, const char *event, int eventid, struct json_object *object); -extern void afb_hook_svc_on_event_after(const struct afb_export *export, const char *event, int eventid, struct json_object *object); -extern void afb_hook_svc_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); -extern void afb_hook_svc_call_result(const struct afb_export *export, int status, struct json_object *result); -extern void afb_hook_svc_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); -extern int afb_hook_svc_callsync_result(const struct afb_export *export, int status, struct json_object *result); +struct afb_hook_api_itf { + void (*hook_api_event_broadcast_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object); + void (*hook_api_event_broadcast_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result); + void (*hook_api_get_event_loop)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result); + void (*hook_api_get_user_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); + void (*hook_api_get_system_bus)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result); + void (*hook_api_vverbose)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); + void (*hook_api_event_make)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result); + void (*hook_api_rootdir_get_fd)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_rootdir_open_locale)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result); + void (*hook_api_queue_job)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); + void (*hook_api_legacy_unstore_req)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq); + void (*hook_api_require_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized); + void (*hook_api_require_api_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result); + void (*hook_api_add_alias)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *oldname, const char *newname, int result); + void (*hook_api_start_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); + void (*hook_api_start_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status); + void (*hook_api_on_event_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object); + void (*hook_api_on_event_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object); + void (*hook_api_call)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); + void (*hook_api_call_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info); + void (*hook_api_callsync)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args); + void (*hook_api_callsync_result)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info); + void (*hook_api_new_api_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency); + void (*hook_api_new_api_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api); + void (*hook_api_api_set_verbs_v2)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs); + void (*hook_api_api_set_verbs_v3)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs); + void (*hook_api_api_add_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob); + void (*hook_api_api_del_verb)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb); + void (*hook_api_api_set_on_event)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_api_set_on_init)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_api_seal)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export); + void (*hook_api_event_handler_add)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern); + void (*hook_api_event_handler_del)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern); + void (*hook_api_class_provide)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name); + void (*hook_api_class_require)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name); + void (*hook_api_delete_api)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result); + void (*hook_api_on_event_handler_before)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); + void (*hook_api_on_event_handler_after)(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); +}; -extern int afb_hook_flags_svc(const char *api); -extern struct afb_hook_svc *afb_hook_create_svc(const char *api, int flags, struct afb_hook_svc_itf *itf, void *closure); -extern struct afb_hook_svc *afb_hook_addref_svc(struct afb_hook_svc *hook); -extern void afb_hook_unref_svc(struct afb_hook_svc *hook); +extern void afb_hook_api_event_broadcast_before(const struct afb_export *export, const char *name, struct json_object *object); +extern int afb_hook_api_event_broadcast_after(const struct afb_export *export, const char *name, struct json_object *object, int result); +extern struct sd_event *afb_hook_api_get_event_loop(const struct afb_export *export, struct sd_event *result); +extern struct sd_bus *afb_hook_api_get_user_bus(const struct afb_export *export, struct sd_bus *result); +extern struct sd_bus *afb_hook_api_get_system_bus(const struct afb_export *export, struct sd_bus *result); +extern void afb_hook_api_vverbose(const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args); +extern struct afb_event_x2 *afb_hook_api_event_make(const struct afb_export *export, const char *name, struct afb_event_x2 *result); +extern int afb_hook_api_rootdir_get_fd(const struct afb_export *export, int result); +extern int afb_hook_api_rootdir_open_locale(const struct afb_export *export, const char *filename, int flags, const char *locale, int result); +extern int afb_hook_api_queue_job(const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result); +extern void afb_hook_api_legacy_unstore_req(const struct afb_export *export, struct afb_stored_req *sreq); +extern void afb_hook_api_require_api(const struct afb_export *export, const char *name, int initialized); +extern int afb_hook_api_require_api_result(const struct afb_export *export, const char *name, int initialized, int result); +extern int afb_hook_api_add_alias(const struct afb_export *export, const char *api, const char *alias, int result); +extern void afb_hook_api_start_before(const struct afb_export *export); +extern int afb_hook_api_start_after(const struct afb_export *export, int status); +extern void afb_hook_api_on_event_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object); +extern void afb_hook_api_on_event_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object); +extern void afb_hook_api_call(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); +extern void afb_hook_api_call_result(const struct afb_export *export, struct json_object *object, const char *error, const char *info); +extern void afb_hook_api_callsync(const struct afb_export *export, const char *api, const char *verb, struct json_object *args); +extern int afb_hook_api_callsync_result(const struct afb_export *export, int result, struct json_object *object, const char *error, const char *info); +extern void afb_hook_api_new_api_before(const struct afb_export *export, const char *api, const char *info, int noconcurrency); +extern int afb_hook_api_new_api_after(const struct afb_export *export, int result, const char *api); +extern int afb_hook_api_api_set_verbs_v2(const struct afb_export *export, int result, const struct afb_verb_v2 *verbs); +extern int afb_hook_api_api_set_verbs_v3(const struct afb_export *export, int result, const struct afb_verb_v3 *verbs); +extern int afb_hook_api_api_add_verb(const struct afb_export *export, int result, const char *verb, const char *info, int glob); +extern int afb_hook_api_api_del_verb(const struct afb_export *export, int result, const char *verb); +extern int afb_hook_api_api_set_on_event(const struct afb_export *export, int result); +extern int afb_hook_api_api_set_on_init(const struct afb_export *export, int result); +extern void afb_hook_api_api_seal(const struct afb_export *export); +extern int afb_hook_api_event_handler_add(const struct afb_export *export, int result, const char *pattern); +extern int afb_hook_api_event_handler_del(const struct afb_export *export, int result, const char *pattern); +extern int afb_hook_api_class_provide(const struct afb_export *export, int result, const char *name); +extern int afb_hook_api_class_require(const struct afb_export *export, int result, const char *name); +extern int afb_hook_api_delete_api(const struct afb_export *export, int result); +extern void afb_hook_api_on_event_handler_before(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); +extern void afb_hook_api_on_event_handler_after(const struct afb_export *export, const char *event, int event_x2, struct json_object *object, const char *pattern); + +extern int afb_hook_flags_api(const char *api); +extern struct afb_hook_api *afb_hook_create_api(const char *api, int flags, struct afb_hook_api_itf *itf, void *closure); +extern struct afb_hook_api *afb_hook_addref_api(struct afb_hook_api *hook); +extern void afb_hook_unref_api(struct afb_hook_api *hook); /********************************************************* * section hooking evt (event interface) @@ -384,3 +454,4 @@ extern struct afb_hook_global *afb_hook_create_global(int flags, struct afb_hook extern struct afb_hook_global *afb_hook_addref_global(struct afb_hook_global *hook); extern void afb_hook_unref_global(struct afb_hook_global *hook); + diff --git a/src/afb-hreq.c b/src/afb-hreq.c index 012debbd..e5dcf642 100644 --- a/src/afb-hreq.c +++ b/src/afb-hreq.c @@ -73,15 +73,13 @@ struct hreq_data { static struct json_object *req_json(struct afb_xreq *xreq); static struct afb_arg req_get(struct afb_xreq *xreq, const char *name); -static void req_fail(struct afb_xreq *xreq, const char *status, const char *info); -static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info); +static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); static void req_destroy(struct afb_xreq *xreq); const struct afb_xreq_query_itf afb_hreq_xreq_query_itf = { .json = req_json, .get = req_get, - .success = req_success, - .fail = req_fail, + .reply = req_reply, .unref = req_destroy }; @@ -332,8 +330,8 @@ static void req_destroy(struct afb_xreq *xreq) } afb_context_disconnect(&hreq->xreq.context); json_object_put(hreq->json); - free((char*)hreq->xreq.request.api); - free((char*)hreq->xreq.request.verb); + free((char*)hreq->xreq.request.called_api); + free((char*)hreq->xreq.request.called_verb); afb_cred_unref(hreq->xreq.cred); free(hreq); } @@ -900,39 +898,32 @@ static ssize_t send_json_cb(json_object *obj, uint64_t pos, char *buf, size_t ma return len ? : (ssize_t)MHD_CONTENT_READER_END_OF_STREAM; } -static void req_reply(struct afb_hreq *hreq, unsigned retcode, const char *status, const char *info, json_object *resp) +static void req_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - struct json_object *reply; + struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); + struct json_object *sub, *reply; const char *reqid; struct MHD_Response *response; + /* create the reply */ + reply = afb_msg_json_reply(object, error, info, &xreq->context); + + /* append the req id on need */ reqid = afb_hreq_get_argument(hreq, long_key_for_reqid); if (reqid == NULL) reqid = afb_hreq_get_argument(hreq, short_key_for_reqid); - - reply = afb_msg_json_reply(status, info, resp, &hreq->xreq.context, reqid); + if (reqid != NULL && json_object_object_get_ex(reply, "request", &sub)) + json_object_object_add(sub, "reqid", json_object_new_string(reqid)); response = MHD_create_response_from_callback((uint64_t)strlen(json_object_to_json_string_ext(reply, JSON_C_TO_STRING_PLAIN)), SIZE_RESPONSE_BUFFER, (void*)send_json_cb, reply, (void*)json_object_put); - afb_hreq_reply(hreq, retcode, response, NULL); -} - -static void req_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); - req_reply(hreq, MHD_HTTP_OK, status, info, NULL); -} - -static void req_success(struct afb_xreq *xreq, json_object *obj, const char *info) -{ - struct afb_hreq *hreq = CONTAINER_OF_XREQ(struct afb_hreq, xreq); - req_reply(hreq, MHD_HTTP_OK, "success", info, obj); + afb_hreq_reply(hreq, MHD_HTTP_OK, response, NULL); } 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.request.api = strndup(api, lenapi); - hreq->xreq.request.verb = strndup(verb, lenverb); - if (hreq->xreq.request.api == NULL || hreq->xreq.request.verb == NULL) { + hreq->xreq.request.called_api = strndup(api, lenapi); + hreq->xreq.request.called_verb = strndup(verb, lenverb); + if (hreq->xreq.request.called_api == NULL || hreq->xreq.request.called_verb == NULL) { ERROR("Out of memory"); afb_hreq_reply_error(hreq, MHD_HTTP_INTERNAL_SERVER_ERROR); } else if (afb_hreq_init_context(hreq) < 0) { diff --git a/src/afb-monitor.c b/src/afb-monitor.c index 18ea606b..a50e2c65 100644 --- a/src/afb-monitor.c +++ b/src/afb-monitor.c @@ -21,12 +21,12 @@ #include <json-c/json.h> -#define AFB_BINDING_VERSION 0 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> #include "afb-api.h" #include "afb-apiset.h" -#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-evt.h" #include "afb-xreq.h" #include "afb-trace.h" @@ -36,13 +36,12 @@ #include "monitor-api.inc" -extern struct afb_apiset *main_apiset; +static struct afb_apiset *target_set; -static struct afb_binding_data_v2 datav2; - -int afb_monitor_init() +int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set) { - return afb_api_so_v2_add_binding(&_afb_binding_v2_monitor, NULL, main_apiset, &datav2); + target_set = call_set; + return -!afb_api_v3_from_binding(&_afb_binding_monitor, declare_set, call_set); } /****************************************************************************** @@ -66,28 +65,28 @@ static int decode_verbosity(struct json_object *v) int level = -1; if (!wrap_json_unpack(v, "i", &level)) { - level = level < Verbosity_Level_Error ? Verbosity_Level_Error : level > Verbosity_Level_Debug ? Verbosity_Level_Debug : level; + level = level < _VERBOSITY_(Log_Level_Error) ? _VERBOSITY_(Log_Level_Error) : level > _VERBOSITY_(Log_Level_Debug) ? _VERBOSITY_(Log_Level_Debug) : level; } else if (!wrap_json_unpack(v, "s", &s)) { switch(*s&~' ') { case 'D': if (!strcasecmp(s, _debug_)) - level = Verbosity_Level_Debug; + level = _VERBOSITY_(Log_Level_Debug); break; case 'I': if (!strcasecmp(s, _info_)) - level = Verbosity_Level_Info; + level = _VERBOSITY_(Log_Level_Info); break; case 'N': if (!strcasecmp(s, _notice_)) - level = Verbosity_Level_Notice; + level = _VERBOSITY_(Log_Level_Notice); break; case 'W': if (!strcasecmp(s, _warning_)) - level = Verbosity_Level_Warning; + level = _VERBOSITY_(Log_Level_Warning); break; case 'E': if (!strcasecmp(s, _error_)) - level = Verbosity_Level_Error; + level = _VERBOSITY_(Log_Level_Error); break; } } @@ -100,9 +99,10 @@ static int decode_verbosity(struct json_object *v) * @param the name of the api to set * @param closure the verbosity to set as an integer casted to a pointer */ -static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void set_verbosity_to_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { - afb_apiset_set_verbosity(set, name, (int)(intptr_t)closure); + if (!isalias) + afb_apiset_set_logmask(set, name, (int)(intptr_t)closure); } /** @@ -112,12 +112,13 @@ static void set_verbosity_to_all_cb(struct afb_apiset *set, const char *name, vo */ static void set_verbosity_to(const char *name, int level) { + int mask = verbosity_to_mask(level); if (!name || !name[0]) - verbosity = level; + verbosity_set(level); else if (name[0] == '*' && !name[1]) - afb_apiset_enum(main_apiset, 1, set_verbosity_to_all_cb, (void*)(intptr_t)level); + afb_apiset_enum(target_set, 1, set_verbosity_to_all_cb, (void*)(intptr_t)mask); else - afb_apiset_set_verbosity(main_apiset, name, level); + afb_apiset_set_logmask(target_set, name, mask); } /** @@ -154,12 +155,12 @@ static void set_verbosity(struct json_object *spec) */ static struct json_object *encode_verbosity(int level) { - switch(level) { - case Verbosity_Level_Error: return json_object_new_string(_error_); - case Verbosity_Level_Warning: return json_object_new_string(_warning_); - case Verbosity_Level_Notice: return json_object_new_string(_notice_); - case Verbosity_Level_Info: return json_object_new_string(_info_); - case Verbosity_Level_Debug: return json_object_new_string(_debug_); + switch(_DEVERBOSITY_(level)) { + case Log_Level_Error: return json_object_new_string(_error_); + case Log_Level_Warning: return json_object_new_string(_warning_); + case Log_Level_Notice: return json_object_new_string(_notice_); + case Log_Level_Info: return json_object_new_string(_info_); + case Log_Level_Debug: return json_object_new_string(_debug_); default: return json_object_new_int(level); } } @@ -170,12 +171,12 @@ static struct json_object *encode_verbosity(int level) * @param the name of the api to set * @param closure the json object to build */ -static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void get_verbosity_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { struct json_object *resu = closure; - int l = afb_apiset_get_verbosity(set, name); - if (l >= 0) - json_object_object_add(resu, name, encode_verbosity(l)); + int m = afb_apiset_get_logmask(set, name); + if (m >= 0) + json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m))); } /** @@ -185,15 +186,15 @@ static void get_verbosity_of_all_cb(struct afb_apiset *set, const char *name, vo */ static void get_verbosity_of(struct json_object *resu, const char *name) { - int l; + int m; if (!name || !name[0]) - json_object_object_add(resu, "", encode_verbosity(verbosity)); + json_object_object_add(resu, "", encode_verbosity(verbosity_get())); else if (name[0] == '*' && !name[1]) - afb_apiset_enum(main_apiset, 1, get_verbosity_of_all_cb, resu); + afb_apiset_enum(target_set, 1, get_verbosity_of_all_cb, resu); else { - l = afb_apiset_get_verbosity(main_apiset, name); - if (l >= 0) - json_object_object_add(resu, name, encode_verbosity(l)); + m = afb_apiset_get_logmask(target_set, name); + if (m >= 0) + json_object_object_add(resu, name, encode_verbosity(verbosity_from_mask(m))); } } @@ -242,8 +243,8 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_ { struct json_object *o; - o = afb_apiset_describe(main_apiset, name); - if (o || afb_apiset_lookup(main_apiset, name, 1)) + o = afb_apiset_describe(target_set, name); + if (o || afb_apiset_lookup(target_set, name, 1)) json_object_object_add(resu, name, o); } @@ -253,7 +254,7 @@ static void get_one_api(struct json_object *resu, const char *name, struct json_ * @param the name of the api to set * @param closure the json object to build */ -static void get_apis_of_all_cb(struct afb_apiset *set, const char *name, void *closure) +static void get_apis_of_all_cb(void *closure, struct afb_apiset *set, const char *name, int isalias) { struct json_object *resu = closure; get_one_api(resu, name, NULL); @@ -285,7 +286,7 @@ static struct json_object *get_apis(struct json_object *spec) } else if (json_object_is_type(spec, json_type_string)) { get_one_api(resu, json_object_get_string(spec), NULL); } else if (json_object_get_boolean(spec)) { - afb_apiset_enum(main_apiset, 1, get_apis_of_all_cb, resu); + afb_apiset_enum(target_set, 1, get_apis_of_all_cb, resu); } return resu; } @@ -298,7 +299,7 @@ static const char _verbosity_[] = "verbosity"; static const char _apis_[] = "apis"; static const char _refresh_token_[] = "refresh-token"; -static void f_get(struct afb_req req) +static void f_get(afb_req_t req) { struct json_object *r; struct json_object *apis = NULL; @@ -314,7 +315,7 @@ static void f_get(struct afb_req req) afb_req_success(req, r, NULL); } -static void f_set(struct afb_req req) +static void f_set(afb_req_t req) { struct json_object *verbosity = NULL; @@ -325,9 +326,9 @@ static void f_set(struct afb_req req) afb_req_success(req, NULL, NULL); } -static void *context_create() +static void *context_create(void *closure) { - return afb_trace_create(_afb_binding_v2_monitor.api, NULL); + return afb_trace_create(_afb_binding_monitor.api, NULL); } static void context_destroy(void *pointer) @@ -336,14 +337,14 @@ static void context_destroy(void *pointer) afb_trace_unref(trace); } -static void f_trace(struct afb_req req) +static void f_trace(afb_req_t req) { int rc; struct json_object *add = NULL; struct json_object *drop = NULL; struct afb_trace *trace; - trace = afb_req_context(req, context_create, context_destroy); + trace = afb_req_context(req, 0, context_create, context_destroy, NULL); wrap_json_unpack(afb_req_json(req), "{s?o s?o}", "add", &add, "drop", &drop); if (add) { rc = afb_trace_add(req, add, trace); @@ -357,15 +358,15 @@ static void f_trace(struct afb_req req) } afb_req_success(req, NULL, NULL); end: - afb_apiset_update_hooks(main_apiset, NULL); + afb_apiset_update_hooks(target_set, NULL); afb_evt_update_hooks(); } -static void f_session(struct afb_req req) +static void f_session(afb_req_t req) { struct json_object *r = NULL; int refresh = 0; - struct afb_xreq *xreq = xreq_from_request(req.closure); + struct afb_xreq *xreq = xreq_from_req_x2(req); /* check right to call it */ if (xreq->context.super) { @@ -387,4 +388,3 @@ static void f_session(struct afb_req req) afb_req_success(req, r, NULL); } - diff --git a/src/afb-monitor.h b/src/afb-monitor.h index 1f3c1446..407116d2 100644 --- a/src/afb-monitor.h +++ b/src/afb-monitor.h @@ -18,4 +18,6 @@ #pragma once -extern int afb_monitor_init(); +struct afb_apiset; + +extern int afb_monitor_init(struct afb_apiset *declare_set, struct afb_apiset *call_set); diff --git a/src/afb-msg-json.c b/src/afb-msg-json.c index 7597f80f..ceeee1a4 100644 --- a/src/afb-msg-json.c +++ b/src/afb-msg-json.c @@ -22,7 +22,9 @@ #include "afb-msg-json.h" #include "afb-context.h" -struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid) +static const char _success_[] = "success"; + +struct json_object *afb_msg_json_reply(struct json_object *resp, const char *error, const char *info, struct afb_context *context) { json_object *msg, *request; const char *token, *uuid; @@ -37,14 +39,11 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str request = json_object_new_object(); json_object_object_add(msg, "request", request); - json_object_object_add(request, "status", json_object_new_string(status)); + json_object_object_add(request, "status", json_object_new_string(error ?: _success_)); if (info != NULL) json_object_object_add(request, "info", json_object_new_string(info)); - if (reqid != NULL) - json_object_object_add(request, "reqid", json_object_new_string(reqid)); - if (context != NULL) { token = afb_context_sent_token(context); if (token != NULL) @@ -58,16 +57,6 @@ struct json_object *afb_msg_json_reply(const char *status, const char *info, str return msg; } -struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid) -{ - return afb_msg_json_reply("success", info, resp, context, reqid); -} - -struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid) -{ - return afb_msg_json_reply(status, info, NULL, context, reqid); -} - struct json_object *afb_msg_json_event(const char *event, struct json_object *object) { json_object *msg; @@ -88,7 +77,7 @@ struct json_object *afb_msg_json_event(const char *event, struct json_object *ob struct json_object *afb_msg_json_internal_error() { - return afb_msg_json_reply_error("failed", "internal error", NULL, NULL); + return afb_msg_json_reply(NULL, "failed", "internal error", NULL); } diff --git a/src/afb-msg-json.h b/src/afb-msg-json.h index e18ca0a9..ee3ed20c 100644 --- a/src/afb-msg-json.h +++ b/src/afb-msg-json.h @@ -21,9 +21,7 @@ struct json_object; struct afb_context; struct afb_arg; -extern struct json_object *afb_msg_json_reply(const char *status, const char *info, struct json_object *resp, struct afb_context *context, const char *reqid); -extern struct json_object *afb_msg_json_reply_ok(const char *info, struct json_object *resp, struct afb_context *context, const char *reqid); -extern struct json_object *afb_msg_json_reply_error(const char *status, const char *info, struct afb_context *context, const char *reqid); +extern struct json_object *afb_msg_json_reply(struct json_object *resp, const char *status, const char *info, struct afb_context *context); extern struct json_object *afb_msg_json_event(const char *event, struct json_object *object); diff --git a/src/afb-proto-ws.c b/src/afb-proto-ws.c index e1993abe..f9313545 100644 --- a/src/afb-proto-ws.c +++ b/src/afb-proto-ws.c @@ -61,8 +61,6 @@ The server must reply to the previous actions by The server can also within the context of a call - - make a subcall - - subscribe or unsubscribe an event For the purpose of handling events the server can: @@ -75,42 +73,17 @@ For the purpose of handling events the server can: /************** constants for protocol definition *************************/ #define CHAR_FOR_CALL 'C' -#define CHAR_FOR_ANSWER_SUCCESS 'T' -#define CHAR_FOR_ANSWER_FAIL 'F' +#define CHAR_FOR_REPLY 'Y' #define CHAR_FOR_EVT_BROADCAST '*' #define CHAR_FOR_EVT_ADD '+' #define CHAR_FOR_EVT_DEL '-' #define CHAR_FOR_EVT_PUSH '!' #define CHAR_FOR_EVT_SUBSCRIBE 'S' #define CHAR_FOR_EVT_UNSUBSCRIBE 'U' -#define CHAR_FOR_SUBCALL_CALL 'B' -#define CHAR_FOR_SUBCALL_REPLY 'R' #define CHAR_FOR_DESCRIBE 'D' #define CHAR_FOR_DESCRIPTION 'd' -/******************* handling subcalls *****************************/ - -/** - * Structure on server side for recording pending - * subcalls. - */ -struct server_subcall -{ - struct server_subcall *next; /**< next subcall for the client */ - uint32_t subcallid; /**< the subcallid */ - void (*callback)(void*, int, struct json_object*); /**< callback on completion */ - void *closure; /**< closure of the callback */ -}; - -/** - * Structure for sending back replies on client side - */ -struct afb_proto_ws_subcall -{ - struct afb_proto_ws *protows; /**< proto descriptor */ - void *buffer; - uint32_t subcallid; /**< subcallid for the reply */ -}; +/******************* handling calls *****************************/ /* * structure for recording calls on client side @@ -182,9 +155,6 @@ struct afb_proto_ws /* emitted calls (client side) */ struct client_call *calls; - /* pending subcalls (server side) */ - struct server_subcall *subcalls; - /* pending description (client side) */ struct client_describe *describes; @@ -237,6 +207,7 @@ static char *readbuf_get(struct readbuf *rb, uint32_t length) return before; } +__attribute__((unused)) static int readbuf_char(struct readbuf *rb, char *value) { if (rb->head >= rb->end) @@ -256,16 +227,35 @@ static int readbuf_uint32(struct readbuf *rb, uint32_t *value) return 1; } -static int readbuf_string(struct readbuf *rb, const char **value, size_t *length) +static int _readbuf_string_(struct readbuf *rb, const char **value, size_t *length, int nulok) { uint32_t len; - if (!readbuf_uint32(rb, &len) || !len) + if (!readbuf_uint32(rb, &len)) return 0; + if (!len) { + if (!nulok) + return 0; + *value = NULL; + if (length) + *length = 0; + return 1; + } if (length) *length = (size_t)(len - 1); return (*value = readbuf_get(rb, len)) != NULL && rb->head[-1] == 0; } + +static int readbuf_string(struct readbuf *rb, const char **value, size_t *length) +{ + return _readbuf_string_(rb, value, length, 0); +} + +static int readbuf_nullstring(struct readbuf *rb, const char **value, size_t *length) +{ + return _readbuf_string_(rb, value, length, 1); +} + static int readbuf_object(struct readbuf *rb, struct json_object **object) { const char *string; @@ -326,6 +316,11 @@ static int writebuf_string(struct writebuf *wb, const char *value) return writebuf_string_length(wb, value, strlen(value)); } +static int writebuf_nullstring(struct writebuf *wb, const char *value) +{ + return value ? writebuf_string_length(wb, value, strlen(value)) : writebuf_uint32(wb, 0); +} + static int writebuf_object(struct writebuf *wb, struct json_object *object) { const char *string = json_object_to_json_string_ext(object, JSON_C_TO_STRING_PLAIN); @@ -349,15 +344,16 @@ void afb_proto_ws_call_unref(struct afb_proto_ws_call *call) free(call); } -int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info) +int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info) { int rc = -1; struct writebuf wb = { .count = 0 }; struct afb_proto_ws *protows = call->protows; - if (writebuf_char(&wb, CHAR_FOR_ANSWER_SUCCESS) + if (writebuf_char(&wb, CHAR_FOR_REPLY) && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, info ?: "") + && writebuf_nullstring(&wb, error) + && writebuf_nullstring(&wb, info) && writebuf_object(&wb, obj)) { pthread_mutex_lock(&protows->mutex); rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); @@ -371,73 +367,6 @@ success: return rc; } -int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info) -{ - int rc = -1; - struct writebuf wb = { .count = 0 }; - struct afb_proto_ws *protows = call->protows; - - if (writebuf_char(&wb, CHAR_FOR_ANSWER_FAIL) - && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, status) - && writebuf_string(&wb, info ? : "")) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) { - rc = 0; - goto success; - } - } -success: - return rc; -} - -int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - int rc = -1; - struct writebuf wb = { .count = 0 }; - struct server_subcall *sc, *osc; - struct afb_proto_ws *protows = call->protows; - - sc = malloc(sizeof *sc); - if (!sc) - errno = ENOMEM; - else { - sc->callback = callback; - sc->closure = cb_closure; - - pthread_mutex_lock(&protows->mutex); - sc->subcallid = ptr2id(sc); - do { - sc->subcallid++; - osc = protows->subcalls; - while(osc && osc->subcallid != sc->subcallid) - osc = osc->next; - } while (osc); - sc->next = protows->subcalls; - protows->subcalls = sc; - pthread_mutex_unlock(&protows->mutex); - - if (writebuf_char(&wb, CHAR_FOR_SUBCALL_CALL) - && writebuf_uint32(&wb, sc->subcallid) - && writebuf_uint32(&wb, call->callid) - && writebuf_string(&wb, api) - && writebuf_string(&wb, verb) - && writebuf_object(&wb, args)) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) { - rc = 0; - goto success; - } - } - } -success: - return rc; -} - int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id) { int rc = -1; @@ -613,113 +542,23 @@ static void client_on_event_push(struct afb_proto_ws *protows, struct readbuf *r protows->client_itf->on_event_push(protows->closure, event_name, (int)event_id, object); } -static void client_on_reply_success(struct afb_proto_ws *protows, struct readbuf *rb) +static void client_on_reply(struct afb_proto_ws *protows, struct readbuf *rb) { struct client_call *call; struct json_object *object; - const char *info; - - if (!client_msg_call_get(protows, rb, &call)) - return; - - if (readbuf_string(rb, &info, NULL) && readbuf_object(rb, &object)) { - protows->client_itf->on_reply_success(protows->closure, call->request, object, info); - } else { - protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process success"); - } - client_call_destroy(call); -} - -static void client_on_reply_fail(struct afb_proto_ws *protows, struct readbuf *rb) -{ - struct client_call *call; - const char *info, *status; + const char *error, *info; if (!client_msg_call_get(protows, rb, &call)) return; - - if (readbuf_string(rb, &status, NULL) && readbuf_string(rb, &info, NULL)) { - protows->client_itf->on_reply_fail(protows->closure, call->request, status, info); + if (readbuf_nullstring(rb, &error, NULL) && readbuf_nullstring(rb, &info, NULL) && readbuf_object(rb, &object)) { + protows->client_itf->on_reply(protows->closure, call->request, object, error, info); } else { - protows->client_itf->on_reply_fail(protows->closure, call->request, "proto-error", "can't process fail"); + protows->client_itf->on_reply(protows->closure, call->request, NULL, "proto-error", "can't process success"); } client_call_destroy(call); } -/* send a subcall reply */ -static int client_send_subcall_reply(struct afb_proto_ws *protows, uint32_t subcallid, int status, json_object *object) -{ - struct writebuf wb = { .count = 0 }; - char ie = status < 0; - int rc; - - if (writebuf_char(&wb, CHAR_FOR_SUBCALL_REPLY) - && writebuf_uint32(&wb, subcallid) - && writebuf_char(&wb, ie) - && writebuf_object(&wb, object)) { - pthread_mutex_lock(&protows->mutex); - rc = afb_ws_binary_v(protows->ws, wb.iovec, wb.count); - pthread_mutex_unlock(&protows->mutex); - if (rc >= 0) - return 0; - } - return -1; -} - -/* callback for subcall reply */ -int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result) -{ - int rc = client_send_subcall_reply(subcall->protows, subcall->subcallid, status, result); - afb_proto_ws_unref(subcall->protows); - free(subcall->buffer); - free(subcall); - return rc; -} - -/* received a subcall request */ -static void client_on_subcall(struct afb_proto_ws *protows, struct readbuf *rb) -{ - struct afb_proto_ws_subcall *subcall; - struct client_call *call; - const char *api, *verb; - uint32_t subcallid; - struct json_object *object; - - /* get the subcallid */ - if (!readbuf_uint32(rb, &subcallid)) - return; - - /* if not expected drop it */ - if (!protows->client_itf->on_subcall) - goto error; - - /* retrieve the message data */ - if (!client_msg_call_get(protows, rb, &call)) - goto error; - - /* allocation of the subcall */ - subcall = malloc(sizeof *subcall); - if (!subcall) - goto error; - - /* make the call */ - if (readbuf_string(rb, &api, NULL) - && readbuf_string(rb, &verb, NULL) - && readbuf_object(rb, &object)) { - afb_proto_ws_addref(protows); - subcall->protows = protows; - subcall->subcallid = subcallid; - subcall->buffer = rb->base; - rb->base = NULL; - protows->client_itf->on_subcall(protows->closure, subcall, call->request, api, verb, object); - return; - } - free(subcall); -error: - client_send_subcall_reply(protows, subcallid, 1, NULL); -} - static void client_on_description(struct afb_proto_ws *protows, struct readbuf *rb) { uint32_t descid; @@ -751,11 +590,8 @@ static void client_on_binary_job(int sig, void *closure) if (!sig) { switch (*binary->rb.head++) { - case CHAR_FOR_ANSWER_SUCCESS: /* success */ - client_on_reply_success(binary->protows, &binary->rb); - break; - case CHAR_FOR_ANSWER_FAIL: /* fail */ - client_on_reply_fail(binary->protows, &binary->rb); + case CHAR_FOR_REPLY: /* reply */ + client_on_reply(binary->protows, &binary->rb); break; case CHAR_FOR_EVT_BROADCAST: /* broadcast */ client_on_event_broadcast(binary->protows, &binary->rb); @@ -775,9 +611,6 @@ static void client_on_binary_job(int sig, void *closure) case CHAR_FOR_EVT_UNSUBSCRIBE: /* unsubscribe event for a request */ client_on_event_unsubscribe(binary->protows, &binary->rb); break; - case CHAR_FOR_SUBCALL_CALL: /* subcall */ - client_on_subcall(binary->protows, &binary->rb); - break; case CHAR_FOR_DESCRIPTION: /* description */ client_on_description(binary->protows, &binary->rb); break; @@ -819,7 +652,8 @@ int afb_proto_ws_client_call( const char *verb, struct json_object *args, const char *sessionid, - void *request + void *request, + const char *user_creds ) { int rc = -1; @@ -849,7 +683,8 @@ int afb_proto_ws_client_call( || !writebuf_uint32(&wb, call->callid) || !writebuf_string(&wb, verb) || !writebuf_string(&wb, sessionid) - || !writebuf_object(&wb, args)) { + || !writebuf_object(&wb, args) + || !writebuf_nullstring(&wb, user_creds)) { errno = EINVAL; goto clean; } @@ -929,7 +764,7 @@ error: static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) { struct afb_proto_ws_call *call; - const char *uuid, *verb; + const char *uuid, *verb, *user_creds; uint32_t callid; size_t lenverb; struct json_object *object; @@ -940,7 +775,8 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) if (!readbuf_uint32(rb, &callid) || !readbuf_string(rb, &verb, &lenverb) || !readbuf_string(rb, &uuid, NULL) - || !readbuf_object(rb, &object)) + || !readbuf_object(rb, &object) + || !readbuf_nullstring(rb, &user_creds, NULL)) goto overflow; /* create the request */ @@ -954,7 +790,7 @@ static void server_on_call(struct afb_proto_ws *protows, struct readbuf *rb) call->buffer = rb->base; rb->base = NULL; /* don't free the buffer */ - protows->server_itf->on_call(protows->closure, call, verb, object, uuid); + protows->server_itf->on_call(protows->closure, call, verb, object, uuid, user_creds); return; out_of_memory: @@ -964,39 +800,6 @@ overflow: afb_proto_ws_unref(protows); } -/* on subcall reply */ -static void server_on_subcall_reply(struct afb_proto_ws *protows, struct readbuf *rb) -{ - char ie; - uint32_t subcallid; - struct json_object *object; - struct server_subcall *sc, **psc; - - /* reads the call message data */ - if (!readbuf_uint32(rb, &subcallid) - || !readbuf_char(rb, &ie) - || !readbuf_object(rb, &object)) { - /* TODO bad protocol */ - return; - } - - /* search the subcall and unlink it */ - pthread_mutex_lock(&protows->mutex); - psc = &protows->subcalls; - while ((sc = *psc) && sc->subcallid != subcallid) - psc = &sc->next; - if (!sc) { - pthread_mutex_unlock(&protows->mutex); - json_object_put(object); - /* TODO subcall not found */ - } else { - *psc = sc->next; - pthread_mutex_unlock(&protows->mutex); - sc->callback(sc->closure, -(int)ie, object); - free(sc); - } -} - static int server_send_description(struct afb_proto_ws *protows, uint32_t descid, struct json_object *descobj) { int rc; @@ -1055,9 +858,6 @@ static void server_on_binary_job(int sig, void *closure) case CHAR_FOR_CALL: server_on_call(binary->protows, &binary->rb); break; - case CHAR_FOR_SUBCALL_REPLY: - server_on_subcall_reply(binary->protows, &binary->rb); - break; case CHAR_FOR_DESCRIBE: server_on_describe(binary->protows, &binary->rb); break; @@ -1139,17 +939,8 @@ int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, const char static void on_hangup(void *closure) { struct afb_proto_ws *protows = closure; - struct server_subcall *sc, *nsc; struct client_describe *cd, *ncd; - nsc = protows->subcalls; - while (nsc) { - sc= nsc; - nsc = sc->next; - sc->callback(sc->closure, 1, NULL); - free(sc); - } - ncd = protows->describes; while (ncd) { cd= ncd; @@ -1202,7 +993,6 @@ static struct afb_proto_ws *afb_proto_ws_create(struct fdev *fdev, const struct if (protows->ws != NULL) { protows->fdev = fdev; protows->refcount = 1; - protows->subcalls = NULL; protows->closure = closure; protows->server_itf = itfs; protows->client_itf = itfc; diff --git a/src/afb-proto-ws.h b/src/afb-proto-ws.h index d674af3d..342313e7 100644 --- a/src/afb-proto-ws.h +++ b/src/afb-proto-ws.h @@ -18,17 +18,21 @@ #pragma once +/* + * Defined since version 3, the value AFB_PROTO_WS_VERSION can be used to + * track versions of afb-proto-ws. + */ +#define AFB_PROTO_WS_VERSION 3 + struct fdev; struct afb_proto_ws; struct afb_proto_ws_call; -struct afb_proto_ws_subcall; struct afb_proto_ws_describe; struct afb_proto_ws_client_itf { /* can't be NULL */ - void (*on_reply_success)(void *closure, void *request, struct json_object *result, const char *info); - void (*on_reply_fail)(void *closure, void *request, const char *status, const char *info); + void (*on_reply)(void *closure, void *request, struct json_object *obj, const char *error, const char *info); /* can be NULL */ void (*on_event_create)(void *closure, const char *event_name, int event_id); @@ -37,13 +41,11 @@ struct afb_proto_ws_client_itf void (*on_event_unsubscribe)(void *closure, void *request, const char *event_name, int event_id); void (*on_event_push)(void *closure, const char *event_name, int event_id, struct json_object *data); void (*on_event_broadcast)(void *closure, const char *event_name, struct json_object *data); - - void (*on_subcall)(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args); }; struct afb_proto_ws_server_itf { - void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid); + void (*on_call)(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds); void (*on_describe)(void *closure, struct afb_proto_ws_describe *describe); }; @@ -61,7 +63,7 @@ extern void afb_proto_ws_on_hangup(struct afb_proto_ws *protows, void (*on_hangu -extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request); +extern int afb_proto_ws_client_call(struct afb_proto_ws *protows, const char *verb, struct json_object *args, const char *sessionid, void *request, const char *user_creds); extern int afb_proto_ws_client_describe(struct afb_proto_ws *protows, void (*callback)(void*, struct json_object*), void *closure); extern int afb_proto_ws_server_event_create(struct afb_proto_ws *protows, const char *event_name, int event_id); @@ -72,14 +74,9 @@ extern int afb_proto_ws_server_event_broadcast(struct afb_proto_ws *protows, con extern void afb_proto_ws_call_addref(struct afb_proto_ws_call *call); extern void afb_proto_ws_call_unref(struct afb_proto_ws_call *call); -extern int afb_proto_ws_call_success(struct afb_proto_ws_call *call, struct json_object *obj, const char *info); -extern int afb_proto_ws_call_fail(struct afb_proto_ws_call *call, const char *status, const char *info); +extern int afb_proto_ws_call_reply(struct afb_proto_ws_call *call, struct json_object *obj, const char *error, const char *info); -extern int afb_proto_ws_call_subcall(struct afb_proto_ws_call *call, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure); extern int afb_proto_ws_call_subscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id); extern int afb_proto_ws_call_unsubscribe(struct afb_proto_ws_call *call, const char *event_name, int event_id); -extern int afb_proto_ws_subcall_reply(struct afb_proto_ws_subcall *subcall, int status, struct json_object *result); - extern int afb_proto_ws_describe_put(struct afb_proto_ws_describe *describe, struct json_object *description); - diff --git a/src/afb-session.c b/src/afb-session.c index 8c0f77b8..16fc69bb 100644 --- a/src/afb-session.c +++ b/src/afb-session.c @@ -27,11 +27,10 @@ #include <uuid/uuid.h> #include <errno.h> -#include <json-c/json.h> - #include "afb-session.h" #include "afb-hook.h" #include "verbose.h" +#include "pearson.h" #define SIZEUUID 37 #define HEADCOUNT 16 @@ -43,41 +42,45 @@ #define MAX_EXPIRATION (_MAXEXP_ >= 0 ? _MAXEXP_ : _MAXEXP2_) #define NOW (time_now()) -/* structure for a cookie added to sessions */ +/** + * structure for a cookie added to sessions + */ struct cookie { - struct cookie *next; /* link to next cookie */ - const void *key; /* pointer key */ - void *value; /* value */ - void (*freecb)(void*); /* function to call when session is closed */ + struct cookie *next; /**< link to next cookie */ + const void *key; /**< pointer key */ + void *value; /**< value */ + void (*freecb)(void*); /**< function to call when session is closed */ }; -/* +/** * structure for session */ struct afb_session { - struct afb_session *next; /* link to the next */ - unsigned refcount; /* external reference count of the session */ - int timeout; /* timeout of the session */ - time_t expiration; /* expiration time of the token */ - pthread_mutex_t mutex; /* mutex of the session */ - struct cookie *cookies[COOKIECOUNT]; /* cookies of the session */ - uint8_t closed: 1; /* is the session closed ? */ - uint8_t autoclose: 1; /* close the session when unreferenced */ - uint8_t notinset: 1; /* session removed from the set of sessions */ - char uuid[SIZEUUID]; /* long term authentication of remote client */ - char token[SIZEUUID]; /* short term authentication of remote client */ + struct afb_session *next; /**< link to the next */ + unsigned refcount; /**< external reference count of the session */ + int timeout; /**< timeout of the session */ + time_t expiration; /**< expiration time of the token */ + pthread_mutex_t mutex; /**< mutex of the session */ + struct cookie *cookies[COOKIECOUNT]; /**< cookies of the session */ + uint8_t closed: 1; /**< is the session closed ? */ + uint8_t autoclose: 1; /**< close the session when unreferenced */ + uint8_t notinset: 1; /**< session removed from the set of sessions */ + char uuid[SIZEUUID]; /**< long term authentication of remote client */ + char token[SIZEUUID]; /**< short term authentication of remote client */ }; -/* Session UUID are store in a simple array [for 10 sessions this should be enough] */ +/** + * structure for managing sessions + */ static struct { - int count; /* current number of sessions */ - int max; /* maximum count of sessions */ - int timeout; /* common initial timeout */ - struct afb_session *heads[HEADCOUNT]; /* sessions */ - char initok[SIZEUUID]; /* common initial token */ - pthread_mutex_t mutex; /* declare a mutex to protect hash table */ + int count; /**< current number of sessions */ + int max; /**< maximum count of sessions */ + int timeout; /**< common initial timeout */ + struct afb_session *heads[HEADCOUNT]; /**< sessions */ + char initok[SIZEUUID]; /**< common initial token */ + pthread_mutex_t mutex; /**< declare a mutex to protect hash table */ } sessions = { .count = 0, .max = 10, @@ -87,7 +90,9 @@ static struct { .mutex = PTHREAD_MUTEX_INITIALIZER }; -/* Get the actual raw time */ +/** + * Get the actual raw time + */ static inline time_t time_now() { struct timespec ts; @@ -95,7 +100,9 @@ static inline time_t time_now() return ts.tv_sec; } -/* generate a new fresh 'uuid' */ +/** + * generate a new fresh 'uuid' + */ static void new_uuid(char uuid[SIZEUUID]) { uuid_t newuuid; @@ -103,26 +110,6 @@ static void new_uuid(char uuid[SIZEUUID]) uuid_unparse_lower(newuuid, uuid); } -/* - * Returns a tiny hash value for the 'text'. - * - * Tiny hash function inspired from pearson - */ -static uint8_t pearson4(const char *text) -{ - static uint8_t T[16] = { - 4, 1, 6, 0, 9, 14, 11, 5, - 2, 3, 12, 15, 10, 7, 8, 13 - }; - uint8_t r, c; - - for (r = 0; (c = (uint8_t)*text) ; text++) { - r = T[r ^ (15 & c)]; - r = T[r ^ (c >> 4)]; - } - return r; // % HEADCOUNT; -} - /* lock the set of sessions for exclusive access */ static inline void sessionset_lock() { @@ -155,7 +142,7 @@ static struct afb_session *sessionset_search(const char *uuid, uint8_t hashidx) static int sessionset_add(struct afb_session *session, uint8_t hashidx) { /* check availability */ - if (sessions.count >= sessions.max) { + if (sessions.max && sessions.count >= sessions.max) { errno = EBUSY; return -1; } @@ -321,7 +308,7 @@ static time_t sessionset_cleanup (int force) * @param max_session_count maximum allowed session count in the same time * @param timeout the initial default timeout of sessions * @param initok the initial default token of sessions - * + * */ int afb_session_init (int max_session_count, int timeout, const char *initok) { @@ -513,7 +500,7 @@ void afb_session_close (struct afb_session *session) * Set the 'autoclose' flag of the 'session' * * A session whose autoclose flag is true will close as - * soon as it is no more referenced. + * soon as it is no more referenced. * * @param session the session to set * @param autoclose the value to set @@ -694,8 +681,7 @@ void *afb_session_get_cookie(struct afb_session *session, const void *key) * @param value the value to store at key * @param freecb a function to use when the cookie value is to remove (or null) * - * @return the data staored for the key or NULL if the key isn't found - * + * @return 0 in case of success or -1 in case of error */ int afb_session_set_cookie(struct afb_session *session, const void *key, void *value, void (*freecb)(void*)) { diff --git a/src/afb-stub-ws.c b/src/afb-stub-ws.c index e725d5ad..68bc8c7c 100644 --- a/src/afb-stub-ws.c +++ b/src/afb-stub-ws.c @@ -34,7 +34,7 @@ #include <json-c/json.h> -#include <afb/afb-event.h> +#include <afb/afb-event-x2.h> #include "afb-session.h" #include "afb-cred.h" @@ -52,29 +52,6 @@ struct afb_stub_ws; -/******************* handling subcalls *****************************/ - -/** - * Structure on server side for recording pending - * subcalls. - */ -struct server_subcall -{ - struct server_subcall *next; /**< next subcall for the client */ - uint32_t subcallid; /**< the subcallid */ - void (*callback)(void*, int, struct json_object*); /**< callback on completion */ - void *closure; /**< closure of the callback */ -}; - -/** - * Structure for sending back replies on client side - */ -struct client_subcall -{ - struct afb_stub_ws *stubws; /**< stub descriptor */ - uint32_t subcallid; /**< subcallid for the reply */ -}; - /* * structure for recording calls on client side */ @@ -100,7 +77,7 @@ struct server_req { struct client_event { struct client_event *next; - struct afb_eventid *eventid; + struct afb_event_x2 *event; int id; int refcount; }; @@ -152,7 +129,7 @@ struct afb_stub_ws /* event replica (client side) */ struct client_event *events; - /* credentials (server side) */ + /* credentials of the client (server side) */ struct afb_cred *cred; /* sessions (server side) */ @@ -183,57 +160,37 @@ static void server_req_destroy_cb(struct afb_xreq *xreq) free(wreq); } -static void server_req_success_cb(struct afb_xreq *xreq, struct json_object *obj, const char *info) +static void server_req_reply_cb(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { int rc; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_success(wreq->call, obj, info); + rc = afb_proto_ws_call_reply(wreq->call, obj, error, info); if (rc < 0) - ERROR("error while sending success"); + ERROR("error while sending reply"); json_object_put(obj); } -static void server_req_fail_cb(struct afb_xreq *xreq, const char *status, const char *info) +static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) { int rc; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_fail(wreq->call, status, info); - if (rc < 0) - ERROR("error while sending fail"); -} - -static void server_req_subcall_cb(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - int rc; - struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - - rc = afb_proto_ws_call_subcall(wreq->call, api, verb, args, callback, cb_closure); - if (rc < 0) - ERROR("error while sending subcall"); -} - -static int server_req_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event) -{ - int rc; - struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - - rc = afb_evt_eventid_add_watch(wreq->stubws->listener, event); + rc = afb_evt_event_x2_add_watch(wreq->stubws->listener, event); if (rc >= 0) - rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event)); + rc = afb_proto_ws_call_subscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event)); if (rc < 0) ERROR("error while subscribing event"); return rc; } -static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *event) +static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_event_x2 *event) { int rc, rc2; struct server_req *wreq = CONTAINER_OF_XREQ(struct server_req, xreq); - rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_eventid_fullname(event), afb_evt_eventid_id(event)); - rc2 = afb_evt_eventid_remove_watch(wreq->stubws->listener, event); + rc = afb_proto_ws_call_unsubscribe(wreq->call, afb_evt_event_x2_fullname(event), afb_evt_event_x2_id(event)); + rc2 = afb_evt_event_x2_remove_watch(wreq->stubws->listener, event); if (rc >= 0 && rc2 < 0) rc = rc2; if (rc < 0) @@ -242,10 +199,8 @@ static int server_req_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid * } static const struct afb_xreq_query_itf server_req_xreq_itf = { - .success = server_req_success_cb, - .fail = server_req_fail_cb, + .reply = server_req_reply_cb, .unref = server_req_destroy_cb, - .subcall = server_req_subcall_cb, .subscribe = server_req_subscribe_cb, .unsubscribe = server_req_unsubscribe_cb }; @@ -258,7 +213,7 @@ static struct client_event *client_event_search(struct afb_stub_ws *stubws, uint struct client_event *ev; ev = stubws->events; - while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name))) + while (ev != NULL && (ev->id != eventid || 0 != strcmp(afb_evt_event_x2_fullname(ev->event), name))) ev = ev->next; return ev; @@ -269,7 +224,13 @@ static void client_call_cb(void * closure, struct afb_xreq *xreq) { struct afb_stub_ws *stubws = closure; - afb_proto_ws_client_call(stubws->proto, xreq->request.verb, afb_xreq_json(xreq), afb_session_uuid(xreq->context.session), xreq); + afb_proto_ws_client_call( + stubws->proto, + xreq->request.called_verb, + afb_xreq_json(xreq), + afb_session_uuid(xreq->context.session), + xreq, + xreq_on_behalf_cred_export(xreq)); afb_xreq_unhooked_addref(xreq); } @@ -339,19 +300,11 @@ static void server_event_broadcast(void *closure, const char *event, int eventid /*****************************************************/ -static void on_reply_success(void *closure, void *request, struct json_object *result, const char *info) -{ - struct afb_xreq *xreq = request; - - afb_xreq_success(xreq, result, *info ? info : NULL); - afb_xreq_unhooked_unref(xreq); -} - -static void on_reply_fail(void *closure, void *request, const char *status, const char *info) +static void on_reply(void *closure, void *request, struct json_object *object, const char *error, const char *info) { struct afb_xreq *xreq = request; - afb_xreq_fail(xreq, status, *info ? info : NULL); + afb_xreq_reply(xreq, object, error, info); afb_xreq_unhooked_unref(xreq); } @@ -370,8 +323,8 @@ static void on_event_create(void *closure, const char *event_name, int event_id) /* no conflict, try to add it */ ev = malloc(sizeof *ev); if (ev != NULL) { - ev->eventid = afb_evt_eventid_create(event_name); - if (ev->eventid != NULL) { + ev->event = afb_evt_event_x2_create(event_name); + if (ev->event != NULL) { ev->refcount = 1; ev->id = event_id; ev->next = stubws->events; @@ -404,7 +357,7 @@ static void on_event_remove(void *closure, const char *event_name, int event_id) *prv = ev->next; /* destroys the event */ - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); } @@ -419,7 +372,7 @@ static void on_event_subscribe(void *closure, void *request, const char *event_n if (ev == NULL) return; - if (afb_xreq_subscribe(xreq, ev->eventid) < 0) + if (afb_xreq_subscribe(xreq, ev->event) < 0) ERROR("can't subscribe: %m"); } @@ -434,7 +387,7 @@ static void on_event_unsubscribe(void *closure, void *request, const char *event if (ev == NULL) return; - if (afb_xreq_unsubscribe(xreq, ev->eventid) < 0) + if (afb_xreq_unsubscribe(xreq, ev->event) < 0) ERROR("can't unsubscribe: %m"); } @@ -446,7 +399,7 @@ static void on_event_push(void *closure, const char *event_name, int event_id, s /* check conflicts */ ev = client_event_search(stubws, event_id, event_name); if (ev) - afb_evt_eventid_push(ev->eventid, data); + afb_evt_event_x2_push(ev->event, data); else ERROR("unreadable push event"); } @@ -456,19 +409,6 @@ static void on_event_broadcast(void *closure, const char *event_name, struct jso afb_evt_broadcast(event_name, data); } -static void client_subcall_reply_cb(void *closure, int status, json_object *object, struct afb_request *request) -{ - struct afb_proto_ws_subcall *subcall = closure; - afb_proto_ws_subcall_reply(subcall, status, object); -} - -static void on_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args) -{ - struct afb_xreq *xreq = request; - - afb_xreq_subcall(xreq, api, verb, args, client_subcall_reply_cb, subcall); -} - /*****************************************************/ static void record_session(struct afb_stub_ws *stubws, struct afb_session *session) @@ -514,7 +454,7 @@ static void release_all_sessions(struct afb_stub_ws *stubws) /*****************************************************/ -static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid) +static void on_call(void *closure, struct afb_proto_ws_call *call, const char *verb, struct json_object *args, const char *sessionid, const char *user_creds) { struct afb_stub_ws *stubws = closure; struct server_req *wreq; @@ -539,9 +479,9 @@ static void on_call(void *closure, struct afb_proto_ws_call *call, const char *v afb_session_set_autoclose(wreq->xreq.context.session, 1); /* makes the call */ - wreq->xreq.cred = afb_cred_addref(stubws->cred); - wreq->xreq.request.api = stubws->apiname; - wreq->xreq.request.verb = verb; + wreq->xreq.cred = afb_cred_mixed_on_behalf_import(stubws->cred, sessionid, user_creds); + wreq->xreq.request.called_api = stubws->apiname; + wreq->xreq.request.called_verb = verb; wreq->xreq.json = args; afb_xreq_process(&wreq->xreq, stubws->apiset); return; @@ -551,7 +491,7 @@ unconnected: out_of_memory: json_object_put(args); afb_stub_ws_unref(stubws); - afb_proto_ws_call_fail(call, "internal-error", NULL); + afb_proto_ws_call_reply(call, NULL, "internal-error", NULL); afb_proto_ws_call_unref(call); } @@ -601,15 +541,13 @@ static void on_describe(void *closure, struct afb_proto_ws_describe *describe) static const struct afb_proto_ws_client_itf client_itf = { - .on_reply_success = on_reply_success, - .on_reply_fail = on_reply_fail, + .on_reply = on_reply, .on_event_create = on_event_create, .on_event_remove = on_event_remove, .on_event_subscribe = on_event_subscribe, .on_event_unsubscribe = on_event_unsubscribe, .on_event_push = on_event_push, .on_event_broadcast = on_event_broadcast, - .on_subcall = on_subcall }; static const struct afb_proto_ws_server_itf server_itf = @@ -642,7 +580,7 @@ static void drop_all_events(struct afb_stub_ws *stubws) while (ev) { nxt = ev->next; - afb_evt_eventid_unref(ev->eventid); + afb_evt_event_x2_unref(ev->event); free(ev); ev = nxt; } @@ -738,9 +676,9 @@ const char *afb_stub_ws_name(struct afb_stub_ws *stubws) return stubws->apiname; } -struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws) +struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws) { - struct afb_api api; + struct afb_api_item api; assert(!stubws->listener); /* check client */ api.closure = stubws; diff --git a/src/afb-stub-ws.h b/src/afb-stub-ws.h index aa643363..e14eac17 100644 --- a/src/afb-stub-ws.h +++ b/src/afb-stub-ws.h @@ -21,7 +21,7 @@ struct fdev; struct afb_stub_ws; struct afb_apiset; -struct afb_api; +struct afb_api_item; extern struct afb_stub_ws *afb_stub_ws_create_client(struct fdev *fdev, const char *apiname, struct afb_apiset *apiset); @@ -35,7 +35,7 @@ extern void afb_stub_ws_on_hangup(struct afb_stub_ws *stubws, void (*on_hangup)( extern const char *afb_stub_ws_name(struct afb_stub_ws *stubws); -extern struct afb_api afb_stub_ws_client_api(struct afb_stub_ws *stubws); +extern struct afb_api_item afb_stub_ws_client_api(struct afb_stub_ws *stubws); extern int afb_stub_ws_client_add(struct afb_stub_ws *stubws, struct afb_apiset *apiset); diff --git a/src/afb-supervision.c b/src/afb-supervision.c index f1024c3c..79a9d3fd 100644 --- a/src/afb-supervision.c +++ b/src/afb-supervision.c @@ -14,7 +14,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - #define _GNU_SOURCE #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO @@ -29,7 +28,9 @@ #include <sys/un.h> #include <json-c/json.h> -#include <afb/afb-binding-v2.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> #include "afb-cred.h" #include "afb-api.h" @@ -252,7 +253,7 @@ int afb_supervision_init() /* init the apiset */ rc = afb_apiset_add(supervision_apiset, supervision_apiname, - (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL}); + (struct afb_api_item){ .itf = &supervision_api_itf, .closure = NULL}); if (rc < 0) { ERROR("Can't create supervision's apiset: %m"); afb_apiset_unref(supervision_apiset); @@ -298,14 +299,14 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) struct json_object *args, *drop, *add, *sub, *list; const char *api, *verb, *uuid; struct afb_session *session; - const struct afb_api *xapi; - struct afb_req req; + const struct afb_api_item *xapi; + afb_req_t req; /* search the verb */ i = (int)(sizeof verbs / sizeof *verbs); - while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb)); + while(--i >= 0 && strcasecmp(verbs[i], xreq->request.called_verb)); if (i < 0) { - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); return; } @@ -324,32 +325,32 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) if (wrap_json_unpack(args, "s", &uuid)) wrap_json_unpack(args, "{ss}", "uuid", &uuid); if (!uuid) - afb_xreq_fail(xreq, "invalid", NULL); + afb_xreq_reply(xreq, NULL, "invalid", NULL); else { session = afb_session_search(uuid); if (!session) - afb_xreq_fail(xreq, "not-found", NULL); + afb_xreq_reply(xreq, NULL, "not-found", NULL); else { afb_session_close(session); afb_session_unref(session); afb_session_purge(); - afb_xreq_success(xreq, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); } } break; case Slist: list = json_object_new_object(); afb_session_foreach(slist, list); - afb_xreq_success(xreq, list, NULL); + afb_xreq_reply(xreq, list, NULL, NULL); break; case Config: - afb_xreq_success(xreq, afb_config_json(main_config), NULL); + afb_xreq_reply(xreq, afb_config_json(main_config), NULL, NULL); break; case Trace: if (!trace) trace = afb_trace_create(supervisor_apiname, NULL /* not bound to any session */); - req = xreq_to_req(xreq); + req = xreq_to_req_x2(xreq); add = drop = NULL; wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop); if (add) { @@ -367,16 +368,16 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) case Do: sub = NULL; if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub)) - afb_xreq_fail(xreq, "error", "bad request"); + afb_xreq_reply(xreq, NULL, "error", "bad request"); else { xapi = afb_apiset_lookup_started(main_apiset, api, 1); if (!xapi) - afb_xreq_fail_unknown_api(xreq); + afb_xreq_reply_unknown_api(xreq); else { afb_cred_unref(xreq->cred); xreq->cred = NULL; - xreq->request.api = api; - xreq->request.verb = verb; + xreq->request.called_api = api; + xreq->request.called_verb = verb; xreq->json = json_object_get(sub); xapi->itf->call(xapi->closure, xreq); json_object_put(args); @@ -384,11 +385,11 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq) } break; case Wait: - afb_req_success(req, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); afb_debug_wait("supervisor"); break; case Break: - afb_req_success(req, NULL, NULL); + afb_xreq_reply(xreq, NULL, NULL, NULL); afb_debug_break("supervisor"); break; } diff --git a/src/afb-trace.c b/src/afb-trace.c index 5404a5af..a603951c 100644 --- a/src/afb-trace.c +++ b/src/afb-trace.c @@ -28,7 +28,7 @@ #include <json-c/json.h> -#define AFB_BINDING_VERSION 0 +#define AFB_BINDING_VERSION 3 #include <afb/afb-binding.h> #include "afb-hook.h" @@ -74,7 +74,7 @@ struct tag { /* struct for events */ struct event { struct event *next; /* link to the next event */ - struct afb_evtid *evtid; /* the event */ + struct afb_evtid *evtid; /* the event */ }; /* struct for sessions */ @@ -95,13 +95,16 @@ struct hook { /* types of hooks */ enum trace_type { - Trace_Type_Xreq, /* xreq hooks */ - Trace_Type_Ditf, /* export hooks */ - Trace_Type_Svc, /* export hooks */ - Trace_Type_Evt, /* evt hooks */ - Trace_Type_Session, /* session hooks */ - Trace_Type_Global, /* global hooks */ - Trace_Type_Count /* count of types of hooks */ + Trace_Type_Xreq, /* xreq hooks */ + Trace_Type_Api, /* api hooks */ + Trace_Type_Evt, /* evt hooks */ + Trace_Type_Session, /* session hooks */ + Trace_Type_Global, /* global hooks */ +#if !defined(REMOVE_LEGACY_TRACE) + Trace_Legacy_Type_Ditf, /* export hooks */ + Trace_Legacy_Type_Svc, /* export hooks */ +#endif + Trace_Type_Count, /* count of types of hooks */ }; /* client data */ @@ -168,8 +171,15 @@ static struct json_object *timestamp(const struct afb_hookid *hookid) { char ts[50]; - snprintf(ts, sizeof ts, "%llu.%06lu", (long long unsigned)hookid->time.tv_sec, (long unsigned)(hookid->time.tv_nsec / 1000)); + snprintf(ts, sizeof ts, "%llu.%06lu", + (long long unsigned)hookid->time.tv_sec, + (long unsigned)((hookid->time.tv_nsec + 500) / 1000)); + + return json_object_new_double_s(0.0f, ts); /* the real value isn't used */ +#if 0 return json_object_new_string(ts); + return json_object_new_double_s(0f, ts); /* the real value isn't used */ +#endif } /* verbosity level name or NULL */ @@ -222,38 +232,35 @@ static struct flag xreq_flags[] = { /* must be sorted by names */ { "begin", afb_hook_flag_req_begin }, { "common", afb_hook_flags_req_common }, { "context", afb_hook_flags_req_context }, - { "context_get", afb_hook_flag_req_context_get }, + { "context_get", afb_hook_flag_req_legacy_context_get }, { "context_make", afb_hook_flag_req_context_make }, - { "context_set", afb_hook_flag_req_context_set }, + { "context_set", afb_hook_flag_req_legacy_context_set }, { "end", afb_hook_flag_req_end }, { "event", afb_hook_flags_req_event }, { "extra", afb_hook_flags_req_extra }, - { "fail", afb_hook_flag_req_fail }, { "get", afb_hook_flag_req_get }, { "get_application_id", afb_hook_flag_req_get_application_id }, + { "get_client_info", afb_hook_flag_req_get_client_info }, { "get_uid", afb_hook_flag_req_get_uid }, { "has_permission", afb_hook_flag_req_has_permission }, { "json", afb_hook_flag_req_json }, { "life", afb_hook_flags_req_life }, { "ref", afb_hook_flags_req_ref }, - { "result", afb_hook_flags_req_result }, + { "reply", afb_hook_flag_req_reply }, { "security", afb_hook_flags_req_security }, { "session", afb_hook_flags_req_session }, { "session_close", afb_hook_flag_req_session_close }, { "session_set_LOA", afb_hook_flag_req_session_set_LOA }, - { "store", afb_hook_flag_req_store }, + { "store", afb_hook_flag_req_legacy_store }, { "stores", afb_hook_flags_req_stores }, { "subcall", afb_hook_flag_req_subcall }, - { "subcall_req", afb_hook_flag_req_subcall_req }, - { "subcall_req_result", afb_hook_flag_req_subcall_req_result }, { "subcall_result", afb_hook_flag_req_subcall_result }, { "subcalls", afb_hook_flags_req_subcalls }, { "subcallsync", afb_hook_flag_req_subcallsync }, { "subcallsync_result", afb_hook_flag_req_subcallsync_result }, { "subscribe", afb_hook_flag_req_subscribe }, - { "success", afb_hook_flag_req_success }, { "unref", afb_hook_flag_req_unref }, - { "unstore", afb_hook_flag_req_unstore }, + { "unstore", afb_hook_flag_req_legacy_unstore }, { "unsubscribe", afb_hook_flag_req_unsubscribe }, { "vverbose", afb_hook_flag_req_vverbose }, }; @@ -285,8 +292,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru va_start(ap, format); emit(closure, hookid, "request", "{si ss ss ss so* ss*}", format, ap, "index", xreq->hookindex, - "api", xreq->request.api, - "verb", xreq->request.verb, + "api", xreq->request.called_api, + "verb", xreq->request.called_verb, "action", action, "credentials", cred, "session", session); @@ -295,7 +302,8 @@ static void hook_xreq(void *closure, const struct afb_hookid *hookid, const stru static void hook_xreq_begin(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) { - hook_xreq(closure, hookid, xreq, "begin", NULL); + hook_xreq(closure, hookid, xreq, "begin", "{sO?}", + "json", afb_xreq_unhooked_json((struct afb_xreq*)xreq)); } static void hook_xreq_end(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq) @@ -318,17 +326,11 @@ static void hook_xreq_get(void *closure, const struct afb_hookid *hookid, const "path", arg.path); } -static void hook_xreq_success(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *info) +static void hook_xreq_reply(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "success", "{sO? ss?}", + hook_xreq(closure, hookid, xreq, "reply", "{sO? ss? ss?}", "result", obj, - "info", info); -} - -static void hook_xreq_fail(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *status, const char *info) -{ - hook_xreq(closure, hookid, xreq, "fail", "{ss? ss?}", - "status", status, + "error", error, "info", info); } @@ -364,21 +366,21 @@ static void hook_xreq_session_set_LOA(void *closure, const struct afb_hookid *ho "result", result); } -static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_subscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result) { hook_xreq(closure, hookid, xreq, "subscribe", "{s{ss si} si}", "event", - "name", afb_evt_eventid_fullname(eventid), - "id", afb_evt_eventid_id(eventid), + "name", afb_evt_event_x2_fullname(event), + "id", afb_evt_event_x2_id(event), "result", result); } -static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_eventid *eventid, int result) +static void hook_xreq_unsubscribe(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct afb_event_x2 *event, int result) { hook_xreq(closure, hookid, xreq, "unsubscribe", "{s{ss? si} si}", "event", - "name", afb_evt_eventid_fullname(eventid), - "id", afb_evt_eventid_id(eventid), + "name", afb_evt_event_x2_fullname(event), + "id", afb_evt_event_x2_id(event), "result", result); } @@ -390,11 +392,12 @@ static void hook_xreq_subcall(void *closure, const struct afb_hookid *hookid, co "args", args); } -static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcall_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "subcall_result", "{si sO?}", - "status", status, - "result", result); + hook_xreq(closure, hookid, xreq, "subcall_result", "{sO? ss? ss?}", + "object", object, + "error", error, + "info", info); } static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) @@ -405,11 +408,13 @@ static void hook_xreq_subcallsync(void *closure, const struct afb_hookid *hookid "args", args); } -static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) +static void hook_xreq_subcallsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *object, const char *error, const char *info) { - hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO?}", + hook_xreq(closure, hookid, xreq, "subcallsync_result", "{si sO? ss? ss?}", "status", status, - "result", result); + "object", object, + "error", error, + "info", info); } static void hook_xreq_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int level, const char *file, int line, const char *func, const char *fmt, va_list args) @@ -448,21 +453,6 @@ static void hook_xreq_unstore(void *closure, const struct afb_hookid *hookid, co hook_xreq(closure, hookid, xreq, "unstore", NULL); } -static void hook_xreq_subcall_req(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args) -{ - hook_xreq(closure, hookid, xreq, "subcall_req", "{ss? ss? sO?}", - "api", api, - "verb", verb, - "args", args); -} - -static void hook_xreq_subcall_req_result(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, int status, struct json_object *result) -{ - hook_xreq(closure, hookid, xreq, "subcall_req_result", "{si sO?}", - "status", status, - "result", result); -} - static void hook_xreq_has_permission(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, const char *permission, int result) { hook_xreq(closure, hookid, xreq, "has_permission", "{ss sb}", @@ -497,15 +487,20 @@ static void hook_xreq_get_uid(void *closure, const struct afb_hookid *hookid, co "result", result); } +static void hook_xreq_get_client_info(void *closure, const struct afb_hookid *hookid, const struct afb_xreq *xreq, struct json_object *result) +{ + hook_xreq(closure, hookid, xreq, "get_client_info", "{so}", + "result", result); +} + static struct afb_hook_xreq_itf hook_xreq_itf = { .hook_xreq_begin = hook_xreq_begin, .hook_xreq_end = hook_xreq_end, .hook_xreq_json = hook_xreq_json, .hook_xreq_get = hook_xreq_get, - .hook_xreq_success = hook_xreq_success, - .hook_xreq_fail = hook_xreq_fail, - .hook_xreq_context_get = hook_xreq_context_get, - .hook_xreq_context_set = hook_xreq_context_set, + .hook_xreq_reply = hook_xreq_reply, + .hook_xreq_legacy_context_get = hook_xreq_context_get, + .hook_xreq_legacy_context_set = hook_xreq_context_set, .hook_xreq_addref = hook_xreq_addref, .hook_xreq_unref = hook_xreq_unref, .hook_xreq_session_close = hook_xreq_session_close, @@ -517,85 +512,146 @@ static struct afb_hook_xreq_itf hook_xreq_itf = { .hook_xreq_subcallsync = hook_xreq_subcallsync, .hook_xreq_subcallsync_result = hook_xreq_subcallsync_result, .hook_xreq_vverbose = hook_xreq_vverbose, - .hook_xreq_store = hook_xreq_store, - .hook_xreq_unstore = hook_xreq_unstore, - .hook_xreq_subcall_req = hook_xreq_subcall_req, - .hook_xreq_subcall_req_result = hook_xreq_subcall_req_result, + .hook_xreq_legacy_store = hook_xreq_store, + .hook_xreq_legacy_unstore = hook_xreq_unstore, .hook_xreq_has_permission = hook_xreq_has_permission, .hook_xreq_get_application_id = hook_xreq_get_application_id, .hook_xreq_context_make = hook_xreq_context_make, .hook_xreq_get_uid = hook_xreq_get_uid, + .hook_xreq_get_client_info = hook_xreq_get_client_info, }; /*******************************************************************************/ -/***** trace the daemon interface *****/ +/***** trace the api interface *****/ /*******************************************************************************/ -static struct flag ditf_flags[] = { /* must be sorted by names */ - { "all", afb_hook_flags_ditf_all }, - { "common", afb_hook_flags_ditf_common }, - { "event_broadcast_after", afb_hook_flag_ditf_event_broadcast_after }, - { "event_broadcast_before", afb_hook_flag_ditf_event_broadcast_before }, - { "event_make", afb_hook_flag_ditf_event_make }, - { "extra", afb_hook_flags_ditf_extra }, - { "get_event_loop", afb_hook_flag_ditf_get_event_loop }, - { "get_system_bus", afb_hook_flag_ditf_get_system_bus }, - { "get_user_bus", afb_hook_flag_ditf_get_user_bus }, - { "queue_job", afb_hook_flag_ditf_queue_job }, - { "require_api", afb_hook_flag_ditf_require_api }, - { "require_api_result", afb_hook_flag_ditf_require_api_result }, - { "rootdir_get_fd", afb_hook_flag_ditf_rootdir_get_fd }, - { "rootdir_open_locale", afb_hook_flag_ditf_rootdir_open_locale }, - { "unstore_req", afb_hook_flag_ditf_unstore_req }, - { "vverbose", afb_hook_flag_ditf_vverbose }, +#if !defined(REMOVE_LEGACY_TRACE) +static struct flag legacy_ditf_flags[] = { /* must be sorted by names */ + { "all", afb_hook_flags_api_ditf_all }, + { "common", afb_hook_flags_api_ditf_common }, + { "event_broadcast_after", afb_hook_flag_api_event_broadcast }, + { "event_broadcast_before", afb_hook_flag_api_event_broadcast }, + { "event_make", afb_hook_flag_api_event_make }, + { "extra", afb_hook_flags_api_ditf_extra }, + { "get_event_loop", afb_hook_flag_api_get_event_loop }, + { "get_system_bus", afb_hook_flag_api_get_system_bus }, + { "get_user_bus", afb_hook_flag_api_get_user_bus }, + { "queue_job", afb_hook_flag_api_queue_job }, + { "require_api", afb_hook_flag_api_require_api }, + { "require_api_result", afb_hook_flag_api_require_api }, + { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd }, + { "rootdir_open_locale", afb_hook_flag_api_rootdir_open_locale }, + { "unstore_req", afb_hook_flag_api_legacy_unstore_req }, + { "vverbose", afb_hook_flag_api_vverbose }, }; +static struct flag legacy_svc_flags[] = { /* must be sorted by names */ + { "all", afb_hook_flags_api_svc_all }, + { "call", afb_hook_flag_api_call }, + { "call_result", afb_hook_flag_api_call }, + { "callsync", afb_hook_flag_api_callsync }, + { "callsync_result", afb_hook_flag_api_callsync }, + { "on_event_after", afb_hook_flag_api_on_event }, + { "on_event_before", afb_hook_flag_api_on_event }, + { "start_after", afb_hook_flag_api_start }, + { "start_before", afb_hook_flag_api_start }, +}; + +/* get the export value for flag of 'name' */ +static int get_legacy_ditf_flag(const char *name) +{ + return get_flag(name, legacy_ditf_flags, (int)(sizeof legacy_ditf_flags / sizeof *legacy_ditf_flags)); +} + /* get the export value for flag of 'name' */ -static int get_ditf_flag(const char *name) +static int get_legacy_svc_flag(const char *name) { - return get_flag(name, ditf_flags, (int)(sizeof ditf_flags / sizeof *ditf_flags)); + return get_flag(name, legacy_svc_flags, (int)(sizeof legacy_svc_flags / sizeof *legacy_svc_flags)); } +#endif + +static struct flag api_flags[] = { /* must be sorted by names */ + { "add_alias", afb_hook_flag_api_add_alias }, + { "all", afb_hook_flags_api_all }, + { "api_add_verb", afb_hook_flag_api_api_add_verb }, + { "api", afb_hook_flags_api_api }, + { "api_del_verb", afb_hook_flag_api_api_del_verb }, + { "api_seal", afb_hook_flag_api_api_seal }, + { "api_set_on_event", afb_hook_flag_api_api_set_on_event }, + { "api_set_on_init", afb_hook_flag_api_api_set_on_init }, + { "api_set_verbs", afb_hook_flag_api_api_set_verbs }, + { "call", afb_hook_flag_api_call }, + { "callsync", afb_hook_flag_api_callsync }, + { "class_provide", afb_hook_flag_api_class_provide }, + { "class_require", afb_hook_flag_api_class_require }, + { "common", afb_hook_flags_api_common }, + { "delete_api", afb_hook_flag_api_delete_api }, + { "event", afb_hook_flags_api_event }, + { "event_broadcast", afb_hook_flag_api_event_broadcast }, + { "event_handler_add", afb_hook_flag_api_event_handler_add }, + { "event_handler_del", afb_hook_flag_api_event_handler_del }, + { "event_make", afb_hook_flag_api_event_make }, + { "extra", afb_hook_flags_api_extra }, + { "get_event_loop", afb_hook_flag_api_get_event_loop }, + { "get_system_bus", afb_hook_flag_api_get_system_bus }, + { "get_user_bus", afb_hook_flag_api_get_user_bus }, + { "legacy_unstore_req", afb_hook_flag_api_legacy_unstore_req }, + { "new_api", afb_hook_flag_api_new_api }, + { "on_event", afb_hook_flag_api_on_event }, + { "on_event_handler", afb_hook_flag_api_on_event_handler }, + { "queue_job", afb_hook_flag_api_queue_job }, + { "require_api", afb_hook_flag_api_require_api }, + { "rootdir_get_fd", afb_hook_flag_api_rootdir_get_fd }, + { "rootdir_open_locale",afb_hook_flag_api_rootdir_open_locale }, + { "start", afb_hook_flag_api_start }, + { "vverbose", afb_hook_flag_api_vverbose }, +}; +/* get the export value for flag of 'name' */ +static int get_api_flag(const char *name) +{ + return get_flag(name, api_flags, (int)(sizeof api_flags / sizeof *api_flags)); +} -static void hook_ditf(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) +static void hook_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) { va_list ap; va_start(ap, format); - emit(closure, hookid, "daemon", "{ss ss}", format, ap, + emit(closure, hookid, "api", "{ss ss}", format, ap, "api", afb_export_apiname(export), "action", action); va_end(ap); } -static void hook_ditf_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) +static void hook_api_event_broadcast_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object) { - hook_ditf(closure, hookid, export, "event_broadcast_before", "{ss sO*}", + hook_api(closure, hookid, export, "event_broadcast_before", "{ss sO?}", "name", name, "data", object); } -static void hook_ditf_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) +static void hook_api_event_broadcast_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct json_object *object, int result) { - hook_ditf(closure, hookid, export, "event_broadcast_after", "{ss sO* si}", + hook_api(closure, hookid, export, "event_broadcast_after", "{ss sO? si}", "name", name, "data", object, "result", result); } -static void hook_ditf_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) +static void hook_api_get_event_loop(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_event *result) { - hook_ditf(closure, hookid, export, "get_event_loop", NULL); + hook_api(closure, hookid, export, "get_event_loop", NULL); } -static void hook_ditf_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_user_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - hook_ditf(closure, hookid, export, "get_user_bus", NULL); + hook_api(closure, hookid, export, "get_user_bus", NULL); } -static void hook_ditf_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) +static void hook_api_get_system_bus(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct sd_bus *result) { - hook_ditf(closure, hookid, export, "get_system_bus", NULL); + hook_api(closure, hookid, export, "get_system_bus", NULL); } -static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) +static void hook_api_vverbose(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int level, const char *file, int line, const char *function, const char *fmt, va_list args) { struct json_object *pos; int len; @@ -612,7 +668,7 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c if (file) wrap_json_pack(&pos, "{ss si ss*}", "file", file, "line", line, "function", function); - hook_ditf(closure, hookid, export, "vverbose", "{si ss* ss? so*}", + hook_api(closure, hookid, export, "vverbose", "{si ss* ss? so*}", "level", level, "type", verbosity_level_name(level), len < 0 ? "format" : "message", len < 0 ? fmt : msg, @@ -621,13 +677,13 @@ static void hook_ditf_vverbose(void *closure, const struct afb_hookid *hookid, c free(msg); } -static void hook_ditf_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_eventid *result) +static void hook_api_event_make(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, struct afb_event_x2 *result) { - hook_ditf(closure, hookid, export, "event_make", "{ss ss si}", - "name", name, "event", afb_evt_eventid_fullname(result), "id", afb_evt_eventid_id(result)); + hook_api(closure, hookid, export, "event_make", "{ss ss si}", + "name", name, "event", afb_evt_event_x2_fullname(result), "id", afb_evt_event_x2_id(result)); } -static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +static void hook_api_rootdir_get_fd(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { char path[PATH_MAX]; @@ -636,12 +692,12 @@ static void hook_ditf_rootdir_get_fd(void *closure, const struct afb_hookid *hoo readlink(path, path, sizeof path); } - hook_ditf(closure, hookid, export, "rootdir_get_fd", "{ss}", + hook_api(closure, hookid, export, "rootdir_get_fd", "{ss}", result < 0 ? "path" : "error", result < 0 ? strerror(errno) : path); } -static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) +static void hook_api_rootdir_open_locale(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *filename, int flags, const char *locale, int result) { char path[PATH_MAX]; @@ -650,7 +706,7 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid readlink(path, path, sizeof path); } - hook_ditf(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}", + hook_api(closure, hookid, export, "rootdir_open_locale", "{ss si ss* ss}", "file", filename, "flags", flags, "locale", locale, @@ -658,130 +714,187 @@ static void hook_ditf_rootdir_open_locale(void *closure, const struct afb_hookid result < 0 ? strerror(errno) : path); } -static void hook_ditf_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) +static void hook_api_queue_job(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, void (*callback)(int signum, void *arg), void *argument, void *group, int timeout, int result) { - hook_ditf(closure, hookid, export, "queue_job", "{ss}", "result", result); + hook_api(closure, hookid, export, "queue_job", "{ss}", "result", result); } -static void hook_ditf_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) +static void hook_api_unstore_req(void * closure, const struct afb_hookid *hookid, const struct afb_export *export, struct afb_stored_req *sreq) { - hook_ditf(closure, hookid, export, "unstore_req", NULL); + hook_api(closure, hookid, export, "unstore_req", NULL); } -static void hook_ditf_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) +static void hook_api_require_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized) { - hook_ditf(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized); + hook_api(closure, hookid, export, "require_api", "{ss sb}", "name", name, "initialized", initialized); } -static void hook_ditf_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) +static void hook_api_require_api_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *name, int initialized, int result) { - hook_ditf(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result); + hook_api(closure, hookid, export, "require_api_result", "{ss sb si}", "name", name, "initialized", initialized, "result", result); } -static struct afb_hook_ditf_itf hook_ditf_itf = { - .hook_ditf_event_broadcast_before = hook_ditf_event_broadcast_before, - .hook_ditf_event_broadcast_after = hook_ditf_event_broadcast_after, - .hook_ditf_get_event_loop = hook_ditf_get_event_loop, - .hook_ditf_get_user_bus = hook_ditf_get_user_bus, - .hook_ditf_get_system_bus = hook_ditf_get_system_bus, - .hook_ditf_vverbose = hook_ditf_vverbose, - .hook_ditf_event_make = hook_ditf_event_make, - .hook_ditf_rootdir_get_fd = hook_ditf_rootdir_get_fd, - .hook_ditf_rootdir_open_locale = hook_ditf_rootdir_open_locale, - .hook_ditf_queue_job = hook_ditf_queue_job, - .hook_ditf_unstore_req = hook_ditf_unstore_req, - .hook_ditf_require_api = hook_ditf_require_api, - .hook_ditf_require_api_result = hook_ditf_require_api_result -}; +static void hook_api_add_alias_cb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *alias, int result) +{ + hook_api(closure, hookid, export, "add_alias", "{si ss? ss}", "status", result, "api", api, "alias", alias); +} -/*******************************************************************************/ -/***** trace the services *****/ -/*******************************************************************************/ +static void hook_api_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + hook_api(closure, hookid, export, "start_before", NULL); +} -static struct flag svc_flags[] = { /* must be sorted by names */ - { "all", afb_hook_flags_svc_all }, - { "call", afb_hook_flag_svc_call }, - { "call_result", afb_hook_flag_svc_call_result }, - { "callsync", afb_hook_flag_svc_callsync }, - { "callsync_result", afb_hook_flag_svc_callsync_result }, - { "on_event_after", afb_hook_flag_svc_on_event_after }, - { "on_event_before", afb_hook_flag_svc_on_event_before }, - { "start_after", afb_hook_flag_svc_start_after }, - { "start_before", afb_hook_flag_svc_start_before }, -}; +static void hook_api_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +{ + hook_api(closure, hookid, export, "start_after", "{si}", "result", status); +} -/* get the export value for flag of 'name' */ -static int get_svc_flag(const char *name) +static void hook_api_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) { - return get_flag(name, svc_flags, (int)(sizeof svc_flags / sizeof *svc_flags)); + hook_api(closure, hookid, export, "on_event_before", "{ss si sO*}", + "event", event, "id", evtid, "data", object); } -static void hook_svc(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *action, const char *format, ...) +static void hook_api_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) { - va_list ap; + hook_api(closure, hookid, export, "on_event_after", "{ss si sO?}", + "event", event, "id", evtid, "data", object); +} - va_start(ap, format); - emit(closure, hookid, "service", "{ss ss}", format, ap, - "api", afb_export_apiname(export), - "action", action); - va_end(ap); +static void hook_api_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +{ + hook_api(closure, hookid, export, "call", "{ss ss sO?}", + "api", api, "verb", verb, "args", args); } -static void hook_svc_start_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +static void hook_api_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, struct json_object *object, const char *error, const char *info) { - hook_svc(closure, hookid, export, "start_before", NULL); + hook_api(closure, hookid, export, "call_result", "{sO? ss? ss?}", + "object", object, "error", error, "info", info); } -static void hook_svc_start_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status) +static void hook_api_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) { - hook_svc(closure, hookid, export, "start_after", "{si}", "result", status); + hook_api(closure, hookid, export, "callsync", "{ss ss sO?}", + "api", api, "verb", verb, "args", args); } -static void hook_svc_on_event_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) +static void hook_api_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *object, const char *error, const char *info) { - hook_svc(closure, hookid, export, "on_event_before", "{ss si sO*}", - "event", event, "id", evtid, "data", object); + hook_api(closure, hookid, export, "callsync_result", "{si sO? ss? ss?}", + "status", status, "object", object, "error", error, "info", info); } -static void hook_svc_on_event_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *event, int evtid, struct json_object *object) +static void hook_api_new_api_before(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *info, int noconcurrency) { - hook_svc(closure, hookid, export, "on_event_after", "{ss si sO*}", - "event", event, "id", evtid, "data", object); + hook_api(closure, hookid, export, "new_api.before", "{ss ss? sb}", + "api", api, "info", info, "noconcurrency", noconcurrency); } -static void hook_svc_call(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +static void hook_api_new_api_after(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *api) { - hook_svc(closure, hookid, export, "call", "{ss ss sO*}", - "api", api, "verb", verb, "args", args); + hook_api(closure, hookid, export, "new_api.after", "{si ss}", + "status", result, "api", api); } -static void hook_svc_call_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +static void hook_api_api_set_verbs_v2(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v2 *verbs) { - hook_svc(closure, hookid, export, "call_result", "{si sO*}", - "status", status, "result", result); + hook_api(closure, hookid, export, "set_verbs_v2", "{si}", "status", result); } -static void hook_svc_callsync(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, const char *api, const char *verb, struct json_object *args) +static void hook_api_api_set_verbs_v3(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const struct afb_verb_v3 *verbs) { - hook_svc(closure, hookid, export, "callsync", "{ss ss sO*}", - "api", api, "verb", verb, "args", args); + hook_api(closure, hookid, export, "set_verbs_v3", "{si}", "status", result); +} + + +static void hook_api_api_add_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb, const char *info, int glob) +{ + hook_api(closure, hookid, export, "add_verb", "{si ss ss? sb}", "status", result, "verb", verb, "info", info, "glob", glob); +} + +static void hook_api_api_del_verb(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *verb) +{ + hook_api(closure, hookid, export, "del_verb", "{si ss}", "status", result, "verb", verb); +} + +static void hook_api_api_set_on_event(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + hook_api(closure, hookid, export, "set_on_event", "{si}", "status", result); } -static void hook_svc_callsync_result(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int status, struct json_object *result) +static void hook_api_api_set_on_init(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) { - hook_svc(closure, hookid, export, "callsync_result", "{si sO*}", - "status", status, "result", result); + hook_api(closure, hookid, export, "set_on_init", "{si}", "status", result); } -static struct afb_hook_svc_itf hook_svc_itf = { - .hook_svc_start_before = hook_svc_start_before, - .hook_svc_start_after = hook_svc_start_after, - .hook_svc_on_event_before = hook_svc_on_event_before, - .hook_svc_on_event_after = hook_svc_on_event_after, - .hook_svc_call = hook_svc_call, - .hook_svc_call_result = hook_svc_call_result, - .hook_svc_callsync = hook_svc_callsync, - .hook_svc_callsync_result = hook_svc_callsync_result +static void hook_api_api_seal(void *closure, const struct afb_hookid *hookid, const struct afb_export *export) +{ + hook_api(closure, hookid, export, "seal", NULL); +} + +static void hook_api_event_handler_add(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + hook_api(closure, hookid, export, "event_handler_add", "{si ss?}", "status", result, "pattern", pattern); +} + +static void hook_api_event_handler_del(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *pattern) +{ + hook_api(closure, hookid, export, "event_handler_del", "{si ss?}", "status", result, "pattern", pattern); +} + +static void hook_api_class_provide(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) +{ + hook_api(closure, hookid, export, "class_provide", "{si ss?}", "status", result, "name", name); +} + +static void hook_api_class_require(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result, const char *name) +{ + hook_api(closure, hookid, export, "class_require", "{si ss?}", "status", result, "name", name); +} + +static void hook_api_delete_api(void *closure, const struct afb_hookid *hookid, const struct afb_export *export, int result) +{ + hook_api(closure, hookid, export, "delete_api", "{si}", "status", result); +} + +static struct afb_hook_api_itf hook_api_itf = { + .hook_api_event_broadcast_before = hook_api_event_broadcast_before, + .hook_api_event_broadcast_after = hook_api_event_broadcast_after, + .hook_api_get_event_loop = hook_api_get_event_loop, + .hook_api_get_user_bus = hook_api_get_user_bus, + .hook_api_get_system_bus = hook_api_get_system_bus, + .hook_api_vverbose = hook_api_vverbose, + .hook_api_event_make = hook_api_event_make, + .hook_api_rootdir_get_fd = hook_api_rootdir_get_fd, + .hook_api_rootdir_open_locale = hook_api_rootdir_open_locale, + .hook_api_queue_job = hook_api_queue_job, + .hook_api_legacy_unstore_req = hook_api_unstore_req, + .hook_api_require_api = hook_api_require_api, + .hook_api_require_api_result = hook_api_require_api_result, + .hook_api_add_alias = hook_api_add_alias_cb, + .hook_api_start_before = hook_api_start_before, + .hook_api_start_after = hook_api_start_after, + .hook_api_on_event_before = hook_api_on_event_before, + .hook_api_on_event_after = hook_api_on_event_after, + .hook_api_call = hook_api_call, + .hook_api_call_result = hook_api_call_result, + .hook_api_callsync = hook_api_callsync, + .hook_api_callsync_result = hook_api_callsync_result, + .hook_api_new_api_before = hook_api_new_api_before, + .hook_api_new_api_after = hook_api_new_api_after, + .hook_api_api_set_verbs_v2 = hook_api_api_set_verbs_v2, + .hook_api_api_set_verbs_v3 = hook_api_api_set_verbs_v3, + .hook_api_api_add_verb = hook_api_api_add_verb, + .hook_api_api_del_verb = hook_api_api_del_verb, + .hook_api_api_set_on_event = hook_api_api_set_on_event, + .hook_api_api_set_on_init = hook_api_api_set_on_init, + .hook_api_api_seal = hook_api_api_seal, + .hook_api_event_handler_add = hook_api_event_handler_add, + .hook_api_event_handler_del = hook_api_event_handler_del, + .hook_api_class_provide = hook_api_class_provide, + .hook_api_class_require = hook_api_class_require, + .hook_api_delete_api = hook_api_delete_api, }; /*******************************************************************************/ @@ -1016,17 +1129,11 @@ abstracting[Trace_Type_Count] = .unref = (void(*)(void*))afb_hook_unref_xreq, .get_flag = get_xreq_flag }, - [Trace_Type_Ditf] = - { - .name = "daemon", - .unref = (void(*)(void*))afb_hook_unref_ditf, - .get_flag = get_ditf_flag - }, - [Trace_Type_Svc] = + [Trace_Type_Api] = { - .name = "service", - .unref = (void(*)(void*))afb_hook_unref_svc, - .get_flag = get_svc_flag + .name = "api", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_api_flag }, [Trace_Type_Evt] = { @@ -1046,6 +1153,20 @@ abstracting[Trace_Type_Count] = .unref = (void(*)(void*))afb_hook_unref_global, .get_flag = get_global_flag }, +#if !defined(REMOVE_LEGACY_TRACE) + [Trace_Legacy_Type_Ditf] = + { + .name = "daemon", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_legacy_ditf_flag + }, + [Trace_Legacy_Type_Svc] = + { + .name = "service", + .unref = (void(*)(void*))afb_hook_unref_api, + .get_flag = get_legacy_svc_flag + }, +#endif }; /*******************************************************************************/ @@ -1242,7 +1363,7 @@ static void trace_attach_hook(struct afb_trace *trace, struct hook *hook, enum t struct context { struct afb_trace *trace; - struct afb_req req; + afb_req_t req; char *errors; }; @@ -1252,13 +1373,12 @@ struct desc const char *name; const char *tag; const char *uuid; - const char *api; - const char *verb; + const char *apiname; + const char *verbname; const char *pattern; int flags[Trace_Type_Count]; }; - static void addhook(struct desc *desc, enum trace_type type) { struct hook *hook; @@ -1299,15 +1419,12 @@ static void addhook(struct desc *desc, enum trace_type type) return; } } - hook->handler = afb_hook_create_xreq(desc->api, desc->verb, session, + hook->handler = afb_hook_create_xreq(desc->apiname, desc->verbname, session, desc->flags[type], &hook_xreq_itf, hook); afb_session_unref(session); break; - case Trace_Type_Ditf: - hook->handler = afb_hook_create_ditf(desc->api, desc->flags[type], &hook_ditf_itf, hook); - break; - case Trace_Type_Svc: - hook->handler = afb_hook_create_svc(desc->api, desc->flags[type], &hook_svc_itf, hook); + case Trace_Type_Api: + hook->handler = afb_hook_create_api(desc->apiname, desc->flags[type], &hook_api_itf, hook); break; case Trace_Type_Evt: hook->handler = afb_hook_create_evt(desc->pattern, desc->flags[type], &hook_evt_itf, hook); @@ -1328,7 +1445,7 @@ static void addhook(struct desc *desc, enum trace_type type) } /* attach and activate the hook */ - afb_req_subscribe(desc->context->req, afb_evt_event_from_evtid(hook->event->evtid)); + afb_req_subscribe(desc->context->req, afb_evt_event_x2_from_evtid(hook->event->evtid)); trace_attach_hook(trace, hook, type); } @@ -1336,6 +1453,11 @@ static void addhooks(struct desc *desc) { int i; +#if !defined(REMOVE_LEGACY_TRACE) + desc->flags[Trace_Type_Api] |= desc->flags[Trace_Legacy_Type_Ditf] | desc->flags[Trace_Legacy_Type_Svc]; + desc->flags[Trace_Legacy_Type_Ditf] = desc->flags[Trace_Legacy_Type_Svc] = 0; +#endif + for (i = 0 ; i < Trace_Type_Count ; i++) { if (desc->flags[i]) addhook(desc, i); @@ -1368,14 +1490,21 @@ static void add_xreq_flags(void *closure, struct json_object *object) add_flags(closure, object, Trace_Type_Xreq); } -static void add_ditf_flags(void *closure, struct json_object *object) +#if !defined(REMOVE_LEGACY_TRACE) +static void legacy_add_ditf_flags(void *closure, struct json_object *object) +{ + add_flags(closure, object, Trace_Legacy_Type_Ditf); +} + +static void legacy_add_svc_flags(void *closure, struct json_object *object) { - add_flags(closure, object, Trace_Type_Ditf); + add_flags(closure, object, Trace_Legacy_Type_Svc); } +#endif -static void add_svc_flags(void *closure, struct json_object *object) +static void add_api_flags(void *closure, struct json_object *object) { - add_flags(closure, object, Trace_Type_Svc); + add_flags(closure, object, Trace_Type_Api); } static void add_evt_flags(void *closure, struct json_object *object) @@ -1398,21 +1527,30 @@ static void add(void *closure, struct json_object *object) { int rc; struct desc desc; - struct json_object *request, *event, *daemon, *service, *sub, *global, *session; + struct json_object *request, *event, *sub, *global, *session, *api; +#if !defined(REMOVE_LEGACY_TRACE) + struct json_object *daemon, *service; +#endif memcpy (&desc, closure, sizeof desc); - request = event = daemon = service = sub = global = session = NULL; + request = event = sub = global = session = api = NULL; +#if !defined(REMOVE_LEGACY_TRACE) + daemon = service = NULL; +#endif - rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o}", + rc = wrap_json_unpack(object, "{s?s s?s s?s s?s s?s s?s s?o s?o s?o s?o s?o s?o s?o}", "name", &desc.name, "tag", &desc.tag, - "api", &desc.api, - "verb", &desc.verb, + "apiname", &desc.apiname, + "verbname", &desc.verbname, "uuid", &desc.uuid, "pattern", &desc.pattern, + "api", &api, "request", &request, +#if !defined(REMOVE_LEGACY_TRACE) "daemon", &daemon, "service", &service, +#endif "event", &event, "session", &session, "global", &global, @@ -1420,11 +1558,11 @@ static void add(void *closure, struct json_object *object) if (!rc) { /* replace stars */ - if (desc.api && desc.api[0] == '*' && !desc.api[1]) - desc.api = NULL; + if (desc.apiname && desc.apiname[0] == '*' && !desc.apiname[1]) + desc.apiname = NULL; - if (desc.verb && desc.verb[0] == '*' && !desc.verb[1]) - desc.verb = NULL; + if (desc.verbname && desc.verbname[0] == '*' && !desc.verbname[1]) + desc.verbname = NULL; if (desc.uuid && desc.uuid[0] == '*' && !desc.uuid[1]) desc.uuid = NULL; @@ -1433,11 +1571,16 @@ static void add(void *closure, struct json_object *object) if (request) wrap_json_optarray_for_all(request, add_xreq_flags, &desc); + if (api) + wrap_json_optarray_for_all(api, add_api_flags, &desc); + +#if !defined(REMOVE_LEGACY_TRACE) if (daemon) - wrap_json_optarray_for_all(daemon, add_ditf_flags, &desc); + wrap_json_optarray_for_all(daemon, legacy_add_ditf_flags, &desc); if (service) - wrap_json_optarray_for_all(service, add_svc_flags, &desc); + wrap_json_optarray_for_all(service, legacy_add_svc_flags, &desc); +#endif if (event) wrap_json_optarray_for_all(event, add_evt_flags, &desc); @@ -1562,7 +1705,7 @@ void afb_trace_unref(struct afb_trace *trace) } /* add traces */ -int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace) +int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace) { struct context context; struct desc desc; @@ -1587,7 +1730,7 @@ int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace } /* drop traces */ -extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace) +extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace) { int rc; struct context context; diff --git a/src/afb-trace.h b/src/afb-trace.h index 5056fb25..0371546f 100644 --- a/src/afb-trace.h +++ b/src/afb-trace.h @@ -25,7 +25,7 @@ extern struct afb_trace *afb_trace_create(const char *api, struct afb_session *b extern void afb_trace_addref(struct afb_trace *trace); extern void afb_trace_unref(struct afb_trace *trace); -extern int afb_trace_add(struct afb_req req, struct json_object *args, struct afb_trace *trace); -extern int afb_trace_drop(struct afb_req req, struct json_object *args, struct afb_trace *trace); +extern int afb_trace_add(afb_req_t req, struct json_object *args, struct afb_trace *trace); +extern int afb_trace_drop(afb_req_t req, struct json_object *args, struct afb_trace *trace); diff --git a/src/afb-ws-json1.c b/src/afb-ws-json1.c index 315bee8e..95167b5f 100644 --- a/src/afb-ws-json1.c +++ b/src/afb-ws-json1.c @@ -49,7 +49,7 @@ static void aws_on_event(struct afb_ws_json1 *ws, const char *event, int eventid /* predeclaration of wsreq callbacks */ static void wsreq_destroy(struct afb_xreq *xreq); -static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj); +static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info); /* declaration of websocket structure */ struct afb_ws_json1 @@ -194,8 +194,8 @@ static void aws_on_call(struct afb_ws_json1 *ws, const char *api, const char *ve afb_wsj1_msg_addref(msg); wsreq->msgj1 = msg; wsreq->xreq.cred = afb_cred_addref(ws->cred); - wsreq->xreq.request.api = api; - wsreq->xreq.request.verb = verb; + wsreq->xreq.request.called_api = api; + wsreq->xreq.request.called_verb = verb; wsreq->xreq.json = afb_wsj1_msg_object_j(wsreq->msgj1); wsreq->aws = afb_ws_json1_addref(ws); wsreq->xreq.listener = wsreq->aws->listener; @@ -228,13 +228,17 @@ static void wsreq_destroy(struct afb_xreq *xreq) free(wsreq); } -static void wsreq_reply(struct afb_xreq *xreq, int status, json_object *obj) +static void wsreq_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { struct afb_wsreq *wsreq = CONTAINER_OF_XREQ(struct afb_wsreq, xreq); int rc; + struct json_object *reply; - rc = (status < 0 ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)( - wsreq->msgj1, obj, afb_context_sent_token(&wsreq->xreq.context)); + /* create the reply */ + reply = afb_msg_json_reply(object, error, info, &xreq->context); + + rc = (error ? afb_wsj1_reply_error_j : afb_wsj1_reply_ok_j)( + wsreq->msgj1, reply, afb_context_sent_token(&wsreq->xreq.context)); if (rc) ERROR("Can't send reply: %m"); } diff --git a/src/afb-xreq.c b/src/afb-xreq.c index 582e9b72..8f246b3c 100644 --- a/src/afb-xreq.c +++ b/src/afb-xreq.c @@ -21,22 +21,26 @@ #include <stdio.h> #include <string.h> #include <errno.h> +#include <stdarg.h> #include <json-c/json.h> + #include <afb/afb-binding-v1.h> #include <afb/afb-binding-v2.h> -#include <afb/afb-request.h> +#include <afb/afb-binding-v3.h> +#include <afb/afb-req-x2.h> +#include "afb-api.h" +#include "afb-apiset.h" +#include "afb-auth.h" +#include "afb-calls.h" #include "afb-context.h" -#include "afb-xreq.h" #include "afb-evt.h" -#include "afb-msg-json.h" #include "afb-cred.h" #include "afb-hook.h" -#include "afb-api.h" -#include "afb-api-dyn.h" -#include "afb-apiset.h" -#include "afb-auth.h" +#include "afb-msg-json.h" +#include "afb-xreq.h" + #include "jobs.h" #include "verbose.h" @@ -45,7 +49,7 @@ static void xreq_finalize(struct afb_xreq *xreq) { if (!xreq->replied) - afb_xreq_fail(xreq, "error", "no reply"); + afb_xreq_reply(xreq, NULL, "error", "no reply"); if (xreq->hookflags) afb_hook_xreq_end(xreq); if (xreq->caller) @@ -66,274 +70,22 @@ inline void afb_xreq_unhooked_unref(struct afb_xreq *xreq) /******************************************************************************/ -struct subcall -{ - struct afb_xreq xreq; - - void (*completion)(struct subcall*, int, struct json_object*); - - union { - struct { - struct jobloop *jobloop; - struct json_object *result; - int status; - }; - struct { - union { - void (*callback)(void*, int, struct json_object*); - void (*callback_req)(void*, int, struct json_object*, struct afb_req); - void (*callback_request)(void*, int, struct json_object*, struct afb_request*); - }; - void *closure; - }; - }; -}; - -static int subcall_subscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - return afb_xreq_subscribe(subcall->xreq.caller, eventid); -} - -static int subcall_unsubscribe_cb(struct afb_xreq *xreq, struct afb_eventid *eventid) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - return afb_xreq_unsubscribe(subcall->xreq.caller, eventid); -} - -static void subcall_reply_cb(struct afb_xreq *xreq, int status, struct json_object *result) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - subcall->completion(subcall, status, result); - json_object_put(result); - afb_xreq_unhooked_unref(&subcall->xreq); -} - -static void subcall_destroy_cb(struct afb_xreq *xreq) -{ - struct subcall *subcall = CONTAINER_OF_XREQ(struct subcall, xreq); - - json_object_put(subcall->xreq.json); - afb_cred_unref(subcall->xreq.cred); - free(subcall); -} - -const struct afb_xreq_query_itf afb_xreq_subcall_itf = { - .reply = subcall_reply_cb, - .unref = subcall_destroy_cb, - .subscribe = subcall_subscribe_cb, - .unsubscribe = subcall_unsubscribe_cb -}; - -static struct subcall *subcall_alloc( - struct afb_xreq *caller, - const char *api, - const char *verb, - struct json_object *args -) -{ - struct subcall *subcall; - size_t lenapi, lenverb; - char *copy; - - lenapi = 1 + strlen(api); - lenverb = 1 + strlen(verb); - subcall = malloc(lenapi + lenverb + sizeof *subcall); - if (!subcall) - ERROR("out of memory"); - else { - copy = (char*)&subcall[1]; - memcpy(copy, api, lenapi); - api = copy; - copy = ©[lenapi]; - memcpy(copy, verb, lenverb); - verb = copy; - - afb_xreq_init(&subcall->xreq, &afb_xreq_subcall_itf); - afb_context_subinit(&subcall->xreq.context, &caller->context); - subcall->xreq.cred = afb_cred_addref(caller->cred); - subcall->xreq.json = args; - subcall->xreq.request.api = api; - subcall->xreq.request.verb = verb; - subcall->xreq.caller = caller; - afb_xreq_unhooked_addref(caller); - } - return subcall; -} - - -static void subcall_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback(subcall->closure, status, result); -} - -static void subcall_req_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback_req(subcall->closure, status, result, xreq_to_req(subcall->xreq.caller)); -} - -static void subcall_request_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->callback_request(subcall->closure, status, result, xreq_to_request(subcall->xreq.caller)); -} - -static void subcall_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result); - subcall_on_reply(subcall, status, result); -} - -static void subcall_req_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_req_result(subcall->xreq.caller, status, result); - subcall_req_on_reply(subcall, status, result); -} - -static void subcall_request_hooked_on_reply(struct subcall *subcall, int status, struct json_object *result) -{ - afb_hook_xreq_subcall_result(subcall->xreq.caller, status, result); - subcall_request_on_reply(subcall, status, result); -} - -static void subcall_reply_direct_cb(void *closure, int status, struct json_object *result) +struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq) { - struct afb_xreq *xreq = closure; - - if (xreq->replied) { - ERROR("subcall replied more than one time!!"); - json_object_put(result); - } else { - xreq->replied = 1; - subcall_reply_cb(xreq, status, result); - } -} - -static void subcall_process(struct subcall *subcall, void (*completion)(struct subcall*, int, struct json_object*)) -{ - subcall->completion = completion; - if (subcall->xreq.caller->queryitf->subcall) { - subcall->xreq.caller->queryitf->subcall( - subcall->xreq.caller, subcall->xreq.request.api, subcall->xreq.request.verb, - subcall->xreq.json, subcall_reply_direct_cb, &subcall->xreq); - } else { - afb_xreq_unhooked_addref(&subcall->xreq); - afb_xreq_process(&subcall->xreq, subcall->xreq.caller->apiset); - } -} - -static void subcall(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - subcall->callback = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_on_reply); -} - -static void subcall_req(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) -{ - subcall->callback_req = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_req_on_reply); -} - -static void subcall_request(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) -{ - subcall->callback_request = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_request_on_reply); -} - -static void subcall_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*), void *cb_closure) -{ - subcall->callback = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_hooked_on_reply); -} - -static void subcall_req_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) -{ - subcall->callback_req = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_req_hooked_on_reply); -} - -static void subcall_request_hooked(struct subcall *subcall, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) -{ - subcall->callback_request = callback; - subcall->closure = cb_closure; - subcall_process(subcall, subcall_request_hooked_on_reply); -} - -static void subcall_sync_leave(struct subcall *subcall) -{ - struct jobloop *jobloop = __atomic_exchange_n(&subcall->jobloop, NULL, __ATOMIC_RELAXED); - if (jobloop) - jobs_leave(jobloop); -} - -static void subcall_sync_reply(struct subcall *subcall, int status, struct json_object *result) -{ - subcall->status = status; - subcall->result = json_object_get(result); - subcall_sync_leave(subcall); -} - -static void subcall_sync_enter(int signum, void *closure, struct jobloop *jobloop) -{ - struct subcall *subcall = closure; - - if (!signum) { - subcall->jobloop = jobloop; - subcall->result = NULL; - subcall->status = 0; - subcall_process(subcall, subcall_sync_reply); - } else { - subcall->status = -1; - subcall_sync_leave(subcall); - } -} - -static int subcallsync(struct subcall *subcall, struct json_object **result) -{ - int rc; - - afb_xreq_unhooked_addref(&subcall->xreq); - rc = jobs_enter(NULL, 0, subcall_sync_enter, subcall); - *result = subcall->result; - if (rc < 0 || subcall->status < 0) { - *result = *result ?: afb_msg_json_internal_error(); - rc = -1; - } - afb_xreq_unhooked_unref(&subcall->xreq); - return rc; -} - -/******************************************************************************/ - -static void vinfo(void *first, void *second, const char *fmt, va_list args, void (*fun)(void*,void*,const char*)) -{ - char *info; - if (fmt == NULL || vasprintf(&info, fmt, args) < 0) - info = NULL; - fun(first, second, info); - free(info); -} - -/******************************************************************************/ - -static struct json_object *xreq_json_cb(struct afb_request *closure) -{ - struct afb_xreq *xreq = xreq_from_request(closure); if (!xreq->json && xreq->queryitf->json) xreq->json = xreq->queryitf->json(xreq); return xreq->json; } -static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name) +static struct json_object *xreq_json_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_unhooked_json(xreq); +} + +static struct afb_arg xreq_get_cb(struct afb_req_x2 *closure, const char *name) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); struct afb_arg arg; struct json_object *object, *value; @@ -353,409 +105,388 @@ static struct afb_arg xreq_get_cb(struct afb_request *closure, const char *name) return arg; } -static void xreq_success_cb(struct afb_request *closure, struct json_object *obj, const char *info) +static void xreq_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); if (xreq->replied) { ERROR("reply called more than one time!!"); json_object_put(obj); } else { xreq->replied = 1; - if (xreq->queryitf->success) - xreq->queryitf->success(xreq, obj, info); - else - xreq->queryitf->reply(xreq, 0, afb_msg_json_reply_ok(info, obj, &xreq->context, NULL)); + xreq->queryitf->reply(xreq, obj, error, info); } } -static void xreq_fail_cb(struct afb_request *closure, const char *status, const char *info) +static void xreq_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + char *info; + if (fmt == NULL || vasprintf(&info, fmt, args) < 0) + info = NULL; + xreq_reply_cb(closure, obj, error, info); + free(info); +} - if (xreq->replied) { - ERROR("reply called more than one time!!"); - } else { - xreq->replied = 1; - if (xreq->queryitf->fail) - xreq->queryitf->fail(xreq, status, info); - else - xreq->queryitf->reply(xreq, -1, afb_msg_json_reply_error(status, info, &xreq->context, NULL)); - } +static void xreq_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info) +{ + xreq_reply_cb(closure, obj, NULL, info); } -static void xreq_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args) +static void xreq_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info) { - vinfo(closure, obj, fmt, args, (void*)xreq_success_cb); + xreq_reply_cb(closure, NULL, status, info); } -static void xreq_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args) +static void xreq_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args) { - vinfo(closure, (void*)status, fmt, args, (void*)xreq_fail_cb); + xreq_vreply_cb(closure, obj, NULL, fmt, args); } -static void *xreq_context_get_cb(struct afb_request *closure) +static void xreq_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + xreq_vreply_cb(closure, NULL, status, fmt, args); +} + +static void *xreq_legacy_context_get_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_get(&xreq->context); } -static void xreq_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*)) +static void xreq_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*)) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_context_set(&xreq->context, value, free_value); } -static struct afb_request *xreq_addref_cb(struct afb_request *closure) +static struct afb_req_x2 *xreq_addref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_xreq_unhooked_addref(xreq); return closure; } -static void xreq_unref_cb(struct afb_request *closure) +static void xreq_unref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_xreq_unhooked_unref(xreq); } -static void xreq_session_close_cb(struct afb_request *closure) +static void xreq_session_close_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_context_close(&xreq->context); } -static int xreq_session_set_LOA_cb(struct afb_request *closure, unsigned level) +static int xreq_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_change_loa(&xreq->context, level); } -static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_subscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_subscribe_eventid_cb(closure, afb_event_to_eventid(event)); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_subscribe(xreq, event); } -static int xreq_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_xreq_subscribe(xreq, eventid); + return xreq_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { if (xreq->listener) - return afb_evt_eventid_add_watch(xreq->listener, eventid); + return afb_evt_event_x2_add_watch(xreq->listener, event); if (xreq->queryitf->subscribe) - return xreq->queryitf->subscribe(xreq, eventid); + return xreq->queryitf->subscribe(xreq, event); ERROR("no event listener, subscription impossible"); errno = EINVAL; return -1; } -static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_unsubscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event)); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_xreq_unsubscribe(xreq, event); } -static int xreq_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_xreq_unsubscribe(xreq, eventid); + return xreq_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid) +int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event) { if (xreq->listener) - return afb_evt_eventid_remove_watch(xreq->listener, eventid); + return afb_evt_event_x2_remove_watch(xreq->listener, event); if (xreq->queryitf->unsubscribe) - return xreq->queryitf->unsubscribe(xreq, eventid); + return xreq->queryitf->unsubscribe(xreq, event); ERROR("no event listener, unsubscription impossible"); errno = EINVAL; return -1; } -static void xreq_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) +static void xreq_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error()); - json_object_put(args); - } else { - subcall(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v1(xreq, api, verb, args, callback, closure); } -static void xreq_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +static void xreq_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq)); - json_object_put(args); - } else { - subcall_req(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v2(xreq, api, verb, args, callback, closure); } -static void xreq_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request*), void *cb_closure) +static void xreq_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq)); - json_object_put(args); - } else { - subcall_request(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_v3(xreq, api, verb, args, callback, closure); } -static int xreq_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) +static int xreq_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - int rc; - struct subcall *sc; - struct afb_xreq *xreq = xreq_from_request(closure); - struct json_object *resu; - - sc = subcall_alloc(xreq, api, verb, args); - if (!sc) { - rc = -1; - resu = afb_msg_json_internal_error(); - json_object_put(args); - } else { - rc = subcallsync(sc, &resu); - } - if (result) - *result = resu; - else - json_object_put(resu); - return rc; + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_subcall_sync(xreq, api, verb, args, result); } -static void xreq_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void xreq_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { char *p; - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); if (!fmt || vasprintf(&p, fmt, args) < 0) vverbose(level, file, line, func, fmt, args); else { - verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.api, p); + verbose(level, file, line, func, "[REQ/API %s] %s", xreq->request.called_api, p); free(p); } } -static struct afb_stored_req *xreq_store_cb(struct afb_request *closure) +static struct afb_stored_req *xreq_legacy_store_cb(struct afb_req_x2 *closure) { xreq_addref_cb(closure); return (struct afb_stored_req*)closure; } -static int xreq_has_permission_cb(struct afb_request *closure, const char *permission) +static int xreq_has_permission_cb(struct afb_req_x2 *closure, const char *permission) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_auth_has_permission(xreq, permission); } -static char *xreq_get_application_id_cb(struct afb_request *closure) +static char *xreq_get_application_id_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return xreq->cred && xreq->cred->id ? strdup(xreq->cred->id) : NULL; } -static void *xreq_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) +static void *xreq_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_context_make(&xreq->context, replace, create_value, free_value, create_closure); } -static int xreq_get_uid_cb(struct afb_request *closure) +static int xreq_get_uid_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return xreq->cred && xreq->cred->id ? (int)xreq->cred->uid : -1; } +static struct json_object *xreq_get_client_info_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct json_object *r = json_object_new_object(); + if (xreq->cred && xreq->cred->id) { + json_object_object_add(r, "uid", json_object_new_int(xreq->cred->uid)); + json_object_object_add(r, "gid", json_object_new_int(xreq->cred->gid)); + json_object_object_add(r, "pid", json_object_new_int(xreq->cred->pid)); + json_object_object_add(r, "user", json_object_new_string(xreq->cred->user)); + json_object_object_add(r, "label", json_object_new_string(xreq->cred->label)); + json_object_object_add(r, "id", json_object_new_string(xreq->cred->id)); + } + if (xreq->context.session) { + json_object_object_add(r, "uuid", json_object_new_string(afb_context_uuid(&xreq->context))); + json_object_object_add(r, "LOA", json_object_new_int(afb_context_get_loa(&xreq->context))); + } + return r; +} + +static void xreq_subcall_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_subcall(xreq, api, verb, args, flags, callback, closure); +} + +static int xreq_subcallsync_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_subcall_sync(xreq, api, verb, args, flags, object, error, info); +} + /******************************************************************************/ -static struct json_object *xreq_hooked_json_cb(struct afb_request *closure) +static struct json_object *xreq_hooked_json_cb(struct afb_req_x2 *closure) { struct json_object *r = xreq_json_cb(closure); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_json(xreq, r); } -static struct afb_arg xreq_hooked_get_cb(struct afb_request *closure, const char *name) +static struct afb_arg xreq_hooked_get_cb(struct afb_req_x2 *closure, const char *name) { struct afb_arg r = xreq_get_cb(closure, name); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_get(xreq, name, r); } -static void xreq_hooked_success_cb(struct afb_request *closure, struct json_object *obj, const char *info) +static void xreq_hooked_reply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + afb_hook_xreq_reply(xreq, obj, error, info); + xreq_reply_cb(closure, obj, error, info); +} + +static void xreq_hooked_vreply_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *error, const char *fmt, va_list args) +{ + char *info; + if (fmt == NULL || vasprintf(&info, fmt, args) < 0) + info = NULL; + xreq_hooked_reply_cb(closure, obj, error, info); + free(info); +} + +static void xreq_hooked_legacy_success_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_success(xreq, obj, info); - xreq_success_cb(closure, obj, info); + xreq_hooked_reply_cb(closure, obj, NULL, info); } -static void xreq_hooked_fail_cb(struct afb_request *closure, const char *status, const char *info) +static void xreq_hooked_legacy_fail_cb(struct afb_req_x2 *closure, const char *status, const char *info) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_fail(xreq, status, info); - xreq_fail_cb(closure, status, info); + xreq_hooked_reply_cb(closure, NULL, status, info); } -static void xreq_hooked_vsuccess_cb(struct afb_request *closure, struct json_object *obj, const char *fmt, va_list args) +static void xreq_hooked_legacy_vsuccess_cb(struct afb_req_x2 *closure, struct json_object *obj, const char *fmt, va_list args) { - vinfo(closure, obj, fmt, args, (void*)xreq_hooked_success_cb); + xreq_hooked_vreply_cb(closure, obj, NULL, fmt, args); } -static void xreq_hooked_vfail_cb(struct afb_request *closure, const char *status, const char *fmt, va_list args) +static void xreq_hooked_legacy_vfail_cb(struct afb_req_x2 *closure, const char *status, const char *fmt, va_list args) { - vinfo(closure, (void*)status, fmt, args, (void*)xreq_hooked_fail_cb); + xreq_hooked_vreply_cb(closure, NULL, status, fmt, args); } -static void *xreq_hooked_context_get_cb(struct afb_request *closure) +static void *xreq_hooked_legacy_context_get_cb(struct afb_req_x2 *closure) { - void *r = xreq_context_get_cb(closure); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_context_get(xreq, r); + void *r = xreq_legacy_context_get_cb(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_legacy_context_get(xreq, r); } -static void xreq_hooked_context_set_cb(struct afb_request *closure, void *value, void (*free_value)(void*)) +static void xreq_hooked_legacy_context_set_cb(struct afb_req_x2 *closure, void *value, void (*free_value)(void*)) { - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_context_set(xreq, value, free_value); - xreq_context_set_cb(closure, value, free_value); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + afb_hook_xreq_legacy_context_set(xreq, value, free_value); + xreq_legacy_context_set_cb(closure, value, free_value); } -static struct afb_request *xreq_hooked_addref_cb(struct afb_request *closure) +static struct afb_req_x2 *xreq_hooked_addref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_addref(xreq); return xreq_addref_cb(closure); } -static void xreq_hooked_unref_cb(struct afb_request *closure) +static void xreq_hooked_unref_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_unref(xreq); xreq_unref_cb(closure); } -static void xreq_hooked_session_close_cb(struct afb_request *closure) +static void xreq_hooked_session_close_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); afb_hook_xreq_session_close(xreq); xreq_session_close_cb(closure); } -static int xreq_hooked_session_set_LOA_cb(struct afb_request *closure, unsigned level) +static int xreq_hooked_session_set_LOA_cb(struct afb_req_x2 *closure, unsigned level) { int r = xreq_session_set_LOA_cb(closure, level); - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); return afb_hook_xreq_session_set_LOA(xreq, level, r); } -static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_hooked_subscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_hooked_subscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_hooked_subscribe_eventid_cb(closure, afb_event_to_eventid(event)); + int r = xreq_subscribe_event_x2_cb(closure, event); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_subscribe(xreq, event, r); } -static int xreq_hooked_subscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_hooked_legacy_subscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - int r = xreq_subscribe_eventid_cb(closure, eventid); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_subscribe(xreq, eventid, r); + return xreq_hooked_subscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid); -static int xreq_hooked_unsubscribe_cb(struct afb_request *closure, struct afb_event event) +static int xreq_hooked_unsubscribe_event_x2_cb(struct afb_req_x2 *closure, struct afb_event_x2 *event) { - return xreq_hooked_unsubscribe_eventid_cb(closure, afb_event_to_eventid(event)); + int r = xreq_unsubscribe_event_x2_cb(closure, event); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + return afb_hook_xreq_unsubscribe(xreq, event, r); } -static int xreq_hooked_unsubscribe_eventid_cb(struct afb_request *closure, struct afb_eventid *eventid) +static int xreq_hooked_legacy_unsubscribe_event_x1_cb(struct afb_req_x2 *closure, struct afb_event_x1 event) { - int r = xreq_unsubscribe_eventid_cb(closure, eventid); - struct afb_xreq *xreq = xreq_from_request(closure); - return afb_hook_xreq_unsubscribe(xreq, eventid, r); + return xreq_hooked_unsubscribe_event_x2_cb(closure, afb_event_x1_to_event_x2(event)); } -static void xreq_hooked_subcall_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *cb_closure) +static void xreq_hooked_legacy_subcall_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error()); - json_object_put(args); - } else { - subcall_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v1(xreq, api, verb, args, callback, closure); } -static void xreq_hooked_subcall_req_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req), void *cb_closure) +static void xreq_hooked_legacy_subcall_req_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x1), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall_req(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_req(xreq)); - json_object_put(args); - } else { - subcall_req_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v2(xreq, api, verb, args, callback, closure); } -static void xreq_hooked_subcall_request_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +static void xreq_hooked_legacy_subcall_request_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct subcall *sc; - - afb_hook_xreq_subcall(xreq, api, verb, args); - sc = subcall_alloc(xreq, api, verb, args); - if (sc == NULL) { - if (callback) - callback(cb_closure, 1, afb_msg_json_internal_error(), xreq_to_request(xreq)); - json_object_put(args); - } else { - subcall_request_hooked(sc, callback, cb_closure); - } + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_legacy_hooked_subcall_v3(xreq, api, verb, args, callback, closure); } -static int xreq_hooked_subcallsync_cb(struct afb_request *closure, const char *api, const char *verb, struct json_object *args, struct json_object **result) +static int xreq_hooked_legacy_subcallsync_cb(struct afb_req_x2 *req, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - int r; - struct afb_xreq *xreq = xreq_from_request(closure); - afb_hook_xreq_subcallsync(xreq, api, verb, args); - r = xreq_subcallsync_cb(closure, api, verb, args, result); - return afb_hook_xreq_subcallsync_result(xreq, r, *result); + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_legacy_hooked_subcall_sync(xreq, api, verb, args, result); } -static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) +static void xreq_hooked_vverbose_cb(struct afb_req_x2 *closure, int level, const char *file, int line, const char *func, const char *fmt, va_list args) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); va_list ap; va_copy(ap, args); xreq_vverbose_cb(closure, level, file, line, func, fmt, args); @@ -763,149 +494,178 @@ static void xreq_hooked_vverbose_cb(struct afb_request *closure, int level, cons va_end(ap); } -static struct afb_stored_req *xreq_hooked_store_cb(struct afb_request *closure) +static struct afb_stored_req *xreq_hooked_legacy_store_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); - struct afb_stored_req *r = xreq_store_cb(closure); - afb_hook_xreq_store(xreq, r); + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct afb_stored_req *r = xreq_legacy_store_cb(closure); + afb_hook_xreq_legacy_store(xreq, r); return r; } -static int xreq_hooked_has_permission_cb(struct afb_request *closure, const char *permission) +static int xreq_hooked_has_permission_cb(struct afb_req_x2 *closure, const char *permission) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); int r = xreq_has_permission_cb(closure, permission); return afb_hook_xreq_has_permission(xreq, permission, r); } -static char *xreq_hooked_get_application_id_cb(struct afb_request *closure) +static char *xreq_hooked_get_application_id_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); char *r = xreq_get_application_id_cb(closure); return afb_hook_xreq_get_application_id(xreq, r); } -static void *xreq_hooked_context_make_cb(struct afb_request *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) +static void *xreq_hooked_context_make_cb(struct afb_req_x2 *closure, int replace, void *(*create_value)(void*), void (*free_value)(void*), void *create_closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); void *result = xreq_context_make_cb(closure, replace, create_value, free_value, create_closure); return afb_hook_xreq_context_make(xreq, replace, create_value, free_value, create_closure, result); } -static int xreq_hooked_get_uid_cb(struct afb_request *closure) +static int xreq_hooked_get_uid_cb(struct afb_req_x2 *closure) { - struct afb_xreq *xreq = xreq_from_request(closure); + struct afb_xreq *xreq = xreq_from_req_x2(closure); int r = xreq_get_uid_cb(closure); return afb_hook_xreq_get_uid(xreq, r); } +static struct json_object *xreq_hooked_get_client_info_cb(struct afb_req_x2 *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(closure); + struct json_object *r = xreq_get_client_info_cb(closure); + return afb_hook_xreq_get_client_info(xreq, r); +} + +static void xreq_hooked_subcall_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void *closure, struct json_object *object, const char *error, const char * info, struct afb_req_x2 *req), + void *closure) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + afb_calls_hooked_subcall(xreq, api, verb, args, flags, callback, closure); +} + +static int xreq_hooked_subcallsync_cb( + struct afb_req_x2 *req, + const char *api, + const char *verb, + struct json_object *args, + int flags, + struct json_object **object, + char **error, + char **info) +{ + struct afb_xreq *xreq = xreq_from_req_x2(req); + return afb_calls_hooked_subcall_sync(xreq, api, verb, args, flags, object, error, info); +} + /******************************************************************************/ -const struct afb_request_itf xreq_itf = { +const struct afb_req_x2_itf xreq_itf = { .json = xreq_json_cb, .get = xreq_get_cb, - .success = xreq_success_cb, - .fail = xreq_fail_cb, - .vsuccess = xreq_vsuccess_cb, - .vfail = xreq_vfail_cb, - .context_get = xreq_context_get_cb, - .context_set = xreq_context_set_cb, + .legacy_success = xreq_legacy_success_cb, + .legacy_fail = xreq_legacy_fail_cb, + .legacy_vsuccess = xreq_legacy_vsuccess_cb, + .legacy_vfail = xreq_legacy_vfail_cb, + .legacy_context_get = xreq_legacy_context_get_cb, + .legacy_context_set = xreq_legacy_context_set_cb, .addref = xreq_addref_cb, .unref = xreq_unref_cb, .session_close = xreq_session_close_cb, .session_set_LOA = xreq_session_set_LOA_cb, - .subscribe = xreq_subscribe_cb, - .unsubscribe = xreq_unsubscribe_cb, - .subcall = xreq_subcall_cb, - .subcallsync = xreq_subcallsync_cb, + .legacy_subscribe_event_x1 = xreq_legacy_subscribe_event_x1_cb, + .legacy_unsubscribe_event_x1 = xreq_legacy_unsubscribe_event_x1_cb, + .legacy_subcall = xreq_legacy_subcall_cb, + .legacy_subcallsync = xreq_legacy_subcallsync_cb, .vverbose = xreq_vverbose_cb, - .store = xreq_store_cb, - .subcall_req = xreq_subcall_req_cb, + .legacy_store_req = xreq_legacy_store_cb, + .legacy_subcall_req = xreq_legacy_subcall_req_cb, .has_permission = xreq_has_permission_cb, .get_application_id = xreq_get_application_id_cb, .context_make = xreq_context_make_cb, - .subscribe_eventid = xreq_subscribe_eventid_cb, - .unsubscribe_eventid = xreq_unsubscribe_eventid_cb, - .subcall_request = xreq_subcall_request_cb, + .subscribe_event_x2 = xreq_subscribe_event_x2_cb, + .unsubscribe_event_x2 = xreq_unsubscribe_event_x2_cb, + .legacy_subcall_request = xreq_legacy_subcall_request_cb, .get_uid = xreq_get_uid_cb, + .reply = xreq_reply_cb, + .vreply = xreq_vreply_cb, + .get_client_info = xreq_get_client_info_cb, + .subcall = xreq_subcall_cb, + .subcallsync = xreq_subcallsync_cb, }; -const struct afb_request_itf xreq_hooked_itf = { +const struct afb_req_x2_itf xreq_hooked_itf = { .json = xreq_hooked_json_cb, .get = xreq_hooked_get_cb, - .success = xreq_hooked_success_cb, - .fail = xreq_hooked_fail_cb, - .vsuccess = xreq_hooked_vsuccess_cb, - .vfail = xreq_hooked_vfail_cb, - .context_get = xreq_hooked_context_get_cb, - .context_set = xreq_hooked_context_set_cb, + .legacy_success = xreq_hooked_legacy_success_cb, + .legacy_fail = xreq_hooked_legacy_fail_cb, + .legacy_vsuccess = xreq_hooked_legacy_vsuccess_cb, + .legacy_vfail = xreq_hooked_legacy_vfail_cb, + .legacy_context_get = xreq_hooked_legacy_context_get_cb, + .legacy_context_set = xreq_hooked_legacy_context_set_cb, .addref = xreq_hooked_addref_cb, .unref = xreq_hooked_unref_cb, .session_close = xreq_hooked_session_close_cb, .session_set_LOA = xreq_hooked_session_set_LOA_cb, - .subscribe = xreq_hooked_subscribe_cb, - .unsubscribe = xreq_hooked_unsubscribe_cb, - .subcall = xreq_hooked_subcall_cb, - .subcallsync = xreq_hooked_subcallsync_cb, + .legacy_subscribe_event_x1 = xreq_hooked_legacy_subscribe_event_x1_cb, + .legacy_unsubscribe_event_x1 = xreq_hooked_legacy_unsubscribe_event_x1_cb, + .legacy_subcall = xreq_hooked_legacy_subcall_cb, + .legacy_subcallsync = xreq_hooked_legacy_subcallsync_cb, .vverbose = xreq_hooked_vverbose_cb, - .store = xreq_hooked_store_cb, - .subcall_req = xreq_hooked_subcall_req_cb, + .legacy_store_req = xreq_hooked_legacy_store_cb, + .legacy_subcall_req = xreq_hooked_legacy_subcall_req_cb, .has_permission = xreq_hooked_has_permission_cb, .get_application_id = xreq_hooked_get_application_id_cb, .context_make = xreq_hooked_context_make_cb, - .subscribe_eventid = xreq_hooked_subscribe_eventid_cb, - .unsubscribe_eventid = xreq_hooked_unsubscribe_eventid_cb, - .subcall_request = xreq_hooked_subcall_request_cb, + .subscribe_event_x2 = xreq_hooked_subscribe_event_x2_cb, + .unsubscribe_event_x2 = xreq_hooked_unsubscribe_event_x2_cb, + .legacy_subcall_request = xreq_hooked_legacy_subcall_request_cb, .get_uid = xreq_hooked_get_uid_cb, + .reply = xreq_hooked_reply_cb, + .vreply = xreq_hooked_vreply_cb, + .get_client_info = xreq_hooked_get_client_info_cb, + .subcall = xreq_hooked_subcall_cb, + .subcallsync = xreq_hooked_subcallsync_cb, }; /******************************************************************************/ -struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq) +struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq) { struct afb_xreq *xreq = (struct afb_xreq *)sreq; if (xreq->hookflags) - afb_hook_xreq_unstore(xreq); - return xreq_to_req(xreq); + afb_hook_xreq_legacy_unstore(xreq); + return xreq_to_req_x1(xreq); } struct json_object *afb_xreq_json(struct afb_xreq *xreq) { - return afb_request_json(xreq_to_request(xreq)); + return afb_req_x2_json(xreq_to_req_x2(xreq)); } -void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info) +void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info) { - afb_request_success(xreq_to_request(xreq), obj, info); + afb_req_x2_reply(xreq_to_req_x2(xreq), obj, error, info); } -void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...) +void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...) { va_list args; va_start(args, info); - afb_request_success_v(xreq_to_request(xreq), obj, info, args); + afb_req_x2_reply_v(xreq_to_req_x2(xreq), obj, error, info, args); va_end(args); } -void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info) -{ - afb_request_fail(xreq_to_request(xreq), status, info); -} - -void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...) -{ - va_list args; - - va_start(args, info); - afb_request_fail_v(xreq_to_request(xreq), status, info, args); - va_end(args); - -} - const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size) { - struct json_object *obj = xreq_json_cb(xreq_to_request(xreq)); + struct json_object *obj = xreq_json_cb(xreq_to_req_x2(xreq)); const char *result = json_object_to_json_string(obj); if (size != NULL) *size = strlen(result); @@ -914,69 +674,79 @@ const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size) void afb_xreq_addref(struct afb_xreq *xreq) { - afb_request_addref(xreq_to_request(xreq)); + afb_req_x2_addref(xreq_to_req_x2(xreq)); } void afb_xreq_unref(struct afb_xreq *xreq) { - afb_request_unref(xreq_to_request(xreq)); + afb_req_x2_unref(xreq_to_req_x2(xreq)); +} + +void afb_xreq_unhooked_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure) +{ + xreq_legacy_subcall_request_cb(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure); +} + +void afb_xreq_legacy_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure) +{ + afb_req_x2_subcall_legacy(xreq_to_req_x2(xreq), api, verb, args, callback, cb_closure); } -void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +void afb_xreq_unhooked_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure) { - xreq_subcall_request_cb(xreq_to_request(xreq), api, verb, args, callback, cb_closure); + xreq_subcall_cb(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure); } -void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, void (*callback)(void*, int, struct json_object*, struct afb_request *), void *cb_closure) +void afb_xreq_subcall(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, int flags, void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), void *closure) { - afb_request_subcall(xreq_to_request(xreq), api, verb, args, callback, cb_closure); + afb_req_x2_subcall(xreq_to_req_x2(xreq), api, verb, args, flags, callback, closure); } -int afb_xreq_unhooked_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) +int afb_xreq_unhooked_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - return xreq_subcallsync_cb(xreq_to_request(xreq), api, verb, args, result); + return xreq_legacy_subcallsync_cb(xreq_to_req_x2(xreq), api, verb, args, result); } -int afb_xreq_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) +int afb_xreq_legacy_subcall_sync(struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result) { - return afb_request_subcall_sync(xreq_to_request(xreq), api, verb, args, result); + return afb_req_x2_subcall_sync_legacy(xreq_to_req_x2(xreq), api, verb, args, result); } static int xreq_session_check_apply_v1(struct afb_xreq *xreq, int sessionflags) { int loa; - if ((sessionflags & (AFB_SESSION_CLOSE_V1|AFB_SESSION_RENEW_V1|AFB_SESSION_CHECK_V1|AFB_SESSION_LOA_EQ_V1)) != 0) { + if ((sessionflags & (AFB_SESSION_CLOSE_X1|AFB_SESSION_RENEW_X1|AFB_SESSION_CHECK_X1|AFB_SESSION_LOA_EQ_X1)) != 0) { if (!afb_context_check(&xreq->context)) { afb_context_close(&xreq->context); - afb_xreq_fail_f(xreq, "denied", "invalid token's identity"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity"); errno = EINVAL; return -1; } } - if ((sessionflags & AFB_SESSION_LOA_GE_V1) != 0) { - loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1; + if ((sessionflags & AFB_SESSION_LOA_GE_X1) != 0) { + loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1; if (!afb_context_check_loa(&xreq->context, loa)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } } - if ((sessionflags & AFB_SESSION_LOA_LE_V1) != 0) { - loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_V1) & AFB_SESSION_LOA_MASK_V1; + if ((sessionflags & AFB_SESSION_LOA_LE_X1) != 0) { + loa = (sessionflags >> AFB_SESSION_LOA_SHIFT_X1) & AFB_SESSION_LOA_MASK_X1; if (afb_context_check_loa(&xreq->context, loa + 1)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } } - if ((sessionflags & AFB_SESSION_RENEW_V1) != 0) { + if ((sessionflags & AFB_SESSION_RENEW_X1) != 0) { afb_context_refresh(&xreq->context); } - if ((sessionflags & AFB_SESSION_CLOSE_V1) != 0) { + if ((sessionflags & AFB_SESSION_CLOSE_X1) != 0) { afb_context_change_loa(&xreq->context, 0); afb_context_close(&xreq->context); } @@ -991,29 +761,29 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl if (sessionflags != 0) { if (!afb_context_check(&xreq->context)) { afb_context_close(&xreq->context); - afb_xreq_fail_f(xreq, "denied", "invalid token's identity"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid token's identity"); errno = EINVAL; return -1; } } - loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_V2); + loa = (int)(sessionflags & AFB_SESSION_LOA_MASK_X2); if (loa && !afb_context_check_loa(&xreq->context, loa)) { - afb_xreq_fail_f(xreq, "denied", "invalid LOA"); + afb_xreq_reply_f(xreq, NULL, "denied", "invalid LOA"); errno = EPERM; return -1; } if (auth && !afb_auth_check(xreq, auth)) { - afb_xreq_fail_f(xreq, "denied", "authorisation refused"); + afb_xreq_reply_f(xreq, NULL, "denied", "authorisation refused"); errno = EPERM; return -1; } - if ((sessionflags & AFB_SESSION_REFRESH_V2) != 0) { + if ((sessionflags & AFB_SESSION_REFRESH_X2) != 0) { afb_context_refresh(&xreq->context); } - if ((sessionflags & AFB_SESSION_CLOSE_V2) != 0) { + if ((sessionflags & AFB_SESSION_CLOSE_X2) != 0) { afb_context_close(&xreq->context); } @@ -1023,55 +793,55 @@ static int xreq_session_check_apply_v2(struct afb_xreq *xreq, uint32_t sessionfl void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (!xreq_session_check_apply_v1(xreq, verb->session)) - verb->callback(xreq_to_req(xreq)); + verb->callback(xreq_to_req_x1(xreq)); } void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (!xreq_session_check_apply_v2(xreq, verb->session, verb->auth)) - verb->callback(xreq_to_req(xreq)); + verb->callback(xreq_to_req_x1(xreq)); } -void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb) +void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb) { if (!verb) - afb_xreq_fail_unknown_verb(xreq); + afb_xreq_reply_unknown_verb(xreq); else if (xreq_session_check_apply_v2(xreq, verb->session, verb->auth) >= 0) - verb->callback(xreq_to_request(xreq)); + verb->callback(xreq_to_req_x2(xreq)); } void afb_xreq_init(struct afb_xreq *xreq, const struct afb_xreq_query_itf *queryitf) { memset(xreq, 0, sizeof *xreq); - xreq->request.itf = &xreq_hooked_itf; /* hook by default */ + xreq->request.itf = &xreq_itf; /* no hook by default */ xreq->refcount = 1; xreq->queryitf = queryitf; } -void afb_xreq_fail_unknown_api(struct afb_xreq *xreq) +void afb_xreq_reply_unknown_api(struct afb_xreq *xreq) { - afb_xreq_fail_f(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb); + afb_xreq_reply_f(xreq, NULL, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb); } -void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq) +void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq) { - afb_xreq_fail_f(xreq, "unknown-verb", "verb %s unknown within api %s", xreq->request.verb, xreq->request.api); + afb_xreq_reply_f(xreq, NULL, "unknown-verb", "verb %s unknown within api %s", xreq->request.called_verb, xreq->request.called_api); } static void init_hooking(struct afb_xreq *xreq) { afb_hook_init_xreq(xreq); - if (xreq->hookflags) + if (xreq->hookflags) { + xreq->request.itf = &xreq_hooked_itf; /* unhook the interface */ afb_hook_xreq_begin(xreq); - else - xreq->request.itf = &xreq_itf; /* unhook the interface */ + } } /** @@ -1080,16 +850,16 @@ static void init_hooking(struct afb_xreq *xreq) static void process_async(int signum, void *arg) { struct afb_xreq *xreq = arg; - const struct afb_api *api; + const struct afb_api_item *api; if (signum != 0) { /* emit the error (assumes that hooking is initialised) */ - afb_xreq_fail_f(xreq, "aborted", "signal %s(%d) caught", strsignal(signum), signum); + afb_xreq_reply_f(xreq, NULL, "aborted", "signal %s(%d) caught", strsignal(signum), signum); } else { /* init hooking */ init_hooking(xreq); - /* invoke api call method to process the reqiest */ - api = (const struct afb_api*)xreq->context.api_key; + /* invoke api call method to process the request */ + api = (const struct afb_api_item*)xreq->context.api_key; api->itf->call(api->closure, xreq); } /* release the request */ @@ -1111,7 +881,7 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char /* send error */ va_start(args, info); - afb_request_fail_v(xreq_to_request(xreq), status, info, args); + afb_req_x2_reply_v(xreq_to_req_x2(xreq), NULL, status, info, args); va_end(args); } @@ -1121,17 +891,17 @@ static void early_failure(struct afb_xreq *xreq, const char *status, const char */ void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset) { - const struct afb_api *api; + const struct afb_api_item *api; struct afb_xreq *caller; /* lookup at the api */ xreq->apiset = apiset; - api = afb_apiset_lookup_started(apiset, xreq->request.api, 1); + api = afb_apiset_lookup_started(apiset, xreq->request.called_api, 1); if (!api) { if (errno == ENOENT) - early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.api, xreq->request.verb); + early_failure(xreq, "unknown-api", "api %s not found (for verb %s)", xreq->request.called_api, xreq->request.called_verb); else - early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.api); + early_failure(xreq, "bad-api-state", "api %s not started correctly: %m", xreq->request.called_api); goto end; } xreq->context.api_key = api; @@ -1140,10 +910,10 @@ void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset) if (api->group) { caller = xreq->caller; while (caller) { - if (((const struct afb_api *)caller->context.api_key)->group == api->group) { + if (((const struct afb_api_item*)caller->context.api_key)->group == api->group) { /* noconcurrency lock detected */ - ERROR("self-lock detected in call stack for API %s", xreq->request.api); - early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.api); + ERROR("self-lock detected in call stack for API %s", xreq->request.called_api); + early_failure(xreq, "self-locked", "recursive self lock, API %s", xreq->request.called_api); goto end; } caller = caller->caller; @@ -1162,3 +932,8 @@ end: afb_xreq_unhooked_unref(xreq); } +const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq) +{ + return xreq->caller ? afb_cred_export(xreq->cred) : NULL; +} + diff --git a/src/afb-xreq.h b/src/afb-xreq.h index ae1419fb..5c748d6f 100644 --- a/src/afb-xreq.h +++ b/src/afb-xreq.h @@ -17,8 +17,9 @@ #pragma once -#include <afb/afb-request-itf.h> -#include <afb/afb-req-itf.h> +#include <stdarg.h> +#include <afb/afb-req-x1-itf.h> +#include <afb/afb-req-x2-itf.h> #include "afb-context.h" struct json_object; @@ -26,29 +27,20 @@ struct afb_evt_listener; struct afb_xreq; struct afb_cred; struct afb_apiset; -struct afb_api_dyn_verb; -struct afb_eventid; +struct afb_event_x2; struct afb_verb_desc_v1; struct afb_verb_v2; -struct afb_req; +struct afb_verb_v3; +struct afb_req_x1; struct afb_stored_req; struct afb_xreq_query_itf { struct json_object *(*json)(struct afb_xreq *xreq); struct afb_arg (*get)(struct afb_xreq *xreq, const char *name); - void (*success)(struct afb_xreq *xreq, struct json_object *obj, const char *info); - void (*fail)(struct afb_xreq *xreq, const char *status, const char *info); - void (*reply)(struct afb_xreq *xreq, int status, struct json_object *obj); + void (*reply)(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); void (*unref)(struct afb_xreq *xreq); - int (*subscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid); - int (*unsubscribe)(struct afb_xreq *xreq, struct afb_eventid *eventid); - void (*subcall)( - struct afb_xreq *xreq, - const char *api, - const char *verb, - struct json_object *args, - void (*callback)(void*, int, struct json_object*), - void *cb_closure); + int (*subscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event); + int (*unsubscribe)(struct afb_xreq *xreq, struct afb_event_x2 *event); }; /** @@ -56,7 +48,7 @@ struct afb_xreq_query_itf { */ struct afb_xreq { - struct afb_request request; /**< exported request */ + struct afb_req_x2 request; /**< exported request */ struct afb_context context; /**< context of the request */ struct afb_apiset *apiset; /**< apiset of the xreq */ struct json_object *json; /**< the json object (or NULL) */ @@ -90,49 +82,65 @@ struct afb_xreq #define CONTAINER_OF_XREQ(type,x) CONTAINER_OF(type,xreq,x) /* req wrappers for xreq */ -extern struct afb_req afb_xreq_unstore(struct afb_stored_req *sreq); +extern struct afb_req_x1 afb_xreq_unstore(struct afb_stored_req *sreq); extern void afb_xreq_addref(struct afb_xreq *xreq); extern void afb_xreq_unref(struct afb_xreq *xreq); extern void afb_xreq_unhooked_addref(struct afb_xreq *xreq); extern void afb_xreq_unhooked_unref(struct afb_xreq *xreq); +extern struct json_object *afb_xreq_unhooked_json(struct afb_xreq *xreq); extern struct json_object *afb_xreq_json(struct afb_xreq *xreq); -extern void afb_xreq_success(struct afb_xreq *xreq, struct json_object *obj, const char *info); -extern void afb_xreq_success_f(struct afb_xreq *xreq, struct json_object *obj, const char *info, ...); +extern void afb_xreq_reply(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info); +extern void afb_xreq_reply_f(struct afb_xreq *xreq, struct json_object *obj, const char *error, const char *info, ...); -extern void afb_xreq_fail(struct afb_xreq *xreq, const char *status, const char *info); -extern void afb_xreq_fail_f(struct afb_xreq *xreq, const char *status, const char *info, ...); -extern void afb_xreq_fail_unknown_api(struct afb_xreq *xreq); -extern void afb_xreq_fail_unknown_verb(struct afb_xreq *xreq); +extern void afb_xreq_reply_unknown_api(struct afb_xreq *xreq); +extern void afb_xreq_reply_unknown_verb(struct afb_xreq *xreq); extern const char *afb_xreq_raw(struct afb_xreq *xreq, size_t *size); -extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid); -extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid); +extern int afb_xreq_subscribe(struct afb_xreq *xreq, struct afb_event_x2 *event); +extern int afb_xreq_unsubscribe(struct afb_xreq *xreq, struct afb_event_x2 *event); -extern void afb_xreq_subcall( +extern void afb_xreq_legacy_subcall( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_request *), + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure); -extern void afb_xreq_unhooked_subcall( +extern void afb_xreq_unhooked_legacy_subcall( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, - void (*callback)(void*, int, struct json_object*, struct afb_request *), + void (*callback)(void*, int, struct json_object*, struct afb_req_x2 *), void *cb_closure); -extern int afb_xreq_unhooked_subcall_sync( +extern void afb_xreq_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), + void *closure); +extern void afb_xreq_unhooked_subcall( + struct afb_xreq *xreq, + const char *api, + const char *verb, + struct json_object *args, + int flags, + void (*callback)(void*, struct json_object*, const char*, const char*, struct afb_req_x2 *), + void *closure); + +extern int afb_xreq_unhooked_legacy_subcall_sync( struct afb_xreq *xreq, const char *api, const char *verb, struct json_object *args, struct json_object **result); -extern int afb_xreq_subcall_sync( +extern int afb_xreq_legacy_subcall_sync( struct afb_xreq *xreq, const char *api, const char *verb, @@ -146,23 +154,24 @@ extern void afb_xreq_process(struct afb_xreq *xreq, struct afb_apiset *apiset); extern void afb_xreq_call_verb_v1(struct afb_xreq *xreq, const struct afb_verb_desc_v1 *verb); extern void afb_xreq_call_verb_v2(struct afb_xreq *xreq, const struct afb_verb_v2 *verb); -extern void afb_xreq_call_verb_vdyn(struct afb_xreq *xreq, const struct afb_api_dyn_verb *verb); +extern void afb_xreq_call_verb_v3(struct afb_xreq *xreq, const struct afb_verb_v3 *verb); + +extern const char *xreq_on_behalf_cred_export(struct afb_xreq *xreq); /******************************************************************************/ -static inline struct afb_req xreq_to_req(struct afb_xreq *xreq) +static inline struct afb_req_x1 xreq_to_req_x1(struct afb_xreq *xreq) { - return (struct afb_req){ .itf = xreq->request.itf, .closure = &xreq->request }; + return (struct afb_req_x1){ .itf = xreq->request.itf, .closure = &xreq->request }; } -static inline struct afb_request *xreq_to_request(struct afb_xreq *xreq) +static inline struct afb_req_x2 *xreq_to_req_x2(struct afb_xreq *xreq) { return &xreq->request; } -static inline struct afb_xreq *xreq_from_request(struct afb_request *request) +static inline struct afb_xreq *xreq_from_req_x2(struct afb_req_x2 *req) { - return CONTAINER_OF(struct afb_xreq, request, request); + return CONTAINER_OF(struct afb_xreq, request, req); } - diff --git a/src/afs-config.c b/src/afs-config.c index 78fee7dc..70a6d475 100644 --- a/src/afs-config.c +++ b/src/afs-config.c @@ -263,11 +263,11 @@ static void parse_arguments(int argc, char **argv, struct afs_config *config) while ((optc = getopt_long(argc, argv, shortopts, gnuOptions, NULL)) != EOF) { switch (optc) { case SET_VERBOSE: - verbosity++; + verbose_inc(); break; case SET_QUIET: - verbosity--; + verbose_dec(); break; case SET_TCP_PORT: @@ -441,7 +441,7 @@ struct afs_config *afs_config_parse_arguments(int argc, char **argv) parse_environment(result); parse_arguments(argc, argv, result); fulfill_config(result); - if (verbosity >= 3) + if (verbose_wants(Log_Level_Info)) afs_config_dump(result); return result; } diff --git a/src/afs-supervision.h b/src/afs-supervision.h index 2c76f249..25d1b4b1 100644 --- a/src/afs-supervision.h +++ b/src/afs-supervision.h @@ -45,5 +45,5 @@ struct afs_supervision_initiator char extra[27]; /**< zero terminated extra computed here to be 64-37 */ }; -#define AFS_SUPERVISION_APINAME "$" +#define AFS_SUPERVISION_APINAME "." #define AFS_SUPERVISOR_APINAME "supervisor" diff --git a/src/afs-supervisor.c b/src/afs-supervisor.c index 285d82cb..6bd1fc62 100644 --- a/src/afs-supervisor.c +++ b/src/afs-supervisor.c @@ -28,13 +28,15 @@ #include <sys/un.h> #include <json-c/json.h> -#include <afb/afb-binding-v2.h> + +#define AFB_BINDING_VERSION 3 +#include <afb/afb-binding.h> #include "afb-cred.h" #include "afb-stub-ws.h" #include "afb-api.h" #include "afb-xreq.h" -#include "afb-api-so-v2.h" +#include "afb-api-v3.h" #include "afb-apiset.h" #include "afb-fdev.h" @@ -76,6 +78,10 @@ static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; /* list of supervised daemons */ static struct supervised *superviseds; +/* events */ +static afb_event_t event_add_pid; +static afb_event_t event_del_pid; + /*************************************************************************************/ @@ -155,7 +161,7 @@ static int send_initiator(int fd, const char *command) } /* - * checks whether the incomming supervised represented by its creds + * checks whether the incoming supervised represented by its creds * is to be accepted or not. * return 1 if yes or 0 otherwise. */ @@ -171,11 +177,15 @@ static void on_supervised_hangup(struct afb_stub_ws *stub) ps = &superviseds; while ((s = *ps) && s->stub != stub) ps = &s->next; - if (s) { + if (s) *ps = s->next; - afb_stub_ws_unref(stub); - } pthread_mutex_unlock(&mutex); + afb_stub_ws_unref(stub); + if (s) { + afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid)); + afb_cred_unref(s->cred); + free(s); + } } /* @@ -246,8 +256,10 @@ static void accept_supervision_link(int sock) rc = send_initiator(fd, NULL); if (!rc) { rc = make_supervised(fd, cred); - if (!rc) + if (!rc) { + afb_event_push(event_add_pid, json_object_new_int((int)cred->pid)); return; + } } } afb_cred_unref(cred); @@ -290,9 +302,27 @@ int afs_supervisor_discover() /*************************************************************************************/ -static struct afb_binding_data_v2 datav2; +static void f_subscribe(afb_req_t req) +{ + struct json_object *args = afb_req_json(req); + int revoke, ok; + + revoke = json_object_is_type(args, json_type_boolean) + && !json_object_get_boolean(args); -static void f_list(struct afb_req req) + ok = 1; + if (!revoke) { + ok = !afb_req_subscribe(req, event_add_pid) + && !afb_req_subscribe(req, event_del_pid); + } + if (revoke || !ok) { + afb_req_unsubscribe(req, event_add_pid); + afb_req_unsubscribe(req, event_del_pid); + } + afb_req_reply(req, NULL, ok ? NULL : "error", NULL); +} + +static void f_list(afb_req_t req) { char pid[50]; struct json_object *resu, *item; @@ -317,82 +347,82 @@ static void f_list(struct afb_req req) afb_req_success(req, resu, NULL); } -static void f_discover(struct afb_req req) +static void f_discover(afb_req_t req) { afs_supervisor_discover(); afb_req_success(req, NULL, NULL); } -static void propagate(struct afb_req req, const char *verb) +static void propagate(afb_req_t req, const char *verb) { struct afb_xreq *xreq; struct json_object *args, *item; struct supervised *s; - struct afb_api api; + struct afb_api_item api; int p; - xreq = xreq_from_request(req.closure); + xreq = xreq_from_req_x2(req); args = afb_xreq_json(xreq); if (!json_object_object_get_ex(args, "pid", &item)) { - afb_xreq_fail(xreq, "no-pid", NULL); + afb_xreq_reply(xreq, NULL, "no-pid", NULL); return; } errno = 0; p = json_object_get_int(item); if (!p && errno) { - afb_xreq_fail(xreq, "bad-pid", NULL); + afb_xreq_reply(xreq, NULL, "bad-pid", NULL); return; } s = supervised_of_pid((pid_t)p); if (!s) { - afb_req_fail(req, "unknown-pid", NULL); + afb_req_reply(req, NULL, "unknown-pid", NULL); return; } json_object_object_del(args, "pid"); if (verb) - xreq->request.verb = verb; + xreq->request.called_verb = verb; api = afb_stub_ws_client_api(s->stub); api.itf->call(api.closure, xreq); } -static void f_do(struct afb_req req) +static void f_do(afb_req_t req) { propagate(req, NULL); } -static void f_config(struct afb_req req) +static void f_config(afb_req_t req) { propagate(req, NULL); } -static void f_trace(struct afb_req req) +static void f_trace(afb_req_t req) { propagate(req, NULL); } -static void f_sessions(struct afb_req req) +static void f_sessions(afb_req_t req) { propagate(req, "slist"); } -static void f_session_close(struct afb_req req) +static void f_session_close(afb_req_t req) { propagate(req, "sclose"); } -static void f_exit(struct afb_req req) +static void f_exit(afb_req_t req) { propagate(req, NULL); afb_req_success(req, NULL, NULL); } -static void f_debug_wait(struct afb_req req) +static void f_debug_wait(afb_req_t req) { propagate(req, "wait"); afb_req_success(req, NULL, NULL); } -static void f_debug_break(struct afb_req req) +static void f_debug_break(afb_req_t req) { propagate(req, "break"); afb_req_success(req, NULL, NULL); @@ -403,10 +433,22 @@ static void f_debug_break(struct afb_req req) /** * initialize the supervisor */ -static int init_supervisor() +static int init_supervisor(afb_api_t api) { int rc, fd; + event_add_pid = afb_api_make_event(api, "add-pid"); + if (!afb_event_is_valid(event_add_pid)) { + ERROR("Can't create added event"); + return -1; + } + + event_del_pid = afb_api_make_event(api, "del-pid"); + if (!afb_event_is_valid(event_del_pid)) { + ERROR("Can't create deleted event"); + return -1; + } + /* create an empty set for superviseds */ empty_apiset = afb_apiset_create(supervision_apiname, 0); if (!empty_apiset) { @@ -448,93 +490,102 @@ static const struct afb_auth _afb_auths_v2_supervisor[] = { } }; -static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = { +static const struct afb_verb_v3 _afb_verbs_supervisor[] = { + { + .verb = "subscribe", + .callback = f_subscribe, + .auth = &_afb_auths_v2_supervisor[0], + .info = NULL, + .session = AFB_SESSION_CHECK_X2 + }, { .verb = "list", .callback = f_list, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "config", .callback = f_config, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "do", .callback = f_do, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "trace", .callback = f_trace, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "sessions", .callback = f_sessions, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "session-close", .callback = f_session_close, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "exit", .callback = f_exit, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "debug-wait", .callback = f_debug_wait, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "debug-break", .callback = f_debug_break, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = "discover", .callback = f_discover, .auth = &_afb_auths_v2_supervisor[0], .info = NULL, - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK_X2 }, { .verb = NULL } }; -static const struct afb_binding_v2 _afb_binding_v2_supervisor = { +static const struct afb_binding_v3 _afb_binding_supervisor = { .api = supervisor_apiname, .specification = NULL, .info = NULL, - .verbs = _afb_verbs_v2_supervisor, + .verbs = _afb_verbs_supervisor, .preinit = NULL, .init = init_supervisor, .onevent = NULL, .noconcurrency = 0 }; -int afs_supervisor_add(struct afb_apiset *apiset) +int afs_supervisor_add( + struct afb_apiset *declare_set, + struct afb_apiset * call_set) { - return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2); + return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set); } diff --git a/src/afs-supervisor.h b/src/afs-supervisor.h index aeae6c72..08768ae7 100644 --- a/src/afs-supervisor.h +++ b/src/afs-supervisor.h @@ -19,5 +19,6 @@ extern int afs_supervisor_discover(); -extern int afs_supervisor_add(struct afb_apiset *apiset); - +extern int afs_supervisor_add( + struct afb_apiset *declare_set, + struct afb_apiset * call_set); diff --git a/src/devtools/genskel.c b/src/devtools/genskel.c index a0a78815..55dd3c15 100644 --- a/src/devtools/genskel.c +++ b/src/devtools/genskel.c @@ -62,6 +62,7 @@ struct path /** * root of the JSON being parsed */ +int version = 3; struct json_object *root = NULL; struct json_object *d_perms = NULL; struct json_object *a_perms = NULL; @@ -78,8 +79,8 @@ int noconc = -1; int cpp = 0; /** - * Search for a reference of type "#/a/b/c" int the - * parsed JSON object + * Search for a reference of type "#/a/b/c" in the + * parsed JSON object (root) */ struct json_object *search(const char *path) { @@ -170,6 +171,7 @@ struct json_object *expand_$ref(struct path path) return path.object; } +/* create c name by replacing non alpha numeric characters with underscores */ char *cify(const char *str) { char *r = strdup(str); @@ -182,6 +184,7 @@ char *cify(const char *str) return r; } +/* format the specification as a C string */ char *make_info(const char *text, int split) { const char *a, *b; @@ -260,11 +263,13 @@ char *make_info(const char *text, int split) return desc; } +/* make the description of the object */ char *make_desc(struct json_object *o) { - return make_info(json_object_to_json_string_ext(root, 0), 1); + return make_info(json_object_to_json_string_ext(o, 0), 1); } +/* get the permission odescription if set */ struct json_object *permissions_of_verb(struct json_object *obj) { struct json_object *x, *y; @@ -279,6 +284,7 @@ struct json_object *permissions_of_verb(struct json_object *obj) return NULL; } +/* output the array of permissions */ void print_perms() { int i, n; @@ -286,7 +292,7 @@ void print_perms() n = a_perms ? json_object_array_length(a_perms) : 0; if (n) { - printf("static const struct afb_auth _afb_auths_v2_%s[] = {\n" , capi); + printf("static const struct afb_auth _afb_auths_%s[] = {\n" , capi); i = 0; while (i < n) { printf(fmtstr, json_object_get_string(json_object_array_get_idx(a_perms, i))); @@ -296,6 +302,10 @@ void print_perms() } } +/* + * search in the global object 'd_perm' the computed representation + * of the permission described either by 'obj' or 'desc' + */ struct json_object *new_perm(struct json_object *obj, const char *desc) { const char *tag; @@ -304,12 +314,15 @@ struct json_object *new_perm(struct json_object *obj, const char *desc) tag = obj ? json_object_to_json_string_ext(obj, 0) : desc; if (!json_object_object_get_ex(d_perms, tag, &y)) { + + /* creates the d_perms dico and the a_perms array */ if (!d_perms) { d_perms = json_object_new_object(); a_perms = json_object_new_array(); } - asprintf(&b, "&_afb_auths_v2_%s[%d]", capi, json_object_array_length(a_perms)); + /* creates the reference in the structure */ + asprintf(&b, "&_afb_auths_%s[%d]", capi, json_object_array_length(a_perms)); x = json_object_new_string(desc); y = json_object_new_string(b); json_object_array_add(a_perms, x); @@ -323,6 +336,7 @@ struct json_object *decl_perm(struct json_object *obj); enum optype { And, Or }; +/* recursive declare and/or permissions */ struct json_object *decl_perm_a(enum optype op, struct json_object *obj) { int i, n; @@ -354,16 +368,22 @@ struct json_object *decl_perm_a(enum optype op, struct json_object *obj) return x; } +/* declare the permission for obj */ struct json_object *decl_perm(struct json_object *obj) { char *a; + const char *fmt; struct json_object *x, *y; if (json_object_object_get_ex(d_perms, json_object_to_json_string_ext(obj, 0), &x)) return x; if (json_object_object_get_ex(obj, "permission", &x)) { - asprintf(&a, cpp ? "afb::auth_permission(\"%s\")" : ".type = afb_auth_Permission, .text = \"%s\"", json_object_get_string(x)); + if (cpp) + fmt = "afb::auth_permission(\"%s\")"; + else + fmt = ".type = afb_auth_Permission, .text = \"%s\""; + asprintf(&a, fmt, json_object_get_string(x)); y = new_perm(obj, a); free(a); } @@ -375,7 +395,11 @@ struct json_object *decl_perm(struct json_object *obj) } else if (json_object_object_get_ex(obj, "not", &x)) { x = decl_perm(x); - asprintf(&a, cpp ? "afb::auth_not(%s)" : ".type = afb_auth_Not, .first = %s", json_object_get_string(x)); + if (cpp) + fmt = "afb::auth_not(%s)"; + else + fmt = ".type = afb_auth_Not, .first = %s"; + asprintf(&a, fmt, json_object_get_string(x)); y = new_perm(obj, a); free(a); } @@ -477,7 +501,7 @@ void print_session(struct json_object *p) s = p ? get_session(p) : 0; c = 1; if (s & SESSION_CHECK) { - printf("%s", "|AFB_SESSION_CHECK_V2" + c); + printf("%s", "|AFB_SESSION_CHECK" + c); c = 0; } if (s & SESSION_LOA_3 & ~SESSION_LOA_2) @@ -489,19 +513,19 @@ void print_session(struct json_object *p) else l = 0; if (l) { - printf("%s%d_V2", "|AFB_SESSION_LOA_" + c, l); + printf("%s%d", "|AFB_SESSION_LOA_" + c, l); c = 0; } if (s & SESSION_CLOSE) { - printf("%s", "|AFB_SESSION_CLOSE_V2" + c); + printf("%s", "|AFB_SESSION_CLOSE" + c); c = 0; } if (s & SESSION_RENEW) { - printf("%s", "|AFB_SESSION_REFRESH_V2" + c); + printf("%s", "|AFB_SESSION_REFRESH" + c); c = 0; } if (c) - printf("AFB_SESSION_NONE_V2"); + printf("AFB_SESSION_NONE"); } void print_verb(const char *name) @@ -513,7 +537,7 @@ void print_declare_verb(const char *name, struct json_object *obj) { printf("%s void ", scope); print_verb(name); - printf("(struct afb_req req);\n"); + printf("(afb_req req);\n"); } void print_struct_verb(const char *name, struct json_object *obj) @@ -542,6 +566,12 @@ void print_struct_verb(const char *name, struct json_object *obj) , info ? make_info(info, 0) : "NULL" ); print_session(p); + if (version == 3) + printf( + ",\n" + " .vcbdata = NULL,\n" + " .glob = 0" + ); printf( "\n" " },\n" @@ -646,7 +676,7 @@ void process(char *filename) /* get the API name */ printf( "\n" - "static const char _afb_description_v2_%s[] =\n" + "static const char _afb_description_%s[] =\n" "%s" ";\n" "\n" @@ -657,8 +687,8 @@ void process(char *filename) enum_verbs(print_declare_verb); printf( "\n" - "static const struct afb_verb_v2 _afb_verbs_v2_%s[] = {\n" - , capi + "static const struct afb_verb_v%d _afb_verbs_%s[] = {\n" + , version, capi ); enum_verbs(print_struct_verb); printf( @@ -667,25 +697,36 @@ void process(char *filename) " .callback = NULL,\n" " .auth = NULL,\n" " .info = NULL,\n" - " .session = 0\n" + " .session = 0" + ); + if (version == 3) + printf( + ",\n" + " .vcbdata = NULL,\n" + " .glob = 0" + ); + printf( + "\n" " }\n" "};\n" ); printf( "\n" - "%sconst struct afb_binding_v2 %s%s = {\n" + "%sconst struct afb_binding_v%d %s%s = {\n" " .api = \"%s\",\n" - " .specification = _afb_description_v2_%s,\n" + " .specification = _afb_description_%s,\n" " .info = %s,\n" - " .verbs = _afb_verbs_v2_%s,\n" + " .verbs = _afb_verbs_%s,\n" " .preinit = %s,\n" " .init = %s,\n" " .onevent = %s,\n" + "%s" " .noconcurrency = %d\n" "};\n" "\n" , priv ? "static " : "" - , priv ? "_afb_binding_v2_" : "afbBindingV2" + , version + , priv ? "_afb_binding_" : version==3 ? "afbBindingV3" : "afbBindingV2" , priv ? capi : "" , api , capi @@ -694,6 +735,7 @@ void process(char *filename) , preinit ?: "NULL" , init ?: "NULL" , onevent ?: "NULL" + , version==3 ? " .userdata = NULL,\n" : "" , !!noconc ); @@ -705,11 +747,25 @@ void process(char *filename) /** process the list of files or stdin if none */ int main(int ac, char **av) { + int r, w; av++; - if (*av && !(strcmp(*av, "-x") && strcmp(*av, "--cpp"))) { - cpp = 1; - av++; + + r = w = 0; + while (av[r]) { + if (!(strcmp(av[r], "-x") && strcmp(av[r], "--cpp"))) { + cpp = 1; + r++; + } else if (!strcmp(av[r], "-2")) { + version = 2; + r++; + } else if (!strcmp(av[r], "-3")) { + version = 3; + r++; + } else { + av[w++] = av[r++]; + } } + av[w] = NULL; if (!*av) process("-"); else { @@ -718,7 +774,3 @@ int main(int ac, char **av) return 0; } - - - - diff --git a/src/devtools/monitor-api.json b/src/devtools/monitor-api.json index 3c8867cd..ca4a9b37 100644 --- a/src/devtools/monitor-api.json +++ b/src/devtools/monitor-api.json @@ -172,11 +172,11 @@ "end", "event", "extra", - "fail", "get", "json", "life", "ref", + "reply", "result", "session", "session_close", @@ -190,7 +190,6 @@ "subcallsync", "subcallsync_result", "subscribe", - "success", "unref", "unstore", "unsubscribe", @@ -306,8 +305,8 @@ "paths": { "/get": { "description": "Get monitoring data.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -338,8 +337,8 @@ }, "/set": { "description": "Set monitoring actions.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -364,8 +363,8 @@ }, "/trace": { "description": "Set monitoring actions.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", @@ -396,8 +395,8 @@ }, "/session": { "description": "describes the session.", + "x-permissions": { "session": "check" }, "get": { - "x-permissions": { "session": "check" }, "parameters": [ { "in": "query", diff --git a/src/jobs-fake.c b/src/jobs-fake.c index d3444e32..d3cd19e1 100644 --- a/src/jobs-fake.c +++ b/src/jobs-fake.c @@ -71,7 +71,7 @@ static int add_job(const void *group, int timeout, void (*callback)(int signum, else first = j; last = j; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); return 0; } @@ -83,7 +83,7 @@ static void *thrrun(void *arg) j = first; if (j) first = j->next; - pthread_mutex_unlock(&mutex); + pthread_mutex_unlock(&mutex); if (j) { j->callback(0, j->closure); free(j); @@ -716,7 +716,7 @@ static int on_evloop_efd(sd_event_source *s, int fd, uint32_t revents, void *use struct evloop *evloop = userdata; read(evloop->efd, &x, sizeof x); pthread_mutex_lock(&mutex); - pthread_cond_broadcast(&evloop->cond); + pthread_cond_broadcast(&evloop->cond); pthread_mutex_unlock(&mutex); return 1; } diff --git a/src/afb-client-demo.c b/src/main-afb-client-demo.c index 011de2b5..4e865879 100644 --- a/src/afb-client-demo.c +++ b/src/main-afb-client-demo.c @@ -41,15 +41,13 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg); static void on_pws_hangup(void *closure); -static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info); -static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info); +static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info); static void on_pws_event_create(void *closure, const char *event_name, int event_id); static void on_pws_event_remove(void *closure, const char *event_name, int event_id); static void on_pws_event_subscribe(void *closure, void *request, const char *event_name, int event_id); static void on_pws_event_unsubscribe(void *closure, void *request, const char *event_name, int event_id); static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data); static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data); -static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args); static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, void *closure); @@ -65,15 +63,13 @@ static struct afb_wsj1_itf wsj1_itf = { /* the callback interface for pws */ static struct afb_proto_ws_client_itf pws_itf = { - .on_reply_success = on_pws_reply_success, - .on_reply_fail = on_pws_reply_fail, + .on_reply = on_pws_reply, .on_event_create = on_pws_event_create, .on_event_remove = on_pws_event_remove, .on_event_subscribe = on_pws_event_subscribe, .on_event_unsubscribe = on_pws_event_unsubscribe, .on_event_push = on_pws_event_push, .on_event_broadcast = on_pws_event_broadcast, - .on_subcall = on_pws_subcall, }; /* global variables */ @@ -96,18 +92,18 @@ static void usage(int status, char *arg0) name = name ? name + 1 : arg0; fprintf(status ? stderr : stdout, "usage: %s [-H [-r]] [-b] [-e] uri [api verb [data]]\n", name); fprintf(status ? stderr : stdout, " %s -d [-H [-r]] [-b] [-e] uri [verb [data]]\n", name); - fprintf(status ? stderr : stdout, "\n" \ - "allowed options\n" \ - " --break, -b Break connection just after event/call has been emitted.\n" \ - " --direct, -d Direct api\n" \ - " --echo, -e Echo inputs\n" \ - " --help, -h Display this help\n" \ - " --human, -H Display human readable JSON\n" \ - " --raw, -r Raw output (default)\n" \ - "Example:\n" \ - " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n" - "\n", name - ); + fprintf(status ? stderr : stdout, "\n" + "allowed options\n" + " --break, -b Break connection just after event/call has been emitted.\n" + " --direct, -d Direct api\n" + " --echo, -e Echo inputs\n" + " --help, -h Display this help\n" + " --human, -H Display human readable JSON\n" + " --raw, -r Raw output (default)\n" + "Example:\n" + " %s --human 'localhost:1234/api?token=HELLO&uuid=magic' hello ping\n" + "\n", name + ); exit(status); } @@ -233,7 +229,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc { int rc; if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-CALL %s/%s:\n%s\n", api, verb, json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg), @@ -248,7 +244,7 @@ static void on_wsj1_call(void *closure, const char *api, const char *verb, struc static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg *msg) { if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-EVENT %s:\n%s\n", event, json_object_to_json_string_ext(afb_wsj1_msg_object_j(msg), @@ -260,7 +256,7 @@ static void on_wsj1_event(void *closure, const char *event, struct afb_wsj1_msg static void on_wsj1_reply(void *closure, struct afb_wsj1_msg *msg) { if (raw) - printf("%s", afb_wsj1_msg_object_s(msg)); + printf("%s\n", afb_wsj1_msg_object_s(msg)); if (human) printf("ON-REPLY %s: %s\n%s\n", (char*)closure, afb_wsj1_msg_is_reply_ok(msg) ? "OK" : "ERROR", @@ -393,20 +389,25 @@ static int io_event_callback(sd_event_source *src, int fd, uint32_t revents, voi return 1; } -static void on_pws_reply_success(void *closure, void *request, struct json_object *result, const char *info) +static void on_pws_reply(void *closure, void *request, struct json_object *result, const char *error, const char *info) { - if (raw) - printf("%s", json_object_to_json_string(result)); + error = error ?: "success"; + if (raw) { + /* TODO: transitionnal: fake the structured response */ + struct json_object *x = json_object_new_object(), *y = json_object_new_object(); + json_object_object_add(x, "jtype", json_object_new_string("afb-reply")); + json_object_object_add(x, "request", y); + json_object_object_add(y, "status", json_object_new_string(error)); + if (info) + json_object_object_add(y, "info", json_object_new_string(info)); + if (result) + json_object_object_add(x, "response", json_object_get(result)); + + printf("%s\n", json_object_to_json_string(x)); + json_object_put(x); + } if (human) - printf("ON-REPLY-SUCCESS %s: %s\n%s\n", (char*)request, info?:"", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY)); - fflush(stdout); - free(request); - dec_callcount(); -} - -static void on_pws_reply_fail(void *closure, void *request, const char *status, const char *info) -{ - printf("ON-REPLY-FAIL %s: %s [%s]\n", (char*)request, status?:"?", info?:""); + printf("ON-REPLY %s: %s %s\n%s\n", (char*)request, error, info ?: "", json_object_to_json_string_ext(result, JSON_C_TO_STRING_PRETTY)); fflush(stdout); free(request); dec_callcount(); @@ -439,7 +440,7 @@ static void on_pws_event_unsubscribe(void *closure, void *request, const char *e static void on_pws_event_push(void *closure, const char *event_name, int event_id, struct json_object *data) { if (raw) - printf("%s", json_object_to_json_string(data)); + printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, 0)); if (human) printf("ON-EVENT-PUSH: [%d:%s]\n%s\n", event_id, event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY)); fflush(stdout); @@ -448,22 +449,12 @@ static void on_pws_event_push(void *closure, const char *event_name, int event_i static void on_pws_event_broadcast(void *closure, const char *event_name, struct json_object *data) { if (raw) - printf("%s", json_object_to_json_string(data)); + printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, 0)); if (human) printf("ON-EVENT-BROADCAST: [%s]\n%s\n", event_name, json_object_to_json_string_ext(data, JSON_C_TO_STRING_PRETTY)); fflush(stdout); } -static void on_pws_subcall(void *closure, struct afb_proto_ws_subcall *subcall, void *request, const char *api, const char *verb, struct json_object *args) -{ - if (raw) - printf("%s", json_object_to_json_string(args)); - if (human) - printf("ON-SUBCALL %s: %s/%s\n%s\n", (char*)request, api, verb, json_object_to_json_string_ext(args, JSON_C_TO_STRING_PRETTY)); - afb_proto_ws_subcall_reply(subcall, 1, NULL); - fflush(stdout); -} - /* makes a call */ static void pws_call(const char *verb, const char *object) { @@ -488,7 +479,7 @@ static void pws_call(const char *verb, const char *object) if (!o) o = json_object_new_string(object); } - rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key); + rc = afb_proto_ws_client_call(pws, verb, o, sessionid, key, NULL); json_object_put(o); if (rc < 0) { fprintf(stderr, "calling %s(%s) failed: %m\n", verb, object?:""); diff --git a/src/main.c b/src/main-afb-daemon.c index 8c243f73..8b1a2b23 100644 --- a/src/main.c +++ b/src/main-afb-daemon.c @@ -39,6 +39,7 @@ #include "afb-config.h" #include "afb-hswitch.h" #include "afb-apiset.h" +#include "afb-autoset.h" #include "afb-api-so.h" #if defined(WITH_DBUS_TRANSPARENCY) # include "afb-api-dbus.h" @@ -90,12 +91,13 @@ 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, struct afb_apiset *apiset) = closure; - return starter(value, main_apiset) >= 0; + int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set) = closure; + return starter(value, main_apiset, main_apiset) >= 0; } static void apiset_start_list(struct afb_config_list *list, - int (*starter) (const char *value, struct afb_apiset *apiset), const char *message) + int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set), + const char *message) { list = run_for_list(list, run_start, starter); if (list) { @@ -263,17 +265,17 @@ static struct afb_hsrv *start_http_server() return NULL; } - if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cacheTimeout) + if (!afb_hsrv_set_cache_timeout(hsrv, main_config->cache_timeout) || !init_http_server(hsrv)) { ERROR("initialisation of httpd failed"); afb_hsrv_put(hsrv); return NULL; } - NOTICE("Waiting port=%d rootdir=%s", main_config->httpdPort, main_config->rootdir); - NOTICE("Browser URL= http://localhost:%d", main_config->httpdPort); + NOTICE("Waiting port=%d rootdir=%s", main_config->http_port, main_config->rootdir); + NOTICE("Browser URL= http://localhost:%d", main_config->http_port); - rc = afb_hsrv_start(hsrv, (uint16_t) main_config->httpdPort, 15); + rc = afb_hsrv_start(hsrv, (uint16_t) main_config->http_port, 15); if (!rc) { ERROR("starting of httpd failed"); afb_hsrv_put(hsrv); @@ -419,8 +421,8 @@ static int execute_command() return 0; /* compute the string for port */ - if (main_config->httpdPort) - rc = snprintf(port, sizeof port, "%d", main_config->httpdPort); + if (main_config->http_port) + rc = snprintf(port, sizeof port, "%d", main_config->http_port); else rc = snprintf(port, sizeof port, "%cp", SUBST_CHAR); if (rc < 0 || rc >= (int)(sizeof port)) { @@ -455,14 +457,16 @@ struct startup_req struct afb_session *session; }; -static void startup_call_reply(struct afb_xreq *xreq, int status, struct json_object *obj) +static void startup_call_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info) { struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq); - if (status >= 0) - NOTICE("startup call %s returned %s", sreq->current->value, json_object_get_string(obj)); - else { - ERROR("startup call %s ERROR! %s", sreq->current->value, json_object_get_string(obj)); + info = info ?: ""; + if (!error) { + NOTICE("startup call %s returned %s (%s)", sreq->current->value, json_object_get_string(object), info); + json_object_put(object); + } else { + ERROR("startup call %s ERROR! %s (%s)", sreq->current->value, error, info); exit(1); } } @@ -506,8 +510,8 @@ static void startup_call_current(struct startup_req *sreq) sreq->xreq.context.validated = 1; sreq->api = strndup(api, verb - api); sreq->verb = strndup(verb + 1, json - verb - 1); - sreq->xreq.request.api = sreq->api; - sreq->xreq.request.verb = sreq->verb; + sreq->xreq.request.called_api = sreq->api; + sreq->xreq.request.called_verb = sreq->verb; sreq->xreq.json = json_tokener_parse(json + 1); if (sreq->api && sreq->verb && sreq->xreq.json) { afb_xreq_process(&sreq->xreq, main_apiset); @@ -560,16 +564,16 @@ static void start(int signum, void *arg) } /* configure the daemon */ - if (afb_session_init(main_config->nbSessionMax, main_config->cntxTimeout, main_config->token)) { + if (afb_session_init(main_config->max_session_count, main_config->session_timeout, main_config->token)) { ERROR("initialisation of session manager failed"); goto error; } - main_apiset = afb_apiset_create("main", main_config->apiTimeout); + main_apiset = afb_apiset_create("main", main_config->api_timeout); if (!main_apiset) { ERROR("can't create main api set"); goto error; } - if (afb_monitor_init() < 0) { + if (afb_monitor_init(main_apiset, main_apiset) < 0) { ERROR("failed to setup monitor"); goto error; } @@ -581,10 +585,8 @@ static void start(int signum, void *arg) /* install hooks */ if (main_config->tracereq) afb_hook_create_xreq(NULL, NULL, NULL, main_config->tracereq, NULL, NULL); - if (main_config->traceditf) - afb_hook_create_ditf(NULL, main_config->traceditf, NULL, NULL); - if (main_config->tracesvc) - afb_hook_create_svc(NULL, main_config->tracesvc, NULL, NULL); + if (main_config->traceapi) + afb_hook_create_api(NULL, main_config->traceapi, NULL, NULL); if (main_config->traceevt) afb_hook_create_evt(NULL, main_config->traceevt, NULL, NULL); if (main_config->traceses) @@ -599,6 +601,8 @@ static void start(int signum, void *arg) apiset_start_list(main_config->ws_clients, afb_api_ws_add_client_weak, "the afb-websocket client"); apiset_start_list(main_config->ldpaths, afb_api_so_add_pathset_fails, "the binding path set"); apiset_start_list(main_config->weak_ldpaths, afb_api_so_add_pathset_nofails, "the weak binding path set"); + apiset_start_list(main_config->auto_ws, afb_autoset_add_ws, "the automatic afb-websocket path set"); + apiset_start_list(main_config->auto_link, afb_autoset_add_so, "the automatic link binding path set"); #if defined(WITH_DBUS_TRANSPARENCY) apiset_start_list(main_config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service"); @@ -617,13 +621,13 @@ static void start(int signum, void *arg) /* start the HTTP server */ afb_debug("start-http"); - if (!main_config->noHttpd) { - if (main_config->httpdPort <= 0) { + if (!main_config->no_httpd) { + if (main_config->http_port <= 0) { ERROR("no port is defined"); goto error; } - if (!afb_hreq_init_cookie(main_config->httpdPort, main_config->rootapi, main_config->cntxTimeout)) { + if (!afb_hreq_init_cookie(main_config->http_port, main_config->rootapi, main_config->session_timeout)) { ERROR("initialisation of HTTP cookies failed"); goto error; } diff --git a/src/afs-main.c b/src/main-afs-supervisor.c index 88e4757f..14f1c3b0 100644 --- a/src/afs-main.c +++ b/src/main-afs-supervisor.c @@ -144,7 +144,7 @@ static void start(int signum, void *arg) } /* init the main apiset */ - rc = afs_supervisor_add(main_apiset); + rc = afs_supervisor_add(main_apiset, main_apiset); if (rc < 0) { ERROR("Can't create supervision's apiset: %m"); goto error; @@ -152,7 +152,7 @@ static void start(int signum, void *arg) /* export the service if required */ if (main_config->ws_server) { - rc = afb_api_ws_add_server(main_config->ws_server, main_apiset); + rc = afb_api_ws_add_server(main_config->ws_server, main_apiset, main_apiset); if (rc < 0) { ERROR("Can't export (ws-server) api %s: %m", main_config->ws_server); goto error; diff --git a/src/monitor-api.inc b/src/monitor-api.inc index cbc1187f..e4dc2c92 100644 --- a/src/monitor-api.inc +++ b/src/monitor-api.inc @@ -1,5 +1,5 @@ -static const char _afb_description_v2_monitor[] = +static const char _afb_description_monitor[] = "{\"openapi\":\"3.0.0\",\"info\":{\"description\":\"monitoring of binding" "s and internals\",\"title\":\"monitor\",\"version\":\"1.0\",\"x-binding-" "c-generator\":{\"api\":\"monitor\",\"version\":2,\"prefix\":\"f_\",\"pos" @@ -118,57 +118,68 @@ static const char _afb_description_v2_monitor[] = "}}}}}}}}}" ; -static void f_get(struct afb_req req); -static void f_set(struct afb_req req); -static void f_trace(struct afb_req req); -static void f_session(struct afb_req req); +static void f_get(afb_req_t req); +static void f_set(afb_req_t req); +static void f_trace(afb_req_t req); +static void f_session(afb_req_t req); -static const struct afb_verb_v2 _afb_verbs_v2_monitor[] = { +static const struct afb_verb_v3 _afb_verbs_monitor[] = { { .verb = "get", .callback = f_get, .auth = NULL, .info = "Get monitoring data.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "set", .callback = f_set, .auth = NULL, .info = "Set monitoring actions.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "trace", .callback = f_trace, .auth = NULL, .info = "Set monitoring actions.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = "session", .callback = f_session, .auth = NULL, .info = "describes the session.", - .session = AFB_SESSION_CHECK_V2 + .session = AFB_SESSION_CHECK, + .vcbdata = NULL, + .glob = 0 }, { .verb = NULL, .callback = NULL, .auth = NULL, .info = NULL, - .session = 0 + .session = 0, + .vcbdata = NULL, + .glob = 0 } }; -static const struct afb_binding_v2 _afb_binding_v2_monitor = { +static const struct afb_binding_v3 _afb_binding_monitor = { .api = "monitor", - .specification = _afb_description_v2_monitor, + .specification = _afb_description_monitor, .info = "monitoring of bindings and internals", - .verbs = _afb_verbs_v2_monitor, + .verbs = _afb_verbs_monitor, .preinit = NULL, .init = NULL, .onevent = NULL, + .userdata = NULL, .noconcurrency = 0 }; diff --git a/src/pearson.c b/src/pearson.c new file mode 100644 index 00000000..a39c8952 --- /dev/null +++ b/src/pearson.c @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2018 "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. + */ + +#include <stdint.h> + +/* + * Returns a tiny hash value for the 'text'. + * + * Tiny hash function inspired from pearson + */ +uint8_t pearson4(const char *text) +{ + static uint8_t T[16] = { + 4, 1, 6, 0, 9, 14, 11, 5, + 2, 3, 12, 15, 10, 7, 8, 13 + }; + uint8_t r, c; + + for (r = 0; (c = (uint8_t)*text) ; text++) { + r = T[r ^ (15 & c)]; + r = T[r ^ (c >> 4)]; + } + return r; // % HEADCOUNT; +} + diff --git a/src/pearson.h b/src/pearson.h new file mode 100644 index 00000000..2daa6546 --- /dev/null +++ b/src/pearson.h @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2018 "IoT.bzh" + * Author: José Bollo <jose.bollo@iot.bzh> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +extern uint8_t pearson4(const char *text); diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index f63f27ae..f0349a68 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -22,6 +22,8 @@ if(check_FOUND) INCLUDE_DIRECTORIES(${INCLUDE_DIRS} ${check_INCLUDE_DIRS}) SET(link_libraries ${link_libraries} ${check_LDFLAGS}) add_subdirectory(session) + add_subdirectory(apiset) + add_subdirectory(apiv3) else(check_FOUND) MESSAGE(WARNING "check not found! no test!") endif(check_FOUND) diff --git a/src/tests/apiset/CMakeLists.txt b/src/tests/apiset/CMakeLists.txt new file mode 100644 index 00000000..180c80b8 --- /dev/null +++ b/src/tests/apiset/CMakeLists.txt @@ -0,0 +1,23 @@ +########################################################################### +# Copyright (C) 2018 "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. +########################################################################### + +add_executable(test-apiset test-apiset.c) +target_include_directories(test-apiset PRIVATE ../..) +target_link_libraries(test-apiset afb-lib ${link_libraries}) +add_test(NAME apiset COMMAND test-apiset) + diff --git a/src/tests/apiset/test-apiset.c b/src/tests/apiset/test-apiset.c new file mode 100644 index 00000000..bdc84137 --- /dev/null +++ b/src/tests/apiset/test-apiset.c @@ -0,0 +1,579 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> + +#include <check.h> +#if !defined(ck_assert_ptr_null) +# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL) +# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL) +#endif + +#include "afb-api.h" +#include "afb-apiset.h" + +const char *names[] = { + "Sadie", + "Milford", + "Yvette", + "Carma", + "Cory", + "Clarence", + "Jeffery", + "Molly", + "Sheba", + "Tasha", + "Corey", + "Gerry", + NULL +}; + +const char *aliases[] = { + "Rich", "Molly", + "Alicia", "Carma", + "Drema", "YVETTE", + "Pablo", "Sheba", + "Wendell", "Sadie", + "Cathrine", "CarMa", + "Allen", "Corey", + "Tori", "Drema", + NULL +}; + +const char *extras[] = { + "Meta", + "Delia", + "Pearlie", + "Hank", + "Vena", + "Terrance", + "Gloria", + "Tobi", + "Mack", + "Rosalee", + NULL +}; + +struct afb_api_itf api_itf_null = { + .call = NULL, + .service_start = NULL, + .update_hooks = NULL, + .get_logmask = NULL, + .set_logmask = NULL, + .describe = NULL, + .unref = NULL +}; + + +/*********************************************************************/ +/* check the initialisation */ +START_TEST (check_initialisation) +{ + const char name[] = "name"; + const char noname[] = ""; + int to = 3600; + int noto = -1; + struct afb_apiset *a, *b; + + a = afb_apiset_create(NULL, noto); + ck_assert_ptr_nonnull(a); + ck_assert_str_eq(noname, afb_apiset_name(a)); + ck_assert_int_eq(noto, afb_apiset_timeout_get(a)); + afb_apiset_timeout_set(a, to); + ck_assert_int_eq(to, afb_apiset_timeout_get(a)); + b = afb_apiset_addref(a); + ck_assert_ptr_eq(a, b); + afb_apiset_unref(b); + afb_apiset_unref(a); + + a = afb_apiset_create(name, to); + ck_assert_ptr_nonnull(a); + ck_assert_str_eq(name, afb_apiset_name(a)); + ck_assert_int_eq(to, afb_apiset_timeout_get(a)); + afb_apiset_timeout_set(a, noto); + ck_assert_int_eq(noto, afb_apiset_timeout_get(a)); + b = afb_apiset_addref(a); + ck_assert_ptr_eq(a, b); + afb_apiset_unref(b); + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ +/* check that NULL is a valid value for addref/unref */ +START_TEST (check_sanity) +{ + struct afb_apiset *a; + + a = afb_apiset_addref(NULL); + ck_assert_ptr_null(a); + afb_apiset_unref(NULL); + ck_assert(1); +} +END_TEST + +/*********************************************************************/ +/* check creation and retrieval of apis */ + +START_TEST (check_creation) +{ + int i, j, nn, na; + struct afb_apiset *a; + struct afb_api_item sa; + const char *x, *y, **set; + const struct afb_api_item *pa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; names[i] != NULL ; i++) { + sa.itf = &api_itf_null; + sa.closure = (void*)names[i]; + sa.group = names[i]; + ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa)); + pa = afb_apiset_lookup(a, names[i], 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(sa.itf, pa->itf); + ck_assert_ptr_eq(sa.closure, pa->closure); + ck_assert_ptr_eq(sa.group, pa->group); + ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i])); + ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i])); + ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa)); + ck_assert_int_eq(errno, EEXIST); + } + nn = i; + + /* add aliases */ + for (i = 0 ; aliases[i] != NULL ; i += 2) { + ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i])); + ck_assert_int_eq(errno, ENOENT); + ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i])); + x = afb_apiset_unalias(a, aliases[i]); + y = afb_apiset_unalias(a, aliases[i + 1]); + ck_assert_int_eq(0, strcasecmp(x, y)); + ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_int_eq(errno, EEXIST); + } + na = i / 2; + + /* check extras */ + for (i = 0 ; extras[i] != NULL ; i++) { + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_ptr_null(pa); + ck_assert_int_eq(errno, ENOENT); + } + + /* get the names */ + set = afb_apiset_get_names(a, 0, 1); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + ck_assert_int_eq(0, afb_apiset_is_alias(a, set[i])); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, nn); + free(set); + set = afb_apiset_get_names(a, 0, 2); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, set[i])); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, na); + free(set); + set = afb_apiset_get_names(a, 0, 3); + ck_assert_ptr_nonnull(set); + for (i = 0 ; set[i] != NULL ; i++) { + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + if (i) + ck_assert_int_gt(0, strcasecmp(set[i-1], set[i])); + } + ck_assert_int_eq(i, nn + na); + + /* removes the apis to check deletion */ + for (i = 0 ; i < nn + na ; i++) { + if (!set[i]) + continue; + + /* should be present */ + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[i], 0)); + + /* deleting a non aliased api removes the aliases! */ + if (!afb_apiset_is_alias(a, set[i])) { + for (j = i + 1 ; j < nn + na ; j++) { + if (!set[j]) + continue; + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0)); + if (afb_apiset_is_alias(a, set[j]) + && afb_apiset_lookup(a, set[i], 0) == afb_apiset_lookup(a, set[j], 0)) { + ck_assert(set[j][0] > 0); + ((char*)set[j])[0] = (char)-set[j][0]; + } + } + } + + /* delete now */ + ck_assert_int_eq(0, afb_apiset_del(a, set[i])); + ck_assert_ptr_null(afb_apiset_lookup(a, set[i], 0)); + + /* check other not removed except aliases */ + for (j = i + 1 ; j < nn + na ; j++) { + if (!set[j]) + continue; + if (set[j][0] > 0) + ck_assert_ptr_nonnull(afb_apiset_lookup(a, set[j], 0)); + else { + ((char*)set[j])[0] = (char)-set[j][0]; + ck_assert_ptr_null(afb_apiset_lookup(a, set[j], 0)); + set[j] = NULL; + } + } + } + free(set); + + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ +/* check onlack behaviour */ + +int onlackcount; + +static void onlackcleanup(void *closure) +{ + int *count = closure; + ck_assert_ptr_eq(count, &onlackcount); + *count = 0; +} +static int onlack(void *closure, struct afb_apiset *a, const char *name) +{ + int *count = closure; + struct afb_api_item sa; + + ck_assert_ptr_eq(count, &onlackcount); + (*count)++; + + sa.itf = &api_itf_null; + sa.closure = (void*)name; + sa.group = name; + + ck_assert_int_eq(0, afb_apiset_add(a, name, sa)); + return 1; +} + +START_TEST (check_onlack) +{ + int i; + struct afb_apiset *a; + struct afb_api_item sa; + const char *x, *y; + const struct afb_api_item *pa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; names[i] != NULL ; i++) { + sa.itf = &api_itf_null; + sa.closure = (void*)names[i]; + sa.group = names[i]; + ck_assert_int_eq(0, afb_apiset_add(a, names[i], sa)); + pa = afb_apiset_lookup(a, names[i], 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(sa.itf, pa->itf); + ck_assert_ptr_eq(sa.closure, pa->closure); + ck_assert_ptr_eq(sa.group, pa->group); + ck_assert_int_eq(0, afb_apiset_is_alias(a, names[i])); + ck_assert_str_eq(names[i], afb_apiset_unalias(a, names[i])); + ck_assert_int_eq(-1, afb_apiset_add(a, names[i], sa)); + ck_assert_int_eq(errno, EEXIST); + } + + /* add aliases */ + for (i = 0 ; aliases[i] != NULL ; i += 2) { + ck_assert_int_eq(-1, afb_apiset_add_alias(a, extras[0], aliases[i])); + ck_assert_int_eq(errno, ENOENT); + ck_assert_int_eq(0, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_ptr_nonnull(afb_apiset_lookup(a, aliases[i], 1)); + ck_assert_int_eq(1, afb_apiset_is_alias(a, aliases[i])); + x = afb_apiset_unalias(a, aliases[i]); + y = afb_apiset_unalias(a, aliases[i + 1]); + ck_assert_int_eq(0, strcasecmp(x, y)); + ck_assert_int_eq(-1, afb_apiset_add_alias(a, aliases[i + 1], aliases[i])); + ck_assert_int_eq(errno, EEXIST); + } + + /* check extras */ + for (i = 0 ; extras[i] != NULL ; i++) { + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_ptr_null(pa); + ck_assert_int_eq(errno, ENOENT); + } + + /* put the onlack feature */ + afb_apiset_onlack_set(a, onlack, &onlackcount, onlackcleanup); + + /* check extras */ + onlackcount = 0; + for (i = 0 ; extras[i] != NULL ; i++) { + ck_assert_int_eq(onlackcount, i); + pa = afb_apiset_lookup(a, extras[i], 1); + ck_assert_int_eq(onlackcount, i + 1); + ck_assert_ptr_nonnull(pa); + ck_assert_ptr_eq(&api_itf_null, pa->itf); + ck_assert_ptr_eq(extras[i], pa->closure); + ck_assert_ptr_eq(extras[i], pa->group); + } + + ck_assert_int_eq(onlackcount, i); + afb_apiset_unref(a); + ck_assert_int_eq(onlackcount, 0); +} +END_TEST + +/*********************************************************************/ + +struct set_api { + const char *name; + int init; + int mask; +} set_apis[] = { + { "Sadie", 0, 0 }, + { "Milford", 0, 0 }, + { "Yvette", 0, 0 }, + { "Carma", 0, 0 }, + { "Cory", 0, 0 }, + { "Clarence", 0, 0 }, + { "Jeffery", 0, 0 }, + { "Molly", 0, 0 }, + { "Sheba", 0, 0 }, + { "Tasha", 0, 0 }, + { "Corey", 0, 0 }, + { "Gerry", 0, 0 }, + { NULL, 0, 0 } +}; + +int set_count; +struct set_api *set_last_api; + +void set_cb0(void *closure) +{ + set_last_api = closure; + set_count++; +} + +void set_cb_setmask(void *closure, int mask) +{ + set_cb0(closure); + set_last_api->mask = mask; +} + +int set_cb_getmask(void *closure) +{ + set_cb0(closure); + return set_last_api->mask; +} + +int set_cb_start(void *closure, int share_session, int onneed) +{ + set_cb0(closure); + ck_assert_int_eq(0, set_last_api->init); + set_last_api->init = 1; + return 0; +} + +struct afb_api_itf set_api_itf = { + .call = NULL, + .service_start = set_cb_start, + .update_hooks = set_cb0, + .get_logmask = set_cb_getmask, + .set_logmask = set_cb_setmask, + .describe = NULL, + .unref = set_cb0 +}; + +START_TEST (check_settings) +{ + int i, nn, mask; + struct afb_apiset *a; + struct afb_api_item sa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; set_apis[i].name != NULL ; i++) { + sa.itf = &set_api_itf; + sa.closure = &set_apis[i]; + sa.group = NULL; + ck_assert_int_eq(0, afb_apiset_add(a, set_apis[i].name, sa)); + } + nn = i; + + set_count = 0; + afb_apiset_start_all_services(a, 1); + ck_assert_int_eq(nn, set_count); + + set_count = 0; + afb_apiset_update_hooks(a, NULL); + ck_assert_int_eq(nn, set_count); + + for (mask = 1 ; !(mask >> 10) ; mask <<= 1) { + set_count = 0; + afb_apiset_set_logmask(a, NULL, mask); + ck_assert_int_eq(nn, set_count); + set_count = 0; + for (i = 0 ; set_apis[i].name != NULL ; i++) { + ck_assert_int_eq(mask, afb_apiset_get_logmask(a, set_apis[i].name)); + ck_assert_ptr_eq(set_last_api, &set_apis[i]); + ck_assert_int_eq(i + 1, set_count); + } + } + + set_count = 0; + afb_apiset_unref(a); + ck_assert_int_eq(nn, set_count); +} +END_TEST + +/*********************************************************************/ + +struct clacl { + const char *name; + int count; +} clacl[] = { + { "Sadie", 0 }, + { "Milford", 0 }, + { "Yvette", 0 }, +}; + +struct clapi { + const char *name; + const char *provides; + const char *requires; + const char *apireq; + int init; + int expect; +} clapi[] = { + { "Carma", "", "Sadie", "", 0, 9 }, + { "Cory", "Milford", "", "Clarence", 0, 3 }, + { "Clarence", "Milford", "", "Jeffery", 0, 2 }, + { "Jeffery", "Milford", "", "", 0, 1 }, + { "Molly", "Yvette", "", "Corey", 0, 6 }, + { "Sheba", "Yvette", "Milford", "Molly", 0, 7 }, + { "Tasha", "Sadie", "Yvette", "", 0, 8 }, + { "Corey", "Sadie", "Milford", "Gerry", 0, 5 }, + { "Gerry", "Sadie", "Milford", "", 0, 4 }, + { NULL, NULL, NULL, NULL, 0, 0 } +}; + +int clorder; + +int clacb_start(void *closure, int share_session, int onneed) +{ + struct clapi *a = closure; + int i; + + ck_assert_int_eq(0, a->init); + + for (i = 0 ; clapi[i].name ; i++) { + if (a->requires && a->requires[0] + && clapi[i].provides && clapi[i].provides[0] + && !strcmp(a->requires, clapi[i].provides)) + ck_assert_int_ne(0, clapi[i].init); + if (a->apireq && a->apireq[0] + && !strcmp(a->apireq, clapi[i].name)) + ck_assert_int_ne(0, clapi[i].init); + } + a->init = ++clorder; + ck_assert_int_eq(a->init, a->expect); + + return 0; +} + +struct afb_api_itf clitf = { + .call = NULL, + .service_start = clacb_start, + .update_hooks = NULL, + .get_logmask = NULL, + .set_logmask = NULL, + .describe = NULL, + .unref = NULL +}; + +START_TEST (check_classes) +{ + int i; + struct afb_apiset *a; + struct afb_api_item sa; + + /* create a apiset */ + a = afb_apiset_create(NULL, 0); + ck_assert_ptr_nonnull(a); + + /* add apis */ + for (i = 0 ; clapi[i].name != NULL ; i++) { + sa.itf = &clitf; + sa.closure = &clapi[i]; + sa.group = NULL; + ck_assert_int_eq(0, afb_apiset_add(a, clapi[i].name, sa)); + } + + /* add constraints */ + for (i = 0 ; clapi[i].name != NULL ; i++) { + if (clapi[i].provides && clapi[i].provides[0]) + ck_assert_int_eq(0, afb_apiset_provide_class(a, clapi[i].name, clapi[i].provides)); + if (clapi[i].requires && clapi[i].requires[0]) + ck_assert_int_eq(0, afb_apiset_require_class(a, clapi[i].name, clapi[i].requires)); + if (clapi[i].apireq && clapi[i].apireq[0]) + ck_assert_int_eq(0, afb_apiset_require(a, clapi[i].name, clapi[i].apireq)); + } + + /* start all */ + ck_assert_int_eq(0, afb_apiset_start_all_services(a, 0)); + + afb_apiset_unref(a); +} +END_TEST + +/*********************************************************************/ + +static Suite *suite; +static TCase *tcase; + +void mksuite(const char *name) { suite = suite_create(name); } +void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); } +void addtest(TFun fun) { tcase_add_test(tcase, fun); } +int srun() +{ + int nerr; + SRunner *srunner = srunner_create(suite); + srunner_run_all(srunner, CK_NORMAL); + nerr = srunner_ntests_failed(srunner); + srunner_free(srunner); + return nerr; +} + +int main(int ac, char **av) +{ + mksuite("apiset"); + addtcase("apiset"); + addtest(check_initialisation); + addtest(check_sanity); + addtest(check_creation); + addtest(check_onlack); + addtest(check_settings); + addtest(check_classes); + return !!srun(); +} diff --git a/src/tests/apiv3/CMakeLists.txt b/src/tests/apiv3/CMakeLists.txt new file mode 100644 index 00000000..dfc44619 --- /dev/null +++ b/src/tests/apiv3/CMakeLists.txt @@ -0,0 +1,24 @@ +########################################################################### +# Copyright (C) 2018 "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. +########################################################################### + +add_executable(test-apiv3 test-apiv3.c) +target_include_directories(test-apiv3 PRIVATE ../..) +target_link_libraries(test-apiv3 afb-lib ${link_libraries}) +add_test(NAME apiv3 COMMAND test-apiv3) + + diff --git a/src/tests/apiv3/test-apiv3.c b/src/tests/apiv3/test-apiv3.c new file mode 100644 index 00000000..dec1af97 --- /dev/null +++ b/src/tests/apiv3/test-apiv3.c @@ -0,0 +1,198 @@ +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> +#include <errno.h> +#include <string.h> + +#include <check.h> + +#if !defined(ck_assert_ptr_null) +# define ck_assert_ptr_null(X) ck_assert_ptr_eq(X, NULL) +# define ck_assert_ptr_nonnull(X) ck_assert_ptr_ne(X, NULL) +#endif + +#define AFB_BINDING_VERSION 0 +#include <afb/afb-binding.h> +#include "afb-api.h" +#include "afb-apiset.h" +#include "afb-api-v3.h" + +struct inapis { + struct afb_binding_v3 desc; + struct afb_api_x3 *api; + int init; +}; + +struct inapis inapis[] = { + { .desc = { + .api = "ezra", + .provide_class = "e", + .require_class = "c", + .require_api = "armel" + }}, + { .desc = { + .api = "clara", + .provide_class = "c", + .require_class = "a" + }}, + { .desc = { + .api = "amelie", + .provide_class = "a", + .require_api = "albert armel" + }}, + { .desc = { + .api = "chloe", + .provide_class = "c a" + }}, + { .desc = { + .api = "albert", + .provide_class = "a" + }}, + { .desc = { + .api = "armel", + .provide_class = "a", + .require_api = "albert" + }}, + { .desc = { .api = NULL }} +}; + +int last_in_init; + +int in_init(struct afb_api_x3 *api) +{ + struct inapis *desc = api->userdata; + + ck_assert_str_eq(api->apiname, desc->desc.api); + ck_assert_int_eq(desc->init, 0); + + desc->init = ++last_in_init; + printf("init %d of %s\n", desc->init, api->apiname); + return 0; +} + +int in_preinit(void *closure, struct afb_api_x3 *api) +{ + int rc; + struct inapis *desc = closure; + + printf("default preinit of %s\n", api->apiname); + + ck_assert_ptr_nonnull(api); + ck_assert_ptr_nonnull(desc); + ck_assert_ptr_nonnull(api->apiname); + ck_assert_ptr_null(api->userdata); + ck_assert_str_eq(api->apiname, desc->desc.api); + ck_assert_ptr_null(desc->api); + ck_assert_int_eq(desc->init, 0); + + rc = afb_api_v3_set_binding_fields(&desc->desc, api); + ck_assert_int_eq(rc, 0); + + api->userdata = desc; + desc->api = api; + + if (desc->desc.preinit) + desc->desc.preinit(api); + + if (!desc->desc.init) { + rc = afb_api_x3_on_init(api, in_init); + ck_assert_int_eq(rc, 0); + } + + return 0; +} + +int out_init(struct afb_api_x3 *api) +{ + return 0; +} + +struct afb_apiset *apiset; +char out_apiname[] = "out"; +struct afb_api_v3 *out_v3; +struct afb_api_x3 *out_api; + +int out_preinit(void *closure, struct afb_api_x3 *api) +{ + int i; + int rc; + struct afb_api_x3 *napi; + + ck_assert_ptr_nonnull(api); + ck_assert_ptr_eq(closure, out_apiname); + ck_assert_ptr_null(api->userdata); + ck_assert_str_eq(api->apiname, out_apiname); + out_api = api; + + for (i = 0 ; inapis[i].desc.api ; i++) { + ck_assert_ptr_null(inapis[i].api); + napi = afb_api_x3_new_api( + api, + inapis[i].desc.api, + NULL, + 0, + in_preinit, + &inapis[i]); + ck_assert_ptr_nonnull(napi); + ck_assert_ptr_nonnull(inapis[i].api); + ck_assert_ptr_eq(inapis[i].api, napi); + } + + rc = afb_api_x3_on_init(api, out_init); + ck_assert_int_eq(rc, 0); + + return 0; +} + +START_TEST (test) +{ + int rc; + + apiset = afb_apiset_create("test-apiv3", 1); + ck_assert_ptr_nonnull(apiset); + + out_v3 = afb_api_v3_create( + apiset, + apiset, + out_apiname, + NULL, + 0, + out_preinit, + out_apiname, + 0 + ); + ck_assert_ptr_nonnull(out_v3); + ck_assert_ptr_nonnull(out_api); + + /* start all services */ + rc = afb_apiset_start_all_services(apiset, 1); + ck_assert_int_eq(rc, 0); +} +END_TEST + + +/*********************************************************************/ + +static Suite *suite; +static TCase *tcase; + +void mksuite(const char *name) { suite = suite_create(name); } +void addtcase(const char *name) { tcase = tcase_create(name); suite_add_tcase(suite, tcase); } +void addtest(TFun fun) { tcase_add_test(tcase, fun); } +int srun() +{ + int nerr; + SRunner *srunner = srunner_create(suite); + srunner_run_all(srunner, CK_NORMAL); + nerr = srunner_ntests_failed(srunner); + srunner_free(srunner); + return nerr; +} + +int main(int ac, char **av) +{ + mksuite("apiv3"); + addtcase("apiv3"); + addtest(test); + return !!srun(); +} diff --git a/src/tests/session/test-session.c b/src/tests/session/test-session.c index 58e57536..637b0a16 100644 --- a/src/tests/session/test-session.c +++ b/src/tests/session/test-session.c @@ -55,7 +55,7 @@ START_TEST (check_creation) ck_assert(afb_session_uuid(s) != NULL); ck_assert(afb_session_token(s) != NULL); ck_assert(!afb_session_is_closed(s)); - + /* token is the initial one */ ck_assert_str_eq(afb_session_token(s), GOOD_UUID); ck_assert(afb_session_check_token(s, GOOD_UUID)); diff --git a/src/verbose.c b/src/verbose.c index 3e266a18..5fd1940c 100644 --- a/src/verbose.c +++ b/src/verbose.c @@ -21,14 +21,44 @@ #include "verbose.h" -#if !defined(DEFAULT_VERBOSITY) -# define DEFAULT_VERBOSITY Verbosity_Level_Warning +#define MASKOF(x) (1 << (x)) + +#if !defined(DEFAULT_LOGLEVEL) +# define DEFAULT_LOGLEVEL Log_Level_Warning +#endif + +#if !defined(DEFAULT_LOGMASK) +# define DEFAULT_LOGMASK (MASKOF((DEFAULT_LOGLEVEL) + 1) - 1) +#endif + +#if !defined(MINIMAL_LOGLEVEL) +# define MINIMAL_LOGLEVEL Log_Level_Error #endif -int verbosity = 1; +#if !defined(MINIMAL_LOGMASK) +# define MINIMAL_LOGMASK (MASKOF((MINIMAL_LOGLEVEL) + 1) - 1) +#endif + +static const char *names[] = { + "emergency", + "alert", + "critical", + "error", + "warning", + "notice", + "info", + "debug" +}; + +static const char asort[] = { 1, 2, 7, 0, 3, 6, 5, 4 }; + +int logmask = DEFAULT_LOGMASK | MINIMAL_LOGMASK; + void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); -#define CROP_LOGLEVEL(x) ((x) < Log_Level_Emergency ? Log_Level_Emergency : (x) > Log_Level_Debug ? Log_Level_Debug : (x)) +#define CROP_LOGLEVEL(x) \ + ((x) < Log_Level_Emergency ? Log_Level_Emergency \ + : (x) > Log_Level_Debug ? Log_Level_Debug : (x)) #if defined(VERBOSE_WITH_SYSLOG) @@ -41,7 +71,7 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun if (file == NULL || vasprintf(&p, fmt, args) < 0) vsyslog(loglevel, fmt, args); else { - syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, function]", p, file, line, function); + syslog(CROP_LOGLEVEL(loglevel), "%s [%s:%d, %s]", p, file, line, function?:"?"); free(p); } } @@ -115,14 +145,18 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun int saverr, n, rc; struct iovec iov[20]; + /* save errno */ saverr = errno; + /* check if tty (2) or not (1) */ if (!tty) tty = 1 + isatty(STDERR_FILENO); + /* prefix */ iov[0].iov_base = (void*)prefixes[CROP_LOGLEVEL(loglevel)] + (tty - 1 ? 4 : 0); iov[0].iov_len = strlen(iov[0].iov_base); + /* " " */ iov[1].iov_base = (void*)&chars[2]; iov[1].iov_len = 2; @@ -134,31 +168,40 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun if (rc < 0) rc = 0; else if ((size_t)rc > sizeof buffer) { + /* if too long, ellipsis the end with ... */ rc = (int)sizeof buffer; buffer[rc - 1] = buffer[rc - 2] = buffer[rc - 3] = '.'; } iov[n++].iov_len = (size_t)rc; } if (file && (!fmt || tty == 1 || loglevel <= Log_Level_Warning)) { + /* "[" (!fmt) or " [" (fmt) */ iov[n].iov_base = (void*)&chars[3 + !fmt]; iov[n++].iov_len = 2 - !fmt; + /* file */ iov[n].iov_base = (void*)file; iov[n++].iov_len = strlen(file); + /* ":" */ iov[n].iov_base = (void*)&chars[2]; iov[n++].iov_len = 1; if (line) { + /* line number */ iov[n].iov_base = lino; iov[n++].iov_len = snprintf(lino, sizeof lino, "%d", line); } else { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } + /* "," */ iov[n].iov_base = (void*)&chars[5]; iov[n++].iov_len = 1; if (function) { + /* function name */ iov[n].iov_base = (void*)function; iov[n++].iov_len = strlen(function); } else { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } @@ -166,16 +209,20 @@ static void _vverbose_(int loglevel, const char *file, int line, const char *fun iov[n++].iov_len = 1; } if (n == 2) { + /* "?" */ iov[n].iov_base = (void*)&chars[1]; iov[n++].iov_len = 1; } + /* "\n" */ iov[n].iov_base = (void*)&chars[0]; iov[n++].iov_len = 1; + /* emit the message */ pthread_mutex_lock(&mutex); writev(STDERR_FILENO, iov, n); pthread_mutex_unlock(&mutex); + /* restore errno */ errno = saverr; } @@ -187,15 +234,6 @@ void verbose_set_name(const char *name, int authority) #endif -void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vverbose(loglevel, file, line, function, fmt, ap); - va_end(ap); -} - void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) { void (*observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args) = verbose_observer; @@ -211,3 +249,89 @@ void vverbose(int loglevel, const char *file, int line, const char *function, co } } +void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vverbose(loglevel, file, line, function, fmt, ap); + va_end(ap); +} + +void set_logmask(int lvl) +{ + logmask = lvl | MINIMAL_LOGMASK; +} + +void verbose_add(int level) +{ + set_logmask(logmask | MASKOF(level)); +} + +void verbose_sub(int level) +{ + set_logmask(logmask & ~MASKOF(level)); +} + +void verbose_clear() +{ + set_logmask(0); +} + +void verbose_dec() +{ + verbosity_set(verbosity_get() - 1); +} + +void verbose_inc() +{ + verbosity_set(verbosity_get() + 1); +} + +int verbosity_to_mask(int verbo) +{ + int x = verbo + Log_Level_Error; + int l = CROP_LOGLEVEL(x); + return (1 << (l + 1)) - 1; +} + +int verbosity_from_mask(int mask) +{ + int v = 0; + while (mask > verbosity_to_mask(v)) + v++; + return v; +} + +void verbosity_set(int verbo) +{ + set_logmask(verbosity_to_mask(verbo)); +} + +int verbosity_get() +{ + return verbosity_from_mask(logmask); +} + +int verbose_level_of_name(const char *name) +{ + int c, i, r, l = 0, u = sizeof names / sizeof * names; + while (l < u) { + i = (l + u) >> 1; + r = (int)asort[i]; + c = strcasecmp(names[r], name); + if (!c) + return r; + if (c < 0) + l = i + 1; + else + u = i; + } + return -1; +} + +const char *verbose_name_of_level(int level) +{ + return level == CROP_LOGLEVEL(level) ? names[level] : NULL; +} + diff --git a/src/verbose.h b/src/verbose.h index 5cbe2aa6..bd36f97e 100644 --- a/src/verbose.h +++ b/src/verbose.h @@ -32,7 +32,6 @@ 3 : ERROR, WARNING, NOTICE, INFO greater than 3 : ERROR, WARNING, NOTICE, INFO, DEBUG -*/ extern int verbosity; enum verbosity_levels @@ -43,6 +42,7 @@ enum verbosity_levels Verbosity_Level_Info = 3, Verbosity_Level_Debug = 4 }; +*/ extern void verbose_set_name(const char *name, int authority); @@ -58,7 +58,7 @@ extern void verbose_set_name(const char *name, int authority); KERN_DEBUG 7 Debug-level messages */ -enum log_levels +enum { Log_Level_Emergency = 0, Log_Level_Alert = 1, @@ -70,27 +70,53 @@ enum log_levels Log_Level_Debug = 7 }; +extern int logmask; + extern void verbose(int loglevel, const char *file, int line, const char *function, const char *fmt, ...) __attribute__((format(printf, 5, 6))); extern void vverbose(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); #if defined(VERBOSE_NO_DATA) -# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__)\ - else verbose(lvl, __FILE__, __LINE__, __func__, NULL);}while(0) +# define __VERBOSE__(lvl,...) do{if((lvl)<=Log_Level_Error) verbose(lvl, __FILE__, __LINE__, NULL, __VA_ARGS__)\ + else verbose(lvl, __FILE__, __LINE__, NULL, NULL);}while(0) #elif defined(VERBOSE_NO_DETAILS) # define __VERBOSE__(lvl,...) verbose(lvl, NULL, 0, NULL, __VA_ARGS__) #else # define __VERBOSE__(lvl,...) verbose(lvl, __FILE__, __LINE__, __func__, __VA_ARGS__) #endif -# define _VERBOSE_(vlvl,llvl,...) do{ if (verbosity >= vlvl) __VERBOSE__(llvl, __VA_ARGS__); } while(0) +#define _LOGMASK_(lvl) ((lvl) < 0 ? -1 : (1 << (lvl))) +#define _WANTLOG_(lvl) (logmask & _LOGMASK_(lvl)) +#define _VERBOSE_(lvl,...) do{ if (_WANTLOG_(lvl)) __VERBOSE__((lvl), __VA_ARGS__); } while(0) -# define ERROR(...) _VERBOSE_(Verbosity_Level_Error, Log_Level_Error, __VA_ARGS__) -# define WARNING(...) _VERBOSE_(Verbosity_Level_Warning, Log_Level_Warning, __VA_ARGS__) -# define NOTICE(...) _VERBOSE_(Verbosity_Level_Notice, Log_Level_Notice, __VA_ARGS__) -# define INFO(...) _VERBOSE_(Verbosity_Level_Info, Log_Level_Info, __VA_ARGS__) -# define DEBUG(...) _VERBOSE_(Verbosity_Level_Debug, Log_Level_Debug, __VA_ARGS__) +#define EMERGENCY(...) _VERBOSE_(Log_Level_Emergency, __VA_ARGS__) +#define ALERT(...) _VERBOSE_(Log_Level_Alert, __VA_ARGS__) +#define CRITICAL(...) _VERBOSE_(Log_Level_Critical, __VA_ARGS__) +#define ERROR(...) _VERBOSE_(Log_Level_Error, __VA_ARGS__) +#define WARNING(...) _VERBOSE_(Log_Level_Warning, __VA_ARGS__) +#define NOTICE(...) _VERBOSE_(Log_Level_Notice, __VA_ARGS__) +#define INFO(...) _VERBOSE_(Log_Level_Info, __VA_ARGS__) +#define DEBUG(...) _VERBOSE_(Log_Level_Debug, __VA_ARGS__) -# define LOGUSER(app) verbose_set_name(app,0) -# define LOGAUTH(app) verbose_set_name(app,1) +#define LOGUSER(app) verbose_set_name(app,0) +#define LOGAUTH(app) verbose_set_name(app,1) extern void (*verbose_observer)(int loglevel, const char *file, int line, const char *function, const char *fmt, va_list args); + +static inline int verbose_wants(int lvl) { return _WANTLOG_(lvl); } + +extern void verbose_dec(); +extern void verbose_inc(); +extern void verbose_clear(); +extern void verbose_add(int level); +extern void verbose_sub(int level); + +extern int verbose_level_of_name(const char *name); +extern const char *verbose_name_of_level(int level); + +#define _DEVERBOSITY_(vlvl) ((vlvl) + Log_Level_Error) +#define _VERBOSITY_(llvl) ((llvl) - Log_Level_Error) +extern int verbosity_get(); +extern void verbosity_set(int verbo); +extern int verbosity_from_mask(int mask); +extern int verbosity_to_mask(int verbo); + diff --git a/src/wrap-json.c b/src/wrap-json.c index b139e7ad..e757c369 100644 --- a/src/wrap-json.c +++ b/src/wrap-json.c @@ -17,6 +17,7 @@ */ #include <string.h> +#include <limits.h> #include "wrap-json.h" @@ -528,7 +529,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i int64_t *pI = NULL; size_t *pz = NULL; uint8_t **py = NULL; - struct { struct json_object *parent; const char *acc; size_t index; size_t count; char type; } stack[STACKCOUNT], *top; + struct { struct json_object *parent; const char *acc; int index; int count; char type; } stack[STACKCOUNT], *top; struct json_object *obj; struct json_object **po; @@ -702,7 +703,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i if (!ignore) { if (!json_object_is_type(obj, json_type_array)) goto missfit; - top->count = json_object_array_length(obj); + top->count = (int)json_object_array_length(obj); } xacc[0] = ']'; acc = unpack_accept_arr; @@ -752,7 +753,7 @@ static int vunpack(struct json_object *object, const char *desc, va_list args, i if (key && key >= unpack_accept_any) { if (top->index >= top->count) goto out_of_range; - obj = json_object_array_get_idx(top->parent, (int)top->index++); + obj = json_object_array_get_idx(top->parent, top->index++); } } break; @@ -863,10 +864,10 @@ static void object_for_all(struct json_object *object, void (*callback)(void*,st static void array_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure) { - size_t n = json_object_array_length(object); - size_t i = 0; + int n = (int)json_object_array_length(object); + int i = 0; while(i < n) - callback(closure, json_object_array_get_idx(object, (int)i++)); + callback(closure, json_object_array_get_idx(object, i++)); } void wrap_json_optarray_for_all(struct json_object *object, void (*callback)(void*,struct json_object*), void *closure) @@ -906,16 +907,362 @@ void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct else if (!json_object_is_type(object, json_type_array)) callback(closure, object, NULL); else { - size_t n = json_object_array_length(object); - size_t i = 0; + int n = (int)json_object_array_length(object); + int i = 0; while(i < n) - callback(closure, json_object_array_get_idx(object, (int)i++), NULL); + callback(closure, json_object_array_get_idx(object, i++), NULL); } } +/** + * Clones the 'object' for the depth 'subdepth'. The object 'object' is + * duplicated and all its fields are cloned with the depth 'subdepth'. + * + * @param object the object to clone. MUST be an **object**. + * @param subdepth the depth to use when cloning the fields of the object. + * + * @return the cloned object. + */ +static struct json_object *clone_object(struct json_object *object, int subdepth) +{ + struct json_object *r = json_object_new_object(); + struct json_object_iterator it = json_object_iter_begin(object); + struct json_object_iterator end = json_object_iter_end(object); + while (!json_object_iter_equal(&it, &end)) { + json_object_object_add(r, + json_object_iter_peek_name(&it), + wrap_json_clone_depth(json_object_iter_peek_value(&it), subdepth)); + json_object_iter_next(&it); + } + return r; +} + +/** + * Clones the 'array' for the depth 'subdepth'. The array 'array' is + * duplicated and all its fields are cloned with the depth 'subdepth'. + * + * @param array the array to clone. MUST be an **array**. + * @param subdepth the depth to use when cloning the items of the array. + * + * @return the cloned array. + */ +static struct json_object *clone_array(struct json_object *array, int subdepth) +{ + int n = json_object_array_length(array); + struct json_object *r = json_object_new_array(); + while (n) { + n--; + json_object_array_put_idx(r, n, + wrap_json_clone_depth(json_object_array_get_idx(array, n), subdepth)); + } + return r; +} + +/** + * Clones any json 'item' for the depth 'depth'. The item is duplicated + * and if 'depth' is not zero, its contents is recursively cloned with + * the depth 'depth' - 1. + * + * Be aware that this implementation doesn't copies the primitive json + * items (numbers, nulls, booleans, strings) but instead increments their + * use count. This can cause issues with newer versions of libjson-c that + * now unfortunately allows to change their values. + * + * @param item the item to clone. Can be of any kind. + * @param depth the depth to use when cloning composites: object or arrays. + * + * @return the cloned array. + * + * @see wrap_json_clone + * @see wrap_json_clone_deep + */ +struct json_object *wrap_json_clone_depth(struct json_object *item, int depth) +{ + if (depth) { + switch (json_object_get_type(item)) { + case json_type_object: + return clone_object(item, depth - 1); + case json_type_array: + return clone_array(item, depth - 1); + default: + break; + } + } + return json_object_get(item); +} + +/** + * Clones the 'object': returns a copy of it. But doen't clones + * the content. Synonym of wrap_json_clone_depth(object, 1). + * + * @param object the object to clone + * + * @return a copy of the object. + * + * @see wrap_json_clone_depth + * @see wrap_json_clone_deep + */ +struct json_object *wrap_json_clone(struct json_object *object) +{ + return wrap_json_clone_depth(object, 1); +} + +/** + * Clones the 'object': returns a copy of it. Also clones all + * the content recursively. Synonym of wrap_json_clone_depth(object, INT_MAX). + * + * @param object the object to clone + * + * @return a copy of the object. + * + * @see wrap_json_clone_depth + * @see wrap_json_clone + */ +struct json_object *wrap_json_clone_deep(struct json_object *object) +{ + return wrap_json_clone_depth(object, INT_MAX); +} + +/** + * Adds the items of the object 'added' to the object 'dest'. + * + * @param dest the object to complete this object is modified + * @added the object containing fields to add + * + * @return the destination object 'dest' + * + * @example wrap_json_object_add({"a":"a"},{"X":"X"}) -> {"a":"a","X":"X"} + */ +struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added) +{ + struct json_object_iterator it, end; + if (json_object_is_type(dest, json_type_object) && json_object_is_type(added, json_type_object)) { + it = json_object_iter_begin(added); + end = json_object_iter_end(added); + while (!json_object_iter_equal(&it, &end)) { + json_object_object_add(dest, + json_object_iter_peek_name(&it), + json_object_get(json_object_iter_peek_value(&it))); + json_object_iter_next(&it); + } + } + return dest; +} + +/** + * Sort the 'array' and returns it. Sorting is done accordingly to the + * order given by the function 'wrap_json_cmp'. If the paramater isn't + * an array, nothing is done and the parameter is returned unchanged. + * + * @param array the array to sort + * + * @returns the array sorted + */ +struct json_object *wrap_json_sort(struct json_object *array) +{ + if (json_object_is_type(array, json_type_array)) + json_object_array_sort(array, (int(*)(const void*, const void*))wrap_json_cmp); + + return array; +} + +/** + * Returns a json array of the sorted keys of 'object' or null if 'object' has no keys. + * + * @param object the object whose keys are to be returned + * + * @return either NULL is 'object' isn't an object or a sorted array of the key's strings. + */ +struct json_object *wrap_json_keys(struct json_object *object) +{ + struct json_object *r; + struct json_object_iterator it, end; + if (!json_object_is_type(object, json_type_object)) + r = NULL; + else { + r = json_object_new_array(); + it = json_object_iter_begin(object); + end = json_object_iter_end(object); + while (!json_object_iter_equal(&it, &end)) { + json_object_array_add(r, json_object_new_string(json_object_iter_peek_name(&it))); + json_object_iter_next(&it); + } + wrap_json_sort(r); + } + return r; +} + +/** + * Internal comparison of 'x' with 'y' + * + * @param x first object to compare + * @param y second object to compare + * @param inc boolean true if should test for inclusion of y in x + * @param sort boolean true if comparison used for sorting + * + * @return an integer indicating the computed result. Refer to + * the table below for meaning of the returned value. + * + * inc | sort | x < y | x == y | x > y | y in x + * ----+------+---------+----------+---------+--------- + * 0 | 0 | != 0 | 0 | != 0 | > 0 + * 0 | 1 | < 0 | 0 | > 0 | > 0 + * 1 | 0 | != 0 | 0 | != 0 | 0 + * 1 | 1 | < 0 | 0 | > 0 | 0 + * + * + * if 'x' is found, respectively, to be less than, to match, + * or be greater than 'y'. This is valid when 'sort' + */ +static int jcmp(struct json_object *x, struct json_object *y, int inc, int sort) +{ + double dx, dy; + int64_t ix, iy; + const char *sx, *sy; + enum json_type tx, ty; + int r, nx, ny, i; + struct json_object_iterator it, end; + struct json_object *jx, *jy; + + /* check equality of pointers */ + if (x == y) + return 0; + + /* get the types */ + tx = json_object_get_type(x); + ty = json_object_get_type(y); + r = (int)tx - (int)ty; + if (r) + return r; + + /* compare following the type */ + switch (tx) { + default: + case json_type_null: + break; + + case json_type_boolean: + r = (int)json_object_get_boolean(x) + - (int)json_object_get_boolean(y); + break; + + case json_type_double: + dx = json_object_get_double(x); + dy = json_object_get_double(y); + r = dx < dy ? -1 : dx > dy; + break; + + case json_type_int: + ix = json_object_get_int64(x); + iy = json_object_get_int64(y); + r = ix < iy ? -1 : ix > iy; + break; + + case json_type_object: + it = json_object_iter_begin(y); + end = json_object_iter_end(y); + nx = json_object_object_length(x); + ny = json_object_object_length(y); + r = nx - ny; + if (r > 0 && inc) + r = 0; + while (!r && !json_object_iter_equal(&it, &end)) { + if (json_object_object_get_ex(x, json_object_iter_peek_name(&it), &jx)) { + jy = json_object_iter_peek_value(&it); + json_object_iter_next(&it); + r = jcmp(jx, jy, inc, sort); + } else if (sort) { + jx = wrap_json_keys(x); + jy = wrap_json_keys(y); + r = wrap_json_cmp(jx, jy); + json_object_put(jx); + json_object_put(jy); + } else + r = 1; + } + break; + + case json_type_array: + nx = json_object_array_length(x); + ny = json_object_array_length(y); + r = nx - ny; + if (r > 0 && inc) + r = 0; + for (i = 0 ; !r && i < ny ; i++) { + jx = json_object_array_get_idx(x, i); + jy = json_object_array_get_idx(y, i); + r = jcmp(jx, jy, inc, sort); + } + break; + + case json_type_string: + sx = json_object_get_string(x); + sy = json_object_get_string(y); + r = strcmp(sx, sy); + break; + } + return r; +} + +/** + * Compares 'x' with 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer less than, equal to, or greater than zero + * if 'x' is found, respectively, to be less than, to match, + * or be greater than 'y'. + */ +int wrap_json_cmp(struct json_object *x, struct json_object *y) +{ + return jcmp(x, y, 0, 1); +} + +/** + * Searchs wether 'x' equals 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer equal to zero when 'x' != 'y' or 1 when 'x' == 'y'. + */ +int wrap_json_equal(struct json_object *x, struct json_object *y) +{ + return !jcmp(x, y, 0, 0); +} + +/** + * Searchs wether 'x' contains 'y' + * + * @param x first object to compare + * @param y second object to compare + * + * @return an integer equal to 1 when 'y' is a subset of 'x' or zero otherwise + */ +int wrap_json_contains(struct json_object *x, struct json_object *y) +{ + return !jcmp(x, y, 1, 0); +} + #if defined(WRAP_JSON_TEST) #include <stdio.h> +void tclone(struct json_object *object) +{ + struct json_object *o; + + o = wrap_json_clone(object); + if (!wrap_json_equal(object, o)) + printf("ERROR in clone or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o)); + json_object_put(o); + + o = wrap_json_clone_deep(object); + if (!wrap_json_equal(object, o)) + printf("ERROR in clone_deep or equal: %s VERSUS %s\n", json_object_to_json_string(object), json_object_to_json_string(o)); + json_object_put(o); +} + void p(const char *desc, ...) { int rc; @@ -929,6 +1276,7 @@ void p(const char *desc, ...) printf(" SUCCESS %s\n\n", json_object_to_json_string(result)); else printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc)); + tclone(result); json_object_put(result); } @@ -945,7 +1293,7 @@ void u(const char *value, const char *desc, ...) unsigned m, k; int rc; va_list args; - struct json_object *obj, *o; + struct json_object *object, *o; memset(xs, 0, sizeof xs); memset(xi, 0, sizeof xi); @@ -954,9 +1302,9 @@ void u(const char *value, const char *desc, ...) memset(xo, 0, sizeof xo); memset(xy, 0, sizeof xy); memset(xz, 0, sizeof xz); - obj = json_tokener_parse(value); + object = json_tokener_parse(value); va_start(args, desc); - rc = wrap_json_vunpack(obj, desc, args); + rc = wrap_json_vunpack(object, desc, args); va_end(args); if (rc) printf(" ERROR[char %d err %d] %s\n\n", wrap_json_get_error_position(rc), wrap_json_get_error_code(rc), wrap_json_get_error_string(rc)); @@ -996,7 +1344,30 @@ void u(const char *value, const char *desc, ...) va_end(args); printf("\n\n"); } - json_object_put(obj); + tclone(object); + json_object_put(object); +} + +void c(const char *sx, const char *sy, int e, int c) +{ + int re, rc; + struct json_object *jx, *jy; + + jx = json_tokener_parse(sx); + jy = json_tokener_parse(sy); + + re = wrap_json_cmp(jx, jy); + rc = wrap_json_contains(jx, jy); + + printf("compare(%s)(%s)\n", sx, sy); + printf(" -> %d / %d\n", re, rc); + + if (!re != !!e) + printf(" ERROR should be %s\n", e ? "equal" : "different"); + if (!rc != !c) + printf(" ERROR should %scontain\n", c ? "" : "not "); + + printf("\n"); } #define P(...) do{ printf("pack(%s)\n",#__VA_ARGS__); p(__VA_ARGS__); } while(0) @@ -1145,6 +1516,41 @@ int main() U("{\"foo\":\"Pz8_Pz8_P2hlbGxvPj4-Pj4-Pg\"}", "{s?y}", "foo", &xy[0], &xz[0]); U("{\"foo\":\"\"}", "{s?y}", "foo", &xy[0], &xz[0]); U("{}", "{s?y}", "foo", &xy[0], &xz[0]); + + c("null", "null", 1, 1); + c("true", "true", 1, 1); + c("false", "false", 1, 1); + c("1", "1", 1, 1); + c("1.0", "1.0", 1, 1); + c("\"\"", "\"\"", 1, 1); + c("\"hi\"", "\"hi\"", 1, 1); + c("{}", "{}", 1, 1); + c("{\"a\":true,\"b\":false}", "{\"b\":false,\"a\":true}", 1, 1); + c("[]", "[]", 1, 1); + c("[1,true,null]", "[1,true,null]", 1, 1); + + c("null", "true", 0, 0); + c("null", "false", 0, 0); + c("0", "1", 0, 0); + c("1", "0", 0, 0); + c("0", "true", 0, 0); + c("0", "false", 0, 0); + c("0", "null", 0, 0); + + c("\"hi\"", "\"hello\"", 0, 0); + c("\"hello\"", "\"hi\"", 0, 0); + + c("{}", "null", 0, 0); + c("{}", "true", 0, 0); + c("{}", "1", 0, 0); + c("{}", "1.0", 0, 0); + c("{}", "[]", 0, 0); + c("{}", "\"x\"", 0, 0); + + c("[1,true,null]", "[1,true]", 0, 1); + c("{\"a\":true,\"b\":false}", "{\"a\":true}", 0, 1); + c("{\"a\":true,\"b\":false}", "{\"a\":true,\"c\":false}", 0, 0); + c("{\"a\":true,\"c\":false}", "{\"a\":true,\"b\":false}", 0, 0); return 0; } diff --git a/src/wrap-json.h b/src/wrap-json.h index 56f99198..d75ebc43 100644 --- a/src/wrap-json.h +++ b/src/wrap-json.h @@ -18,6 +18,10 @@ #pragma once +#ifdef __cplusplus + extern "C" { +#endif + #include <stdarg.h> #include <json-c/json.h> @@ -44,3 +48,18 @@ extern void wrap_json_object_for_all(struct json_object *object, void (*callback extern void wrap_json_optobject_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure); extern void wrap_json_for_all(struct json_object *object, void (*callback)(void*,struct json_object*,const char*), void *closure); +extern struct json_object *wrap_json_clone(struct json_object *object); +extern struct json_object *wrap_json_clone_deep(struct json_object *object); +extern struct json_object *wrap_json_clone_depth(struct json_object *object, int depth); + +extern struct json_object *wrap_json_object_add(struct json_object *dest, struct json_object *added); + +extern struct json_object *wrap_json_sort(struct json_object *array); +extern struct json_object *wrap_json_keys(struct json_object *object); +extern int wrap_json_cmp(struct json_object *x, struct json_object *y); +extern int wrap_json_equal(struct json_object *x, struct json_object *y); +extern int wrap_json_contains(struct json_object *x, struct json_object *y); + +#ifdef __cplusplus + } +#endif |