afb-api: Define the function afb_api_is_public
[src/app-framework-binder.git] / src / afb-apiset.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 <stdio.h>
22 #include <string.h>
23 #include <errno.h>
24
25 #include "afb-session.h"
26 #include "verbose.h"
27 #include "afb-api.h"
28 #include "afb-apiset.h"
29 #include "afb-context.h"
30 #include "afb-xreq.h"
31
32 #define INCR 8          /* CAUTION: must be a power of 2 */
33
34 struct afb_apiset;
35 struct api_desc;
36 struct api_class;
37 struct api_alias;
38 struct api_depend;
39
40 /**
41  * array of items
42  */
43 struct api_array {
44         int count;                      /* count of items */
45         union {
46                 void **anys;
47                 struct api_desc **apis;
48                 struct api_class **classes;
49                 struct api_alias **aliases;
50                 struct api_depend **depends;
51         };
52 };
53
54 /**
55  * Internal description of an api
56  */
57 struct api_desc
58 {
59         struct api_desc *next;
60         const char *name;               /**< name of the api */
61         int status;                     /**< initialisation status */
62         struct afb_api_item api;        /**< handler of the api */
63         struct {
64                 struct api_array classes;
65                 struct api_array apis;
66         } require;
67 };
68
69 /**
70  * internal description of aliases
71  */
72 struct api_alias
73 {
74         struct api_alias *next;
75         struct api_desc *api;
76         char name[1];
77 };
78
79 /**
80  *
81  */
82 struct api_class
83 {
84         struct api_class *next;
85         struct api_array providers;
86         char name[1];
87 };
88
89 /**
90  *
91  */
92 struct api_depend
93 {
94         struct afb_apiset *set;
95         char name[1];
96 };
97
98 /**
99  * Data structure for apiset
100  */
101 struct afb_apiset
102 {
103         struct api_array apis;          /**< the apis */
104         struct api_alias *aliases;      /**< the aliases */
105         struct afb_apiset *subset;      /**< subset if any */
106         struct {
107                 int (*callback)(void*, struct afb_apiset*, const char*); /* not found handler */
108                 void *closure;
109                 void (*cleanup)(void*);
110         } onlack;                       /** not found handler */
111         int timeout;                    /**< the timeout in second for the apiset */
112         int refcount;                   /**< reference count for freeing resources */
113         char name[1];                   /**< name of the apiset */
114 };
115
116 /**
117  * global apis
118  */
119 static struct api_desc *all_apis;
120
121 /**
122  * global classes
123  */
124 static struct api_class *all_classes;
125
126 /**
127  * Ensure enough room in 'array' for 'count' items
128  */
129 static int api_array_ensure_count(struct api_array *array, int count)
130 {
131         int c;
132         void **anys;
133
134         c = (count + INCR - 1) & ~(INCR - 1);
135         anys = realloc(array->anys, c * sizeof *anys);
136         if (!anys) {
137                 errno = ENOMEM;
138                 return -1;
139         }
140
141         array->count = count;
142         array->anys = anys;
143         return 0;
144 }
145
146 /**
147  * Insert in 'array' the item 'any' at the 'index'
148  */
149 static int api_array_insert(struct api_array *array, void *any, int index)
150 {
151         int n = array->count;
152
153         if (api_array_ensure_count(array, n + 1) < 0)
154                 return -1;
155
156         while (index < n) {
157                 array->anys[n] = array->anys[n - 1];
158                 n--;
159         }
160
161         array->anys[index] = any;
162         return 0;
163 }
164
165 /**
166  * Add the item 'any' to the 'array'
167  */
168 static int api_array_add(struct api_array *array, void *any)
169 {
170         int i, n = array->count;
171
172         for (i = 0 ; i < n ; i++) {
173                 if (array->anys[i] == any)
174                         return 0;
175         }
176
177         if (api_array_ensure_count(array, n + 1) < 0)
178                 return -1;
179
180         array->anys[n] = any;
181         return 0;
182 }
183
184 /**
185  * Delete the 'api' from the 'array'
186  * Returns 1 if delete or 0 if not found
187  */
188 static int api_array_del(struct api_array *array, void *any)
189 {
190         int i = array->count;
191         while (i) {
192                 if (array->anys[--i] == any) {
193                         array->anys[i] = array->anys[--array->count];
194                         return 1;
195                 }
196         }
197         return 0;
198 }
199
200 /**
201  * Search the class of 'name' and return it.
202  * In case where the class of 'namle' isn't found, it returns
203  * NULL when 'create' is null or a fresh created instance if 'create' isn't
204  * zero (but NULL on allocation failure).
205  */
206 static struct api_class *class_search(const char *name, int create)
207 {
208         struct api_class *c;
209
210         for (c= all_classes ; c ; c = c->next) {
211                 if (!strcasecmp(name, c->name))
212                         return c;
213         }
214
215         if (!create)
216                 return NULL;
217
218         c = calloc(1, strlen(name) + sizeof *c);
219         if (!c)
220                 errno = ENOMEM;
221         else {
222                 strcpy(c->name, name);
223                 c->next = all_classes;
224                 all_classes = c;
225         }
226         return c;
227 }
228
229 /**
230  * Search the api of 'name'.
231  * @param set the api set
232  * @param name the api name to search
233  * @return the descriptor if found or NULL otherwise
234  */
235 static struct api_desc *search(struct afb_apiset *set, const char *name)
236 {
237         int i, c, up, lo;
238         struct api_desc *a;
239         struct api_alias *aliases;
240
241         /* dichotomic search of the api */
242         /* initial slice */
243         lo = 0;
244         up = set->apis.count;
245         while (lo < up) {
246                 /* check the mid of the slice */
247                 i = (lo + up) >> 1;
248                 a = set->apis.apis[i];
249                 c = strcasecmp(a->name, name);
250                 if (c == 0) {
251                         /* found */
252                         return a;
253                 }
254                 /* update the slice */
255                 if (c < 0)
256                         lo = i + 1;
257                 else
258                         up = i;
259         }
260
261         /* linear search of aliases */
262         aliases = set->aliases;
263         for(;;) {
264                 if (!aliases)
265                         break;
266                 c = strcasecmp(aliases->name, name);
267                 if (!c)
268                         return aliases->api;
269                 if (c > 0)
270                         break;
271                 aliases = aliases->next;
272         }
273         return NULL;
274 }
275
276 /**
277  * Search the api of 'name' in the apiset and in its subsets.
278  * @param set the api set
279  * @param name the api name to search
280  * @return the descriptor if found or NULL otherwise
281  */
282 static struct api_desc *searchrec(struct afb_apiset *set, const char *name)
283 {
284         struct api_desc *result;
285
286         do {
287                 result = search(set, name);
288         } while (result == NULL && (set = set->subset) != NULL);
289
290         return result;
291 }
292
293 /**
294  * Increases the count of references to the apiset and return its address
295  * @param set the set whose reference count is to be increased
296  * @return the given apiset
297  */
298 struct afb_apiset *afb_apiset_addref(struct afb_apiset *set)
299 {
300         if (set)
301                 __atomic_add_fetch(&set->refcount, 1, __ATOMIC_RELAXED);
302         return set;
303 }
304
305 /**
306  * Decreases the count of references to the apiset and frees its
307  * resources when no more references exists.
308  * @param set the set to unrefrence
309  */
310 void afb_apiset_unref(struct afb_apiset *set)
311 {
312         struct api_alias *a;
313         struct api_desc *d;
314
315         if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) {
316                 afb_apiset_unref(set->subset);
317                 if (set->onlack.cleanup)
318                         set->onlack.cleanup(set->onlack.closure);
319                 while((a = set->aliases)) {
320                         set->aliases = a->next;
321                         free(a);
322                 }
323                 while (set->apis.count) {
324                         d = set->apis.apis[--set->apis.count];
325                         if (d->api.itf->unref)
326                                 d->api.itf->unref(d->api.closure);
327                         free(d);
328                 }
329                 free(set->apis.apis);
330                 free(set);
331         }
332 }
333
334 /**
335  * Create an apiset
336  * @param name the name of the apiset
337  * @param timeout the default timeout in seconds for the apiset
338  * @return the created apiset or NULL in case of error
339  */
340 struct afb_apiset *afb_apiset_create(const char *name, int timeout)
341 {
342         struct afb_apiset *set;
343
344         set = calloc(1, (name ? strlen(name) : 0) + sizeof *set);
345         if (set) {
346                 set->timeout = timeout;
347                 set->refcount = 1;
348                 if (name)
349                         strcpy(set->name, name);
350         }
351         return set;
352 }
353
354 /**
355  * Create an apiset being the last subset of 'set'
356  * @param set     the set to extend with the created subset (can be NULL)
357  * @param name    the name of the created apiset (can be NULL)
358  * @param timeout the default timeout in seconds for the created apiset
359  * @return the created apiset or NULL in case of error
360  */
361 struct afb_apiset *afb_apiset_create_subset_last(struct afb_apiset *set, const char *name, int timeout)
362 {
363         if (set)
364                 while (set->subset)
365                         set = set->subset;
366         return afb_apiset_create_subset_first(set, name, timeout);
367 }
368
369 /**
370  * Create an apiset being the first subset of 'set'
371  * @param set     the set to extend with the created subset (can be NULL)
372  * @param name    the name of the created apiset (can be NULL)
373  * @param timeout the default timeout in seconds for the created apiset
374  * @return the created apiset or NULL in case of error
375  */
376 struct afb_apiset *afb_apiset_create_subset_first(struct afb_apiset *set, const char *name, int timeout)
377 {
378         struct afb_apiset *result = afb_apiset_create(name, timeout);
379         if (result && set) {
380                 result->subset = set->subset;
381                 set->subset = result;
382         }
383         return result;
384 }
385
386 /**
387  * the name of the apiset
388  * @param set the api set
389  * @return the name of the set
390  */
391 const char *afb_apiset_name(struct afb_apiset *set)
392 {
393         return set->name;
394 }
395
396 /**
397  * Get the API timeout of the set
398  * @param set the api set
399  * @return the timeout in seconds
400  */
401 int afb_apiset_timeout_get(struct afb_apiset *set)
402 {
403         return set->timeout;
404 }
405
406 /**
407  * Set the API timeout of the set
408  * @param set the api set
409  * @param to the timeout in seconds
410  */
411 void afb_apiset_timeout_set(struct afb_apiset *set, int to)
412 {
413         set->timeout = to;
414 }
415
416 /**
417  * Get the subset of the set
418  * @param set the api set
419  * @return the subset of set
420  */
421 struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set)
422 {
423         return set->subset;
424 }
425
426 /**
427  * Set the subset of the set
428  * @param set the api set
429  * @param subset the subset to set
430  */
431 void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
432 {
433         struct afb_apiset *tmp;
434         if (subset == set) {
435                 /* avoid infinite loop */
436                 subset = NULL;
437         }
438         tmp = set->subset;
439         set->subset = afb_apiset_addref(subset);
440         afb_apiset_unref(tmp);
441 }
442
443 void afb_apiset_onlack_set(struct afb_apiset *set, int (*callback)(void*, struct afb_apiset*, const char*), void *closure, void (*cleanup)(void*))
444 {
445         if (set->onlack.cleanup)
446                 set->onlack.cleanup(set->onlack.closure);
447         set->onlack.callback = callback;
448         set->onlack.closure = closure;
449         set->onlack.cleanup = cleanup;
450 }
451
452 /**
453  * Adds the api of 'name' described by 'api'.
454  * @param set the api set
455  * @param name the name of the api to add (have to survive, not copied!)
456  * @param api the api
457  * @returns 0 in case of success or -1 in case
458  * of error with errno set:
459  *   - EEXIST if name already registered
460  *   - ENOMEM when out of memory
461  */
462 int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api_item api)
463 {
464         struct api_desc *desc;
465         int i, c;
466
467         /* check whether it exists already */
468         if (search(set, name)) {
469                 ERROR("api of name %s already exists", name);
470                 errno = EEXIST;
471                 goto error;
472         }
473
474         /* search insertion place */
475         for (i = 0 ; i < set->apis.count ; i++) {
476                 c = strcasecmp(set->apis.apis[i]->name, name);
477                 if (c > 0)
478                         break;
479         }
480
481         /* allocates memory */
482         desc = calloc(1, sizeof *desc);
483         if (!desc)
484                 goto oom;
485
486         desc->status = -1;
487         desc->api = api;
488         desc->name = name;
489
490         if (api_array_insert(&set->apis, desc, i) < 0) {
491                 free(desc);
492                 goto error;
493         }
494
495         desc->next = all_apis;
496         all_apis = desc;
497
498         if (afb_api_is_public(name))
499                 INFO("API %s added", name);
500
501         return 0;
502
503 oom:
504         ERROR("out of memory");
505         errno = ENOMEM;
506 error:
507         return -1;
508 }
509
510 /**
511  * Adds a the 'alias' name to the api of 'name'.
512  * @params set the api set
513  * @param name the name of the api to alias
514  * @param alias the aliased name to add to the api of name
515  * @returns 0 in case of success or -1 in case
516  * of error with errno set:
517  *   - ENOENT if the api doesn't exist
518  *   - EEXIST if name (of alias) already registered
519  *   - ENOMEM when out of memory
520  */
521 int afb_apiset_add_alias(struct afb_apiset *set, const char *name, const char *alias)
522 {
523         struct api_desc *api;
524         struct api_alias *ali, **pali;
525
526         /* check alias doesn't already exist */
527         if (search(set, alias)) {
528                 ERROR("api of name %s already exists", alias);
529                 errno = EEXIST;
530                 goto error;
531         }
532
533         /* check aliased api exists */
534         api = search(set, name);
535         if (api == NULL) {
536                 ERROR("api of name %s doesn't exists", name);
537                 errno = ENOENT;
538                 goto error;
539         }
540
541         /* allocates and init the struct */
542         ali = malloc(sizeof *ali + strlen(alias));
543         if (ali == NULL) {
544                 ERROR("out of memory");
545                 errno = ENOMEM;
546                 goto error;
547         }
548         ali->api = api;
549         strcpy(ali->name, alias);
550
551         /* insert the alias in the sorted order */
552         pali = &set->aliases;
553         while(*pali && strcmp((*pali)->name, alias) < 0)
554                 pali = &(*pali)->next;
555         ali->next = *pali;
556         *pali = ali;
557         return 0;
558 error:
559         return -1;
560 }
561
562 int afb_apiset_is_alias(struct afb_apiset *set, const char *name)
563 {
564         struct api_desc *api = searchrec(set, name);
565         return api && strcasecmp(api->name, name);
566 }
567
568 const char *afb_apiset_unalias(struct afb_apiset *set, const char *name)
569 {
570         struct api_desc *api = searchrec(set, name);
571         return api ? api->name : NULL;
572 }
573
574 /**
575  * Delete from the 'set' the api of 'name'.
576  * @param set the set to be changed
577  * @param name the name of the API to remove
578  * @return 0 in case of success or -1 in case where the API doesn't exist.
579  */
580 int afb_apiset_del(struct afb_apiset *set, const char *name)
581 {
582         struct api_class *cla;
583         struct api_alias *ali, **pali;
584         struct api_desc *desc, **pdesc, *odesc;
585         int i, c;
586
587         /* search the alias */
588         pali = &set->aliases;
589         while ((ali = *pali)) {
590                 c = strcasecmp(ali->name, name);
591                 if (!c) {
592                         *pali = ali->next;
593                         free(ali);
594                         return 0;
595                 }
596                 if (c > 0)
597                         break;
598                 pali = &ali->next;
599         }
600
601         /* search the api */
602         for (i = 0 ; i < set->apis.count ; i++) {
603                 desc = set->apis.apis[i];
604                 c = strcasecmp(desc->name, name);
605                 if (c == 0) {
606                         /* remove from classes */
607                         for (cla = all_classes ; cla ; cla = cla->next)
608                                 api_array_del(&cla->providers, desc);
609
610                         /* unlink from the whole set and their requires */
611                         pdesc = &all_apis;
612                         while ((odesc = *pdesc) != desc) {
613                                 pdesc = &odesc->next;
614                         }
615                         *pdesc = odesc = desc->next;
616                         while (odesc) {
617                                 odesc = odesc->next;
618                         }
619
620                         /* remove references from classes */
621                         free(desc->require.classes.classes);
622
623                         /* drop the aliases */
624                         pali = &set->aliases;
625                         while ((ali = *pali)) {
626                                 if (ali->api != desc)
627                                         pali = &ali->next;
628                                 else {
629                                         *pali = ali->next;
630                                         free(ali);
631                                 }
632                         }
633
634                         /* unref the api */
635                         if (desc->api.itf->unref)
636                                 desc->api.itf->unref(desc->api.closure);
637
638                         set->apis.count--;
639                         while(i < set->apis.count) {
640                                 set->apis.apis[i] = set->apis.apis[i + 1];
641                                 i++;
642                         }
643                         free(desc);
644                         return 0;
645                 }
646                 if (c > 0)
647                         break;
648         }
649         errno = ENOENT;
650         return -1;
651 }
652
653 /**
654  * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api
655  * @param set the set of API
656  * @param name the name of the API to get
657  * @param rec if not zero look also recursively in subsets
658  * @return the api pointer in case of success or NULL in case of error
659  */
660 static struct api_desc *lookup(struct afb_apiset *set, const char *name, int rec)
661 {
662         struct api_desc *result;
663
664         result = search(set, name);
665         while (!result) {
666                 /* lacking the api, try onlack behaviour */
667                 if (set->onlack.callback && set->onlack.callback(set->onlack.closure, set, name) > 0) {
668                         result = search(set, name);
669                         if (result)
670                                 break;
671                 }
672                 if (!rec || !(set = set->subset))
673                         break;
674                 result = search(set, name);
675         }
676         return result;
677 }
678
679 /**
680  * Get from the 'set' the API of 'name' in 'api'
681  * @param set the set of API
682  * @param name the name of the API to get
683  * @param rec if not zero look also recursively in subsets
684  * @return the api pointer in case of success or NULL in case of error
685  */
686 const struct afb_api_item *afb_apiset_lookup(struct afb_apiset *set, const char *name, int rec)
687 {
688         struct api_desc *i;
689
690         i = lookup(set, name, rec);
691         if (i)
692                 return &i->api;
693         errno = ENOENT;
694         return NULL;
695 }
696
697 static int start_api(struct api_desc *api);
698
699 /**
700  * Start the apis of the 'array'
701  */
702 static int start_array_apis(struct api_array *array)
703 {
704         int i, rc = 0, rc2;
705
706         i = array->count;
707         while (i) {
708                 rc2 = start_api(array->apis[--i]);
709                 if (rc2 < 0) {
710                         rc = rc2;
711                 }
712         }
713         return rc;
714 }
715
716 /**
717  * Start the class 'cla' (start the apis that provide it).
718  */
719 static int start_class(struct api_class *cla)
720 {
721         return start_array_apis(&cla->providers);
722 }
723
724 /**
725  * Start the classes of the 'array'
726  */
727 static int start_array_classes(struct api_array *array)
728 {
729         int i, rc = 0, rc2;
730
731         i = array->count;
732         while (i) {
733                 rc2 = start_class(array->classes[--i]);
734                 if (rc2 < 0) {
735                         rc = rc2;
736                 }
737         }
738         return rc;
739 }
740
741 /**
742  * Start the depends of the 'array'
743  */
744 static int start_array_depends(struct api_array *array)
745 {
746         struct api_desc *api;
747         int i, rc = 0, rc2;
748
749         i = array->count;
750         while (i) {
751                 i--;
752                 api = searchrec(array->depends[i]->set, array->depends[i]->name);
753                 if (!api)
754                         rc = -1;
755                 else {
756                         rc2 = start_api(api);
757                         if (rc2 < 0) {
758                                 rc = rc2;
759                         }
760                 }
761         }
762         return rc;
763 }
764
765 /**
766  * Starts the service 'api'.
767  * @param api the api
768  * @return a positive number on success
769  */
770 static int start_api(struct api_desc *api)
771 {
772         int rc;
773
774         if (api->status == 0)
775                 return 0;
776         else if (api->status > 0) {
777                 errno = api->status;
778                 return -1;
779         }
780
781         INFO("API %s starting...", api->name);
782         api->status = EBUSY;
783         rc = start_array_classes(&api->require.classes);
784         if (rc < 0)
785                 ERROR("Can start classes needed by api %s", api->name);
786         else {
787                 rc = start_array_depends(&api->require.apis);
788                 if (rc < 0)
789                         ERROR("Can start apis needed by api %s", api->name);
790                 else if (api->api.itf->service_start) {
791                         rc = api->api.itf->service_start(api->api.closure);
792                         if (rc < 0)
793                                 ERROR("The api %s failed to start", api->name);
794                 }
795         }
796         if (rc < 0) {
797                 api->status = errno ?: ECANCELED;
798                 return -1;
799         }
800         NOTICE("API %s started", api->name);
801         api->status = 0;
802         return 0;
803 }
804
805 /**
806  * Get from the 'set' the API of 'name' in 'api'
807  * @param set the set of API
808  * @param name the name of the API to get
809  * @param rec if not zero look also recursively in subsets
810  * @return 0 in case of success or -1 in case of error
811  */
812 const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
813 {
814         struct api_desc *i;
815
816         i = lookup(set, name, rec);
817         if (i)
818                 return i->status && start_api(i) ? NULL : &i->api;
819         errno = ENOENT;
820         return NULL;
821 }
822
823 /**
824  * Starts a service by its 'api' name.
825  * @param set the api set
826  * @param name name of the service to start
827  * @return a positive number on success
828  */
829 int afb_apiset_start_service(struct afb_apiset *set, const char *name)
830 {
831         struct api_desc *a;
832
833         a = searchrec(set, name);
834         if (!a) {
835                 ERROR("can't find service %s", name);
836                 errno = ENOENT;
837                 return -1;
838         }
839
840         return start_api(a);
841 }
842
843 /**
844  * Starts all possible services but stops at first error.
845  * @param set the api set
846  * @return 0 on success or a negative number when an error is found
847  */
848 int afb_apiset_start_all_services(struct afb_apiset *set)
849 {
850         int rc, ret;
851         int i;
852
853         ret = 0;
854         while (set) {
855                 i = 0;
856                 while (i < set->apis.count) {
857                         rc = start_api(set->apis.apis[i]);
858                         if (rc < 0)
859                                 ret = rc;
860                         i++;
861                 }
862                 set = set->subset;
863         }
864         return ret;
865 }
866
867 /**
868  * Ask to update the hook flags of the 'api'
869  * @param set the api set
870  * @param name the api to update (NULL updates all)
871  */
872 void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
873 {
874         struct api_desc **i, **e, *d;
875
876         if (!name) {
877                 i = set->apis.apis;
878                 e = &set->apis.apis[set->apis.count];
879                 while (i != e) {
880                         d = *i++;
881                         if (d->api.itf->update_hooks)
882                                 d->api.itf->update_hooks(d->api.closure);
883                 }
884         } else {
885                 d = searchrec(set, name);
886                 if (d && d->api.itf->update_hooks)
887                         d->api.itf->update_hooks(d->api.closure);
888         }
889 }
890
891 /**
892  * Set the logmask of the 'api' to 'mask'
893  * @param set the api set
894  * @param name the api to set (NULL set all)
895  */
896 void afb_apiset_set_logmask(struct afb_apiset *set, const char *name, int mask)
897 {
898         int i;
899         struct api_desc *d;
900
901         if (!name) {
902                 for (i = 0 ; i < set->apis.count ; i++) {
903                         d = set->apis.apis[i];;
904                         if (d->api.itf->set_logmask)
905                                 d->api.itf->set_logmask(d->api.closure, mask);
906                 }
907         } else {
908                 d = searchrec(set, name);
909                 if (d && d->api.itf->set_logmask)
910                         d->api.itf->set_logmask(d->api.closure, mask);
911         }
912 }
913
914 /**
915  * Get the logmask level of the 'api'
916  * @param set the api set
917  * @param name the api to get
918  * @return the logmask level or -1 in case of error
919  */
920 int afb_apiset_get_logmask(struct afb_apiset *set, const char *name)
921 {
922         const struct api_desc *i;
923
924         i = name ? searchrec(set, name) : NULL;
925         if (!i) {
926                 errno = ENOENT;
927                 return -1;
928         }
929
930         if (!i->api.itf->get_logmask)
931                 return logmask;
932
933         return i->api.itf->get_logmask(i->api.closure);
934 }
935
936 /**
937  * Get the description of the API of 'name'
938  * @param set the api set
939  * @param name the api whose description is required
940  * @return the description or NULL
941  */
942 struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name)
943 {
944         const struct api_desc *i;
945
946         i = name ? searchrec(set, name) : NULL;
947         return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL;
948 }
949
950 struct get_names {
951         union  {
952                 struct {
953                         size_t count;
954                         size_t size;
955                 };
956                 struct {
957                         const char **ptr;
958                         char *data;
959                 };
960         };
961         int type;
962 };
963
964 static void get_names_count(void *closure, struct afb_apiset *set, const char *name, int isalias)
965 {
966         struct get_names *gc = closure;
967         if ((1 + isalias) & gc->type) {
968                 gc->size += strlen(name);
969                 gc->count++;
970         }
971 }
972
973 static void get_names_value(void *closure, struct afb_apiset *set, const char *name, int isalias)
974 {
975         struct get_names *gc = closure;
976         if ((1 + isalias) & gc->type) {
977                 *gc->ptr++ = gc->data;
978                 gc->data = stpcpy(gc->data, name) + 1;
979         }
980 }
981
982 #if !defined(APISET_NO_SORT)
983 static int get_names_sortcb(const void *a, const void *b)
984 {
985         return strcasecmp(*(const char **)a, *(const char **)b);
986 }
987 #endif
988
989 /**
990  * Get the list of api names
991  * @param set the api set
992  * @param rec recursive
993  * @param type expected type: 1 names, 3 names+aliases, 2 aliases
994  * @return a NULL terminated array of api names. Must be freed.
995  */
996 const char **afb_apiset_get_names(struct afb_apiset *set, int rec, int type)
997 {
998         struct get_names gc;
999         size_t size;
1000         const char **names;
1001
1002         gc.count = gc.size = 0;
1003         gc.type = type >= 1 && type <= 3 ? type : 1;
1004         afb_apiset_enum(set, rec, get_names_count, &gc);
1005
1006         size = gc.size + gc.count * (1 + sizeof *names) + sizeof(*names);
1007         names = malloc(size);
1008
1009         if (!names)
1010                 errno = ENOMEM;
1011         else {
1012                 gc.data = (char*)&names[gc.count + 1];
1013                 gc.ptr = names;
1014                 afb_apiset_enum(set, rec, get_names_value, &gc);
1015 #if !defined(APISET_NO_SORT)
1016                 qsort(names, gc.ptr - names, sizeof *names, get_names_sortcb);
1017 #endif
1018                 *gc.ptr = NULL;
1019         }
1020         return names;
1021 }
1022
1023 /**
1024  * Enumerate the api names to a callback.
1025  * @param set the api set
1026  * @param rec should the enumeration be recursive
1027  * @param callback the function to call for each name
1028  * @param closure the closure for the callback
1029  */
1030 void afb_apiset_enum(
1031         struct afb_apiset *set,
1032         int rec,
1033         void (*callback)(void *closure, struct afb_apiset *set, const char *name, int isalias),
1034         void *closure)
1035 {
1036         int i;
1037         struct afb_apiset *iset;
1038         struct api_desc *d;
1039         struct api_alias *a;
1040
1041         iset = set;
1042         while (iset) {
1043                 for (i = 0 ; i < set->apis.count ; i++) {
1044                         d = set->apis.apis[i];;
1045                         if (searchrec(set, d->name) == d)
1046                                 callback(closure, iset, d->name, 0);
1047                 }
1048                 a = iset->aliases;
1049                 while (a) {
1050                         if (searchrec(set, a->name) == a->api)
1051                                 callback(closure, iset, a->name, 1);
1052                         a = a->next;
1053                 }
1054                 iset = rec ? iset->subset : NULL;
1055         }
1056 }
1057
1058 /**
1059  * Declare that the api of 'name' requires the api of name 'required'.
1060  * The api is searched in the apiset 'set' and if 'rec' isn't null also in its subset.
1061  * Returns 0 if the declaration successed or -1 in case of failure
1062  * (ENOMEM: allocation failure, ENOENT: api name not found)
1063  */
1064 int afb_apiset_require(struct afb_apiset *set, const char *name, const char *required)
1065 {
1066         struct api_desc *a;
1067         struct api_depend *d;
1068         int rc = -1;
1069
1070         a = searchrec(set, name);
1071         if (!a)
1072                 errno = ENOENT;
1073         else {
1074                 d = malloc(strlen(required) + sizeof *d);
1075                 if (!d)
1076                         errno = ENOMEM;
1077                 else {
1078                         d->set = set;
1079                         strcpy(d->name, required);
1080                         rc = api_array_add(&a->require.apis, d);
1081                 }
1082         }
1083         return rc;
1084 }
1085
1086 /**
1087  * Declare that the api of name 'apiname' requires the class of name 'classname'.
1088  * Returns 0 if the declaration successed or -1 in case of failure
1089  * (ENOMEM: allocation failure, ENOENT: api name not found)
1090  */
1091 int afb_apiset_require_class(struct afb_apiset *set, const char *apiname, const char *classname)
1092 {
1093         struct api_desc *a = searchrec(set, apiname);
1094         struct api_class *c = class_search(classname, 1);
1095         return a && c ? api_array_add(&a->require.classes, c) : (errno = ENOENT, -1);
1096 }
1097
1098 /**
1099  * Declare that the api of name 'apiname' provides the class of name 'classname'
1100  * Returns 0 if the declaration successed or -1 in case of failure
1101  * (ENOMEM: allocation failure, ENOENT: api name not found)
1102  */
1103 int afb_apiset_provide_class(struct afb_apiset *set, const char *apiname, const char *classname)
1104 {
1105         struct api_desc *a = searchrec(set, apiname);
1106         struct api_class *c = class_search(classname, 1);
1107         return a && c ? api_array_add(&c->providers, a) : (errno = ENOENT, -1);
1108 }
1109
1110 /**
1111  * Start any API that provides the class of name 'classname'
1112  */
1113 int afb_apiset_class_start(const char *classname)
1114 {
1115         struct api_class *cla = class_search(classname, 0);
1116         return cla ? start_class(cla) : (errno = ENOENT, -1);
1117 }
1118