2 * Copyright (C) 2015-2020 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
26 #include <json-c/json.h>
28 #define AFB_BINDING_VERSION 0
29 #include <afb/afb-binding.h>
32 #include "afb-api-v3.h"
33 #include "afb-apiset.h"
35 #include "afb-export.h"
38 #include "sig-monitor.h"
41 * Description of a binding
46 struct afb_verb_v3 **verbs;
47 #if WITH_LEGACY_BINDING_V2
48 const struct afb_verb_v2 *verbsv2;
50 const struct afb_verb_v3 *verbsv3;
51 struct afb_export *export;
55 static const char nulchar = 0;
57 static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name)
60 ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD)
61 : strcasecmp(verb->verb, name);
64 static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name)
66 struct afb_verb_v3 **v, **e, *i;
72 if (!verb_name_compare(i, name))
79 void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq)
81 const struct afb_verb_v3 *verbsv3;
82 #if WITH_LEGACY_BINDING_V2
83 const struct afb_verb_v2 *verbsv2;
87 name = xreq->request.called_verb;
89 /* look first in dynamic set */
90 verbsv3 = search_dynamic_verb(api, name);
92 /* look then in static set */
93 verbsv3 = api->verbsv3;
97 else if (!verb_name_compare(verbsv3, name))
103 /* is it a v3 verb ? */
106 xreq->request.vcbdata = verbsv3->vcbdata;
107 afb_xreq_call_verb_v3(xreq, verbsv3);
111 #if WITH_LEGACY_BINDING_V2
112 /* look in legacy set */
113 verbsv2 = api->verbsv2;
115 while (verbsv2->verb) {
116 if (strcasecmp(verbsv2->verb, name))
119 afb_xreq_call_verb_v2(xreq, verbsv2);
125 afb_xreq_reply_unknown_verb(xreq);
128 static struct json_object *describe_verb_v3(const struct afb_verb_v3 *verb)
130 struct json_object *f, *a, *g;
132 f = json_object_new_object();
134 g = json_object_new_object();
135 json_object_object_add(f, "get", g);
137 a = afb_auth_json_x2(verb->auth, verb->session);
139 json_object_object_add(g, "x-permissions", a);
141 a = json_object_new_object();
142 json_object_object_add(g, "responses", a);
143 g = json_object_new_object();
144 json_object_object_add(a, "200", g);
145 json_object_object_add(g, "description", json_object_new_string(verb->info?:verb->verb));
150 struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
153 struct afb_verb_v3 **iter, **end;
154 const struct afb_verb_v3 *verb;
155 struct json_object *r, *i, *p;
157 r = json_object_new_object();
158 json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
160 i = json_object_new_object();
161 json_object_object_add(r, "info", i);
162 json_object_object_add(i, "title", json_object_new_string(apiname));
163 json_object_object_add(i, "version", json_object_new_string("0.0.0"));
164 json_object_object_add(i, "description", json_object_new_string(api->info));
167 buffer[sizeof buffer - 1] = 0;
169 p = json_object_new_object();
170 json_object_object_add(r, "paths", p);
172 end = iter + api->count;
173 while (iter != end) {
175 strncpy(buffer + 1, verb->verb, sizeof buffer - 2);
176 json_object_object_add(p, buffer, describe_verb_v3(verb));
181 strncpy(buffer + 1, verb->verb, sizeof buffer - 2);
182 json_object_object_add(p, buffer, describe_verb_v3(verb));
188 struct afb_api_v3 *afb_api_v3_create(struct afb_apiset *declare_set,
189 struct afb_apiset *call_set,
193 int (*preinit)(void*, struct afb_api_x3 *),
196 struct afb_export* creator,
199 struct afb_api_v3 *api;
201 /* allocates the description */
202 api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
204 ERROR("out of memory");
209 api->info = &nulchar;
211 api->info = strcpy((char*)(api + 1), info);
215 api->export = afb_export_create_v3(declare_set, call_set, apiname, api, creator, path);
219 if (afb_export_declare(api->export, noconcurrency) < 0)
222 if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
228 afb_export_undeclare(api->export);
230 afb_export_unref(api->export);
237 struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
240 __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
244 void afb_api_v3_unref(struct afb_api_v3 *api)
246 if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
247 afb_export_destroy(api->export);
249 free(api->verbs[--api->count]);
255 struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
260 #if WITH_LEGACY_BINDING_V2
261 void afb_api_v3_set_verbs_v2(
262 struct afb_api_v3 *api,
263 const struct afb_verb_v2 *verbs)
265 api->verbsv2 = verbs;
269 void afb_api_v3_set_verbs_v3(
270 struct afb_api_v3 *api,
271 const struct afb_verb_v3 *verbs)
273 api->verbsv3 = verbs;
276 int afb_api_v3_add_verb(
277 struct afb_api_v3 *api,
280 void (*callback)(struct afb_req_x2 *req),
282 const struct afb_auth *auth,
286 struct afb_verb_v3 *v, **vv;
290 for (i = 0 ; i < api->count ; i++) {
292 if (glob == v->glob && !strcasecmp(verb, v->verb)) {
293 /* refuse to redefine a dynamic verb */
299 vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
304 v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
308 v->callback = callback;
309 v->vcbdata = vcbdata;
311 v->session = session;
314 txt = (char*)(v + 1);
316 txt = stpcpy(txt, verb);
324 api->verbs[api->count++] = v;
331 int afb_api_v3_del_verb(
332 struct afb_api_v3 *api,
336 struct afb_verb_v3 *v;
339 for (i = 0 ; i < api->count ; i++) {
341 if (!strcasecmp(verb, v->verb)) {
342 api->verbs[i] = api->verbs[--api->count];
344 *vcbdata = v->vcbdata;
354 int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
358 rc = afb_api_x3_set_verbs_v3(api, desc->verbs);
359 if (!rc && desc->onevent)
360 rc = afb_api_x3_on_event(api, desc->onevent);
361 if (!rc && desc->init)
362 rc = afb_api_x3_on_init(api, desc->init);
363 if (!rc && desc->provide_class)
364 rc = afb_api_x3_provide_class(api, desc->provide_class);
365 if (!rc && desc->require_class)
366 rc = afb_api_x3_require_class(api, desc->require_class);
367 if (!rc && desc->require_api)
368 rc = afb_api_x3_require_api(api, desc->require_api, 0);
372 struct safe_preinit_data
374 int (*preinit)(struct afb_api_x3 *);
375 struct afb_api_x3 *api;
379 static void safe_preinit(int sig, void *closure)
381 struct safe_preinit_data *spd = closure;
383 spd->result = spd->preinit(spd->api);
390 int afb_api_v3_safe_preinit(struct afb_api_x3 *api, int (*preinit)(struct afb_api_x3 *))
392 struct safe_preinit_data spd;
394 spd.preinit = preinit;
396 sig_monitor(60, safe_preinit, &spd);
400 static int init_binding(void *closure, struct afb_api_x3 *api)
402 const struct afb_binding_v3 *desc = closure;
403 int rc = afb_api_v3_set_binding_fields(desc, api);
404 if (!rc && desc->preinit)
405 rc = afb_api_v3_safe_preinit(api, desc->preinit);
409 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)
411 return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0, NULL, NULL);