2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author "Fulup Ar Foll"
4 * Author José Bollo <jose.bollo@iot.bzh>
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
26 #include "afb-session.h"
29 #include "afb-apiset.h"
30 #include "afb-context.h"
34 #include <afb/afb-req-itf.h>
36 #define INCR 8 /* CAUTION: must be a power of 2 */
39 * Internal description of an api
42 const char *name; /**< name of the api */
43 struct afb_api api; /**< handler of the api */
47 * Data structure for apiset
51 struct api_desc *apis; /**< description of apis */
52 struct afb_apiset *subset; /**< subset if any */
53 struct afb_api defapi; /**< default api if any */
54 int count; /**< count of apis in the set */
55 int timeout; /**< the timeout in second for the apiset */
56 int refcount; /**< reference count for freeing resources */
57 char name[1]; /**< name of the apiset */
61 * Search the api of 'name'.
62 * @param set the api set
63 * @param name the api name to search
64 * @return the descriptor if found or NULL otherwise
66 static const struct api_desc *search(struct afb_apiset *set, const char *name)
69 const struct api_desc *a;
71 /* dichotomic search of the api */
76 /* check remaining slice */
81 /* check the mid of the slice */
84 c = strcasecmp(a->name, name);
89 /* update the slice */
98 * Increases the count of references to the apiset and return its address
99 * @param set the set whose reference count is to be increased
100 * @return the given apiset
102 struct afb_apiset *afb_apiset_addref(struct afb_apiset *set)
105 __atomic_add_fetch(&set->refcount, 1, __ATOMIC_RELAXED);
110 * Decreases the count of references to the apiset and frees its
111 * resources when no more references exists.
112 * @param set the set to unrefrence
114 void afb_apiset_unref(struct afb_apiset *set)
116 if (set && !__atomic_sub_fetch(&set->refcount, 1, __ATOMIC_RELAXED)) {
117 afb_apiset_unref(set->subset);
125 * @param name the name of the apiset
126 * @param timeout the default timeout in seconds for the apiset
127 * @return the created apiset or NULL in case of error
129 struct afb_apiset *afb_apiset_create(const char *name, int timeout)
131 struct afb_apiset *set;
133 set = malloc((name ? strlen(name) : 0) + sizeof *set);
135 set->apis = malloc(INCR * sizeof *set->apis);
137 set->timeout = timeout;
140 set->defapi.itf = NULL;
142 strcpy(set->name, name);
150 * the name of the apiset
151 * @param set the api set
152 * @return the name of the set
154 const char *afb_apiset_name(struct afb_apiset *set)
160 * Get the API timeout of the set
161 * @param set the api set
162 * @return the timeout in seconds
164 int afb_apiset_timeout_get(struct afb_apiset *set)
170 * Set the API timeout of the set
171 * @param set the api set
172 * @param to the timeout in seconds
174 void afb_apiset_timeout_set(struct afb_apiset *set, int to)
180 * Get the subset of the set
181 * @param set the api set
182 * @return the subset of set
184 struct afb_apiset *afb_apiset_subset_get(struct afb_apiset *set)
190 * Set the subset of the set
191 * @param set the api set
192 * @param subset the subset to set
194 void afb_apiset_subset_set(struct afb_apiset *set, struct afb_apiset *subset)
196 struct afb_apiset *tmp;
198 /* avoid infinite loop */
202 set->subset = afb_apiset_addref(subset);
203 afb_apiset_unref(tmp);
207 * Check if the apiset has a default api
208 * @param set the api set
209 * @return 1 if the set has a default api or 0 otherwise
211 int afb_apiset_default_api_exist(struct afb_apiset *set)
213 return !!set->defapi.itf;
217 * Get the default api of the api set.
218 * @param set the api set
219 * @param api where to store the default api
220 * @return 0 in case of success or -1 when no default api is set
222 int afb_apiset_default_api_get(struct afb_apiset *set, struct afb_api *api)
224 if (set->defapi.itf) {
233 * Set the default api of the api set
234 * @param set the api set
235 * @param subset the subset to set
237 void afb_apiset_default_api_set(struct afb_apiset *set, struct afb_api api)
243 * Set the default api of the api set
244 * @param set the api set
246 void afb_apiset_default_api_drop(struct afb_apiset *set)
248 set->defapi.itf = NULL;
252 * Adds the api of 'name' described by 'api'.
253 * @param set the api set
254 * @param name the name of the api to add (have to survive, not copied!)
256 * @returns 0 in case of success or -1 in case
257 * of error with errno set:
258 * - EEXIST if name already registered
259 * - ENOMEM when out of memory
261 int afb_apiset_add(struct afb_apiset *set, const char *name, struct afb_api api)
263 struct api_desc *apis;
266 /* check previously existing plugin */
267 for (i = 0 ; i < set->count ; i++) {
268 c = strcasecmp(set->apis[i].name, name);
270 ERROR("api of name %s already exists", name);
278 /* allocates enough memory */
279 c = (set->count + INCR) & ~(INCR - 1);
280 apis = realloc(set->apis, ((unsigned)c) * sizeof * apis);
282 ERROR("out of memory");
288 /* copy higher part of the array */
291 memmove(apis + 1, apis, ((unsigned)(set->count - i)) * sizeof *apis);
293 /* record the plugin */
298 NOTICE("API %s added", name);
307 * Delete from the 'set' the api of 'name'.
308 * @param set the set to be changed
309 * @param name the name of the API to remove
310 * @return 0 in case of success or -1 in case where the API doesn't exist.
312 int afb_apiset_del(struct afb_apiset *set, const char *name)
317 for (i = 0 ; i < set->count ; i++) {
318 c = strcasecmp(set->apis[i].name, name);
321 while(i < set->count) {
322 set->apis[i] = set->apis[i + 1];
335 * Get from the 'set' the API of 'name' in 'api'
336 * @param set the set of API
337 * @param name the name of the API to get
338 * @param api the structure where to store data about the API of name
339 * @return 0 in case of success or -1 in case of error
341 int afb_apiset_lookup(struct afb_apiset *set, const char *name, struct afb_api *api)
343 const struct api_desc *i;
345 i = search(set, name);
356 * Get from the 'set' the API of 'name' in 'api' with fallback to subset or default api
357 * @param set the set of API
358 * @param name the name of the API to get
359 * @param api the structure where to store data about the API of name
360 * @return 0 in case of success or -1 in case of error
362 int afb_apiset_get(struct afb_apiset *set, const char *name, struct afb_api *api)
364 const struct api_desc *i;
366 i = search(set, name);
372 if (set->subset && 0 == afb_apiset_get(set->subset, name, api))
375 if (set->defapi.itf) {
385 * Starts a service by its 'api' name.
386 * @param set the api set
387 * @param name name of the service to start
388 * @param share_session if true start the servic"e in a shared session
389 * if false start it in its own session
390 * @param onneed if true start the service if possible, if false the api
392 * @return a positive number on success
394 int afb_apiset_start_service(struct afb_apiset *set, const char *name, int share_session, int onneed)
396 const struct api_desc *a;
398 a = search(set, name);
400 ERROR("can't find service %s", name);
405 if (a->api.itf->service_start)
406 return a->api.itf->service_start(a->api.closure, share_session, onneed, set);
411 /* already started: it is an error */
412 ERROR("The api %s is not a startable service", name);
418 * Starts all possible services but stops at first error.
419 * @param set the api set
420 * @param share_session if true start the servic"e in a shared session
421 * if false start it in its own session
422 * @return 0 on success or a negative number when an error is found
424 int afb_apiset_start_all_services(struct afb_apiset *set, int share_session)
427 const struct api_desc *i, *e;
430 e = &set->apis[set->count];
432 if (i->api.itf->service_start) {
433 rc = i->api.itf->service_start(i->api.closure, share_session, 1, set);
443 * Ask to update the hook flags of the 'api'
444 * @param set the api set
445 * @param name the api to update (NULL updates all)
447 void afb_apiset_update_hooks(struct afb_apiset *set, const char *name)
449 const struct api_desc *i, *e;
453 e = &set->apis[set->count];
455 i = search(set, name);
459 if (i->api.itf->update_hooks)
460 i->api.itf->update_hooks(i->api.closure);
466 * Set the verbosity level of the 'api'
467 * @param set the api set
468 * @param name the api to set (NULL set all)
470 void afb_apiset_set_verbosity(struct afb_apiset *set, const char *name, int level)
472 const struct api_desc *i, *e;
476 e = &set->apis[set->count];
478 i = search(set, name);
482 if (i->api.itf->set_verbosity)
483 i->api.itf->set_verbosity(i->api.closure, level);
489 * Set the verbosity level of the 'api'
490 * @param set the api set
491 * @param name the api to set (NULL set all)
493 int afb_apiset_get_verbosity(struct afb_apiset *set, const char *name)
495 const struct api_desc *i;
497 i = name ? search(set, name) : NULL;
502 if (!i->api.itf->get_verbosity)
505 return i->api.itf->get_verbosity(i->api.closure);
509 * Get the list of api names
510 * @param set the api set
511 * @return a NULL terminated array of api names. Must be freed.
513 const char **afb_apiset_get_names(struct afb_apiset *set)
520 size = set->count * (1 + sizeof(*names)) + sizeof(*names);
521 for (i = 0 ; i < set->count ; i++)
522 size += strlen(set->apis[i].name);
524 names = malloc(size);
528 dest = (void*)&names[set->count+1];
529 for (i = 0 ; i < set->count ; i++) {
531 dest = stpcpy(dest, set->apis[i].name) + 1;
539 * Enumerate the api names to a callback.
540 * @param set the api set
541 * @param callback the function to call for each name
542 * @param closure the closure for the callback
544 void afb_apiset_enum(struct afb_apiset *set, void (*callback)(struct afb_apiset *set, const char *name, void *closure), void *closure)
548 for (i = 0 ; i < set->count ; i++)
549 callback(set, set->apis[i].name, closure);