api-v3: Add monitoring of faults in preinit functions
[src/app-framework-binder.git] / src / afb-api-v3.c
1 /*
2  * Copyright (C) 2016, 2017, 2018 "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         const struct afb_verb_v2 *verbsv2;
48         const struct afb_verb_v3 *verbsv3;
49         struct afb_export *export;
50         const char *info;
51 };
52
53 static const char nulchar = 0;
54
55 static int verb_name_compare(const struct afb_verb_v3 *verb, const char *name)
56 {
57         return verb->glob
58                 ? fnmatch(verb->verb, name, FNM_NOESCAPE|FNM_PATHNAME|FNM_CASEFOLD|FNM_PERIOD)
59                 : strcasecmp(verb->verb, name);
60 }
61
62 static struct afb_verb_v3 *search_dynamic_verb(struct afb_api_v3 *api, const char *name)
63 {
64         struct afb_verb_v3 **v, **e, *i;
65
66         v = api->verbs;
67         e = &v[api->count];
68         while (v != e) {
69                 i = *v;
70                 if (!verb_name_compare(i, name))
71                         return i;
72                 v++;
73         }
74         return 0;
75 }
76
77 void afb_api_v3_process_call(struct afb_api_v3 *api, struct afb_xreq *xreq)
78 {
79         const struct afb_verb_v3 *verbsv3;
80         const struct afb_verb_v2 *verbsv2;
81         const char *name;
82
83         name = xreq->request.called_verb;
84
85         /* look first in dynamic set */
86         verbsv3 = search_dynamic_verb(api, name);
87         if (!verbsv3) {
88                 /* look then in static set */
89                 verbsv3 = api->verbsv3;
90                 while (verbsv3) {
91                         if (!verbsv3->verb)
92                                 verbsv3 = 0;
93                         else if (!verb_name_compare(verbsv3, name))
94                                 break;
95                         else
96                                 verbsv3++;
97                 }
98         }
99         /* is it a v3 verb ? */
100         if (verbsv3) {
101                 /* yes */
102                 xreq->request.vcbdata = verbsv3->vcbdata;
103                 afb_xreq_call_verb_v3(xreq, verbsv3);
104                 return;
105         }
106
107         /* look in legacy set */
108         verbsv2 = api->verbsv2;
109         if (verbsv2) {
110                 while (verbsv2->verb) {
111                         if (strcasecmp(verbsv2->verb, name))
112                                 verbsv2++;
113                         else {
114                                 afb_xreq_call_verb_v2(xreq, verbsv2);
115                                 return;
116                         }
117                 }
118         }
119
120         afb_xreq_reply_unknown_verb(xreq);
121 }
122
123 struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
124 {
125         char buffer[256];
126         struct afb_verb_v3 **iter, **end, *verb;
127         struct json_object *r, *f, *a, *i, *p, *g;
128
129         r = json_object_new_object();
130         json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
131
132         i = json_object_new_object();
133         json_object_object_add(r, "info", i);
134         json_object_object_add(i, "title", json_object_new_string(apiname));
135         json_object_object_add(i, "version", json_object_new_string("0.0.0"));
136         json_object_object_add(i, "description", json_object_new_string(api->info));
137
138         p = json_object_new_object();
139         json_object_object_add(r, "paths", p);
140         iter = api->verbs;
141         end = iter + api->count;
142         while (iter != end) {
143                 verb = *iter++;
144                 buffer[0] = '/';
145                 strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
146                 buffer[sizeof buffer - 1] = 0;
147                 f = json_object_new_object();
148                 json_object_object_add(p, buffer, f);
149                 g = json_object_new_object();
150                 json_object_object_add(f, "get", g);
151
152                 a = afb_auth_json_v2(verb->auth, verb->session);
153                 if (a)
154                         json_object_object_add(g, "x-permissions", a);
155
156                 a = json_object_new_object();
157                 json_object_object_add(g, "responses", a);
158                 f = json_object_new_object();
159                 json_object_object_add(a, "200", f);
160                 json_object_object_add(f, "description", json_object_new_string(verb->info?:verb->verb));
161         }
162         return r;
163 }
164
165 struct afb_api_v3 *afb_api_v3_create(
166                 struct afb_apiset *declare_set,
167                 struct afb_apiset *call_set,
168                 const char *apiname,
169                 const char *info,
170                 int noconcurrency,
171                 int (*preinit)(void*, struct afb_api_x3 *),
172                 void *closure,
173                 int copy_info
174 )
175 {
176         struct afb_api_v3 *api;
177
178         /* allocates the description */
179         api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
180         if (!api)
181                 goto oom;
182         api->refcount = 1;
183         if (!info)
184                 api->info = &nulchar;
185         else if (copy_info)
186                 api->info = strcpy((char*)(api + 1), info);
187         else
188                 api->info = info;
189
190         api->export = afb_export_create_v3(declare_set, call_set, apiname, api);
191         if (!api->export)
192                 goto oom2;
193
194         if (afb_export_declare(api->export, noconcurrency) < 0)
195                 goto oom3;
196
197         if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
198                 goto oom4;
199
200         return api;
201
202 oom4:
203         afb_export_undeclare(api->export);
204 oom3:
205         afb_export_unref(api->export);
206 oom2:
207         free(api);
208 oom:
209         ERROR("out of memory");
210         return NULL;
211 }
212
213 struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
214 {
215         if (api)
216                 __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
217         return api;
218 }
219
220 void afb_api_v3_unref(struct afb_api_v3 *api)
221 {
222         if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
223                 afb_export_destroy(api->export);
224                 free(api);
225         }
226 }
227
228 struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
229 {
230         return api->export;
231 }
232
233 void afb_api_v3_set_verbs_v2(
234                 struct afb_api_v3 *api,
235                 const struct afb_verb_v2 *verbs)
236 {
237         api->verbsv2 = verbs;
238 }
239
240 void afb_api_v3_set_verbs_v3(
241                 struct afb_api_v3 *api,
242                 const struct afb_verb_v3 *verbs)
243 {
244         api->verbsv3 = verbs;
245 }
246
247 int afb_api_v3_add_verb(
248                 struct afb_api_v3 *api,
249                 const char *verb,
250                 const char *info,
251                 void (*callback)(struct afb_req_x2 *req),
252                 void *vcbdata,
253                 const struct afb_auth *auth,
254                 uint16_t session,
255                 int glob)
256 {
257         struct afb_verb_v3 *v, **vv;
258         char *txt;
259         int i;
260
261         for (i = 0 ; i < api->count ; i++) {
262                 v = api->verbs[i];
263                 if (glob == v->glob && !strcasecmp(verb, v->verb)) {
264                         /* refuse to redefine a dynamic verb */
265                         errno = EEXIST;
266                         return -1;
267                 }
268         }
269
270         vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
271         if (!vv)
272                 goto oom;
273         api->verbs = vv;
274
275         v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
276         if (!v)
277                 goto oom;
278
279         v->callback = callback;
280         v->vcbdata = vcbdata;
281         v->auth = auth;
282         v->session = session;
283         v->glob = !!glob;
284
285         txt = (char*)(v + 1);
286         v->verb = txt;
287         txt = stpcpy(txt, verb);
288         if (!info)
289                 v->info = NULL;
290         else {
291                 v->info = ++txt;
292                 strcpy(txt, info);
293         }
294
295         api->verbs[api->count++] = v;
296         return 0;
297 oom:
298         errno = ENOMEM;
299         return -1;
300 }
301
302 int afb_api_v3_del_verb(
303                 struct afb_api_v3 *api,
304                 const char *verb,
305                 void **vcbdata)
306 {
307         struct afb_verb_v3 **v, **e, *i;
308
309         v = api->verbs;
310         e = &v[api->count];
311         while (v != e) {
312                 i = *v++;
313                 if (!strcasecmp(i->verb, verb)) {
314                         api->count--;
315                         if (vcbdata)
316                                 *vcbdata = i->vcbdata;
317                         if (v != e)
318                                 *--v = *--e;
319                         free(i);
320                         return 0;
321                 }
322         }
323
324         errno = ENOENT;
325         return -1;
326 }
327
328 int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
329 {
330         int rc = 0;
331         if (desc->verbs)
332                 rc =  afb_api_x3_set_verbs_v3(api, desc->verbs);
333         if (!rc && desc->onevent)
334                 rc =  afb_api_x3_on_event(api, desc->onevent);
335         if (!rc && desc->init)
336                 rc =  afb_api_x3_on_init(api, desc->init);
337         if (!rc && desc->provide_class)
338                 rc =  afb_api_x3_provide_class(api, desc->provide_class);
339         if (!rc && desc->require_class)
340                 rc =  afb_api_x3_require_class(api, desc->require_class);
341         if (!rc && desc->require_api)
342                 rc =  afb_api_x3_require_api(api, desc->require_api, 1);
343         return rc;
344 }
345
346 struct safe_preinit_data
347 {
348         int (*preinit)(struct afb_api_x3 *);
349         struct afb_api_x3 *api;
350         int result;
351 };
352
353 static void safe_preinit(int sig, void *closure)
354 {
355         struct safe_preinit_data *spd = closure;
356         if (!sig)
357                 spd->result = spd->preinit(spd->api);
358         else {
359                 spd->result = -1;
360                 errno = EFAULT;
361         }
362 }
363
364 int afb_api_v3_safe_preinit(struct afb_api_x3 *api, int (*preinit)(struct afb_api_x3 *))
365 {
366         struct safe_preinit_data spd;
367
368         spd.preinit = preinit;
369         spd.api = api;
370         sig_monitor(60, safe_preinit, &spd);
371         return spd.result;
372 }
373
374 static int init_binding(void *closure, struct afb_api_x3 *api)
375 {
376         const struct afb_binding_v3 *desc = closure;
377         int rc = afb_api_v3_set_binding_fields(desc, api);
378         if (!rc && desc->preinit)
379                 rc = afb_api_v3_safe_preinit(api, desc->preinit);
380         return rc;
381 }
382
383 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)
384 {
385         return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0);
386 }
387