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