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