X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;ds=sidebyside;f=src%2Fafb-api-v3.c;fp=src%2Fafb-api-v3.c;h=8c755f9430050c19d8e67918bae8d63cf0c7321d;hb=4521c1e7ae5371ab9d639adc617d17fb4e8ded0c;hp=0000000000000000000000000000000000000000;hpb=63682b4da9d3e892d1d0a671de860adc43068142;p=src%2Fapp-framework-binder.git 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 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define _GNU_SOURCE + +#include +#include +#include +#include +#include + +#include + +#define AFB_BINDING_VERSION 0 +#include + +#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); +} +