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