Fix some more memory leaks
[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 static struct json_object *describe_verb_v3(const struct afb_verb_v3 *verb)
124 {
125         struct json_object *f, *a, *g;
126
127         f = json_object_new_object();
128
129         g = json_object_new_object();
130         json_object_object_add(f, "get", g);
131
132         a = afb_auth_json_v2(verb->auth, verb->session);
133         if (a)
134                 json_object_object_add(g, "x-permissions", a);
135
136         a = json_object_new_object();
137         json_object_object_add(g, "responses", a);
138         g = json_object_new_object();
139         json_object_object_add(a, "200", g);
140         json_object_object_add(g, "description", json_object_new_string(verb->info?:verb->verb));
141
142         return f;
143 }
144
145 struct json_object *afb_api_v3_make_description_openAPIv3(struct afb_api_v3 *api, const char *apiname)
146 {
147         char buffer[256];
148         struct afb_verb_v3 **iter, **end;
149         const struct afb_verb_v3 *verb;
150         struct json_object *r, *i, *p;
151
152         r = json_object_new_object();
153         json_object_object_add(r, "openapi", json_object_new_string("3.0.0"));
154
155         i = json_object_new_object();
156         json_object_object_add(r, "info", i);
157         json_object_object_add(i, "title", json_object_new_string(apiname));
158         json_object_object_add(i, "version", json_object_new_string("0.0.0"));
159         json_object_object_add(i, "description", json_object_new_string(api->info));
160
161         p = json_object_new_object();
162         json_object_object_add(r, "paths", p);
163         iter = api->verbs;
164         end = iter + api->count;
165         while (iter != end) {
166                 verb = *iter++;
167                 buffer[0] = '/';
168                 strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
169                 json_object_object_add(p, buffer, describe_verb_v3(verb));
170         }
171         verb = api->verbsv3;
172         if (verb)
173                 while(verb->verb) {
174                         buffer[0] = '/';
175                         strncpy(buffer + 1, verb->verb, sizeof buffer - 1);
176                         json_object_object_add(p, buffer, describe_verb_v3(verb));
177                         verb++;
178                 }
179         return r;
180 }
181
182 struct afb_api_v3 *afb_api_v3_create(
183                 struct afb_apiset *declare_set,
184                 struct afb_apiset *call_set,
185                 const char *apiname,
186                 const char *info,
187                 int noconcurrency,
188                 int (*preinit)(void*, struct afb_api_x3 *),
189                 void *closure,
190                 int copy_info
191 )
192 {
193         struct afb_api_v3 *api;
194
195         /* allocates the description */
196         api = calloc(1, sizeof *api + (copy_info && info ? 1 + strlen(info) : 0));
197         if (!api) {
198                 ERROR("out of memory");
199                 goto oom;
200         }
201         api->refcount = 1;
202         if (!info)
203                 api->info = &nulchar;
204         else if (copy_info)
205                 api->info = strcpy((char*)(api + 1), info);
206         else
207                 api->info = info;
208
209         api->export = afb_export_create_v3(declare_set, call_set, apiname, api);
210         if (!api->export)
211                 goto oom2;
212
213         if (afb_export_declare(api->export, noconcurrency) < 0)
214                 goto oom3;
215
216         if (preinit && afb_export_preinit_x3(api->export, preinit, closure) < 0)
217                 goto oom4;
218
219         return api;
220
221 oom4:
222         afb_export_undeclare(api->export);
223 oom3:
224         afb_export_unref(api->export);
225 oom2:
226         free(api);
227 oom:
228         return NULL;
229 }
230
231 struct afb_api_v3 *afb_api_v3_addref(struct afb_api_v3 *api)
232 {
233         if (api)
234                 __atomic_add_fetch(&api->refcount, 1, __ATOMIC_RELAXED);
235         return api;
236 }
237
238 void afb_api_v3_unref(struct afb_api_v3 *api)
239 {
240         if (api && !__atomic_sub_fetch(&api->refcount, 1, __ATOMIC_RELAXED)) {
241                 afb_export_destroy(api->export);
242                 while (api->count)
243                         free(api->verbs[--api->count]);
244                 free(api->verbs);
245                 free(api);
246         }
247 }
248
249 struct afb_export *afb_api_v3_export(struct afb_api_v3 *api)
250 {
251         return api->export;
252 }
253
254 void afb_api_v3_set_verbs_v2(
255                 struct afb_api_v3 *api,
256                 const struct afb_verb_v2 *verbs)
257 {
258         api->verbsv2 = verbs;
259 }
260
261 void afb_api_v3_set_verbs_v3(
262                 struct afb_api_v3 *api,
263                 const struct afb_verb_v3 *verbs)
264 {
265         api->verbsv3 = verbs;
266 }
267
268 int afb_api_v3_add_verb(
269                 struct afb_api_v3 *api,
270                 const char *verb,
271                 const char *info,
272                 void (*callback)(struct afb_req_x2 *req),
273                 void *vcbdata,
274                 const struct afb_auth *auth,
275                 uint16_t session,
276                 int glob)
277 {
278         struct afb_verb_v3 *v, **vv;
279         char *txt;
280         int i;
281
282         for (i = 0 ; i < api->count ; i++) {
283                 v = api->verbs[i];
284                 if (glob == v->glob && !strcasecmp(verb, v->verb)) {
285                         /* refuse to redefine a dynamic verb */
286                         errno = EEXIST;
287                         return -1;
288                 }
289         }
290
291         vv = realloc(api->verbs, (1 + api->count) * sizeof *vv);
292         if (!vv)
293                 goto oom;
294         api->verbs = vv;
295
296         v = malloc(sizeof *v + (1 + strlen(verb)) + (info ? 1 + strlen(info) : 0));
297         if (!v)
298                 goto oom;
299
300         v->callback = callback;
301         v->vcbdata = vcbdata;
302         v->auth = auth;
303         v->session = session;
304         v->glob = !!glob;
305
306         txt = (char*)(v + 1);
307         v->verb = txt;
308         txt = stpcpy(txt, verb);
309         if (!info)
310                 v->info = NULL;
311         else {
312                 v->info = ++txt;
313                 strcpy(txt, info);
314         }
315
316         api->verbs[api->count++] = v;
317         return 0;
318 oom:
319         errno = ENOMEM;
320         return -1;
321 }
322
323 int afb_api_v3_del_verb(
324                 struct afb_api_v3 *api,
325                 const char *verb,
326                 void **vcbdata)
327 {
328         struct afb_verb_v3 **v, **e, *i;
329
330         v = api->verbs;
331         e = &v[api->count];
332         while (v != e) {
333                 i = *v++;
334                 if (!strcasecmp(i->verb, verb)) {
335                         api->count--;
336                         if (vcbdata)
337                                 *vcbdata = i->vcbdata;
338                         if (v != e)
339                                 *--v = *--e;
340                         free(i);
341                         return 0;
342                 }
343         }
344
345         errno = ENOENT;
346         return -1;
347 }
348
349 int afb_api_v3_set_binding_fields(const struct afb_binding_v3 *desc, struct afb_api_x3 *api)
350 {
351         int rc = 0;
352         if (desc->verbs)
353                 rc =  afb_api_x3_set_verbs_v3(api, desc->verbs);
354         if (!rc && desc->onevent)
355                 rc =  afb_api_x3_on_event(api, desc->onevent);
356         if (!rc && desc->init)
357                 rc =  afb_api_x3_on_init(api, desc->init);
358         if (!rc && desc->provide_class)
359                 rc =  afb_api_x3_provide_class(api, desc->provide_class);
360         if (!rc && desc->require_class)
361                 rc =  afb_api_x3_require_class(api, desc->require_class);
362         if (!rc && desc->require_api)
363                 rc =  afb_api_x3_require_api(api, desc->require_api, 1);
364         return rc;
365 }
366
367 struct safe_preinit_data
368 {
369         int (*preinit)(struct afb_api_x3 *);
370         struct afb_api_x3 *api;
371         int result;
372 };
373
374 static void safe_preinit(int sig, void *closure)
375 {
376         struct safe_preinit_data *spd = closure;
377         if (!sig)
378                 spd->result = spd->preinit(spd->api);
379         else {
380                 spd->result = -1;
381                 errno = EFAULT;
382         }
383 }
384
385 int afb_api_v3_safe_preinit(struct afb_api_x3 *api, int (*preinit)(struct afb_api_x3 *))
386 {
387         struct safe_preinit_data spd;
388
389         spd.preinit = preinit;
390         spd.api = api;
391         sig_monitor(60, safe_preinit, &spd);
392         return spd.result;
393 }
394
395 static int init_binding(void *closure, struct afb_api_x3 *api)
396 {
397         const struct afb_binding_v3 *desc = closure;
398         int rc = afb_api_v3_set_binding_fields(desc, api);
399         if (!rc && desc->preinit)
400                 rc = afb_api_v3_safe_preinit(api, desc->preinit);
401         return rc;
402 }
403
404 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)
405 {
406         return afb_api_v3_create(declare_set, call_set, desc->api, desc->info, desc->noconcurrency, init_binding, (void*)desc, 0);
407 }
408