ea691761d214930c99b9ac09bcea61f7bbe1e8a4
[src/app-framework-binder.git] / src / afb-api-v3.c
1 /*
2  * Copyright (C) 2016-2019 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdlib.h>
21 #include <string.h>
22 #include <assert.h>
23 #include <errno.h>
24 #include <fnmatch.h>
25
26 #include <json-c/json.h>
27
28 #define AFB_BINDING_VERSION 0
29 #include <afb/afb-binding.h>
30
31 #include "afb-api.h"
32 #include "afb-api-v3.h"
33 #include "afb-apiset.h"
34 #include "afb-auth.h"
35 #include "afb-export.h"
36 #include "afb-xreq.h"
37 #include "verbose.h"
38 #include "sig-monitor.h"
39
40 /*
41  * Description of a binding
42  */
43 struct afb_api_v3 {
44         int refcount;
45         int count;
46         struct afb_verb_v3 **verbs;
47 #if WITH_LEGACY_BINDING_V2
48         const struct afb_verb_v2 *verbsv2;
49 #endif
50         const struct afb_verb_v3 *verbsv3;
51         struct afb_export *export;
52         const char *info;
53 };
54
55 static const char nulchar = 0;
56
57 static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name)
58 {
59         return verb->glob
60                 ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD)
61                 : strcasecmp(verb->verb, name);
62 }
63
64 static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name)
65 {
66         struct afb_verb_v3 **v, **e, *i;
67
68         v = api->verbs;
69         e = &v[api->count];
70         while (v != e) {
71                 i = *v;
72                 if (!verb_name_compare(i, name))
73                         return i;
74                 v++;
75         }
76         return 0;
77 }
78
79 void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq)
80 {
81         const struct afb_verb_v3 *verbsv3;
82 #if WITH_LEGACY_BINDING_V2
83         const struct afb_verb_v2 *verbsv2;
84 #endif
85         const char *name;
86
87         name = xreq->request.called_verb;
88
89         /* look first in dynamic set */
90         verbsv3 = search_dynamic_verb(api, name);
91         if (!verbsv3) {
92                 /* look then in static set */
93                 verbsv3 = api->verbsv3;
94                 while (verbsv3) {
95                         if (!verbsv3->verb)
96                                 verbsv3 = 0;
97                         else if (!verb_name_compare(verbsv3, name))
98                                 break;
99                         else
100                                 verbsv3++;
101                 }
102         }
103         /* is it a v3 verb ? */
104         if (verbsv3) {
105                 /* yes */
106                 xreq->request.vcbdata = verbsv3->vcbdata;
107                 afb_xreq_call_verb_v3(xreq, verbsv3);
108                 return;
109         }
110
111 #if WITH_LEGACY_BINDING_V2
112         /* look in legacy set */
113         verbsv2 = api->verbsv2;
114         if (verbsv2) {
115                 while (verbsv2->verb) {
116                         if (strcasecmp(verbsv2->verb, name))
117                                 verbsv2++;
118                         else {
119                                 afb_xreq_call_verb_v2(xreq, verbsv2);
120                                 return;
121                         }
122                 }
123         }
124 #endif
125         afb_xreq_reply_unknown_verb(xreq);
126 }
127
128 static struct json_object *describe_verb_v3(const struct afb_verb_v3 *verb)
129 {
130         struct json_object *f, *a, *g;
131
132         f = json_object_new_object();
133
134         g = json_object_new_object();
135         json_object_object_add(f, "get", g);
136
137         a = afb_auth_json_x2(verb->auth, verb->session);
138         if (a)
139                 json_object_object_add(g, "x-permissions", a);
140
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));
146
147         return f;
148 }
149
150 struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
151 {
152         char buffer[256];
153         struct afb_verb_v3 **iter, **end;
154         const struct afb_verb_v3 *verb;
155         struct json_object *r, *i, *p;
156
157         r = json_object_new_object();
158         json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
159
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));
165
166         buffer[0] = '/';
167         buffer[sizeof buffer - 1] = 0;
168
169         p = json_object_new_object();
170         json_object_object_add(r, "paths", p);
171         iter = api->verbs;
172         end = iter + api->count;
173         while (iter != end) {
174                 verb = *iter++;
175                 strncpy(buffer + 1, verb->verb, sizeof buffer - 2);
176                 json_object_object_add(p, buffer, describe_verb_v3(verb));
177         }
178         verb = api->verbsv3;
179         if (verb)
180                 while(verb->verb) {
181                         strncpy(buffer + 1, verb->verb, sizeof buffer - 2);
182                         json_object_object_add(p, buffer, describe_verb_v3(verb));
183                         verb++;
184                 }
185         return r;
186 }
187
188 struct afb_api_v3 *afb_api_v3_create(struct afb_apiset *declare_set,
189                 struct afb_apiset *call_set,
190                 const char *apiname,
191                 const char *info,
192                 int noconcurrency,
193                 int (*preinit)(void*, struct afb_api_x3 *),
194                 void *closure,
195                 int copy_info,
196                 struct afb_export* creator,
197                 const char* path)
198 {
199         struct afb_api_v3 *api;
200
201         /* allocates the description */
202         api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
203         if (!api) {
204                 ERROR("out of memory");
205                 goto oom;
206         }
207         api->refcount = 1;
208         if (!info)
209                 api->info = &nulchar;
210         else if (copy_info)
211                 api->info = strcpy((char*)(api + 1), info);
212         else
213                 api->info = info;
214
215         api->export = afb_export_create_v3(declare_set, call_set, apiname, api, creator, path);
216         if (!api->export)
217                 goto oom2;
218
219         if (afb_export_declare(api->export, noconcurrency) < 0)
220                 goto oom3;
221
222         if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
223                 goto oom4;
224
225         return api;
226
227 oom4:
228         afb_export_undeclare(api->export);
229 oom3:
230         afb_export_unref(api->export);
231 oom2:
232         free(api);
233 oom:
234         return NULL;
235 }
236
237 struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
238 {
239         if (api)
240                 __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
241         return api;
242 }
243
244 void afb_api_v3_unref(struct afb_api_v3 *api)
245 {
246         if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
247                 afb_export_destroy(api->export);
248                 while (api->count)
249                         free(api->verbs[--api->count]);
250                 free(api->verbs);
251                 free(api);
252         }
253 }
254
255 struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
256 {
257         return api->export;
258 }
259
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)
264 {
265         api->verbsv2 = verbs;
266 }
267 #endif
268
269 void afb_api_v3_set_verbs_v3(
270                 struct afb_api_v3 *api,
271                 const struct afb_verb_v3 *verbs)
272 {
273         api->verbsv3 = verbs;
274 }
275
276 int afb_api_v3_add_verb(
277                 struct afb_api_v3 *api,
278                 const char *verb,
279                 const char *info,
280                 void (*callback)(struct afb_req_x2 *req),
281                 void *vcbdata,
282                 const struct afb_auth *auth,
283                 uint16_t session,
284                 int glob)
285 {
286         struct afb_verb_v3 *v, **vv;
287         char *txt;
288         int i;
289
290         for (i = 0 ; i < api->count ; i++) {
291                 v = api->verbs[i];
292                 if (glob == v->glob && !strcasecmp(verb, v->verb)) {
293                         /* refuse to redefine a dynamic verb */
294                         errno = EEXIST;
295                         return -1;
296                 }
297         }
298
299         vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
300         if (!vv)
301                 goto oom;
302         api->verbs = vv;
303
304         v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
305         if (!v)
306                 goto oom;
307
308         v->callback = callback;
309         v->vcbdata = vcbdata;
310         v->auth = auth;
311         v->session = session;
312         v->glob = !!glob;
313
314         txt = (char*)(v + 1);
315         v->verb = txt;
316         txt = stpcpy(txt, verb);
317         if (!info)
318                 v->info = NULL;
319         else {
320                 v->info = ++txt;
321                 strcpy(txt, info);
322         }
323
324         api->verbs[api->count++] = v;
325         return 0;
326 oom:
327         errno = ENOMEM;
328         return -1;
329 }
330
331 int afb_api_v3_del_verb(
332                 struct afb_api_v3 *api,
333                 const char *verb,
334                 void **vcbdata)
335 {
336         struct afb_verb_v3 *v;
337         int i;
338
339         for (i = 0 ; i < api->count ; i++) {
340                 v = api->verbs[i];
341                 if (!strcasecmp(verb, v->verb)) {
342                         api->verbs[i] = api->verbs[--api->count];
343                         if (vcbdata)
344                                 *vcbdata = v->vcbdata;
345                         free(v);
346                         return 0;
347                 }
348         }
349
350         errno = ENOENT;
351         return -1;
352 }
353
354 int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
355 {
356         int rc = 0;
357         if (desc->verbs)
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);
369         return rc;
370 }
371
372 struct safe_preinit_data
373 {
374         int (*preinit)(struct afb_api_x3 *);
375         struct afb_api_x3 *api;
376         int result;
377 };
378
379 static void safe_preinit(int sig, void *closure)
380 {
381         struct safe_preinit_data *spd = closure;
382         if (!sig)
383                 spd->result = spd->preinit(spd->api);
384         else {
385                 spd->result = -1;
386                 errno = EFAULT;
387         }
388 }
389
390 int afb_api_v3_safe_preinit(struct afb_api_x3 *api, int (*preinit)(struct afb_api_x3 *))
391 {
392         struct safe_preinit_data spd;
393
394         spd.preinit = preinit;
395         spd.api = api;
396         sig_monitor(60, safe_preinit, &spd);
397         return spd.result;
398 }
399
400 static int init_binding(void *closure, struct afb_api_x3 *api)
401 {
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);
406         return rc;
407 }
408
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)
410 {
411         return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0, NULL, NULL);
412 }
413