/*
- * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
+ * Copyright (C) 2015-2020 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#include <stdio.h>
#include <string.h>
#include <errno.h>
+#include <stdint.h>
-#include "afb-session.h"
#include "verbose.h"
#include "afb-api.h"
#include "afb-apiset.h"
#include "afb-context.h"
#include "afb-xreq.h"
+#include "jobs.h"
-#define INCR 8 /* CAUTION: must be a power of 2 */
+#define INCR 8 /* CAUTION: must be a power of 2 */
+#define NOT_STARTED -1
struct afb_apiset;
struct api_desc;
{
struct api_desc *next;
const char *name; /**< name of the api */
- int status; /**< initialisation status */
+ int status; /**< initialisation status:
+ - NOT_STARTED not started,
+ - 0 started without error,
+ - greater than 0, error number of start */
struct afb_api_item api; /**< handler of the api */
struct {
struct api_array classes;
{
struct api_alias *next;
struct api_desc *api;
- char name[1];
+ char name[];
};
/**
{
struct api_class *next;
struct api_array providers;
- char name[1];
+ char name[];
};
/**
struct api_depend
{
struct afb_apiset *set;
- char name[1];
+ char name[];
};
/**
} onlack; /** not found handler */
int timeout; /**< the timeout in second for the apiset */
int refcount; /**< reference count for freeing resources */
- char name[1]; /**< name of the apiset */
+ char name[]; /**< name of the apiset */
};
/**
if (!create)
return NULL;
- c = calloc(1, strlen(name) + sizeof *c);
+ c = calloc(1, strlen(name) + 1 + sizeof *c);
if (!c)
errno = ENOMEM;
else {
{
struct afb_apiset *set;
- set = calloc(1, (name ? strlen(name) : 0) + sizeof *set);
+ set = calloc(1, (name ? strlen(name) : 0) + 1 + sizeof *set);
if (set) {
set->timeout = timeout;
set->refcount = 1;
if (!desc)
goto oom;
- desc->status = -1;
+ desc->status = NOT_STARTED;
desc->api = api;
desc->name = name;
}
/* allocates and init the struct */
- ali = malloc(sizeof *ali + strlen(alias));
+ ali = malloc(sizeof *ali + strlen(alias) + 1);
if (ali == NULL) {
ERROR("out of memory");
errno = ENOMEM;
{
int i, rc = 0, rc2;
- i = array->count;
- while (i) {
- rc2 = start_api(array->apis[--i]);
- if (rc2 < 0) {
- rc = rc2;
+ i = 0;
+ while (i < array->count) {
+ rc2 = array->apis[i]->status;
+ if (rc2 == NOT_STARTED) {
+ rc2 = start_api(array->apis[i]);
+ if (rc2 < 0)
+ rc = rc2;
+ i = 0;
+ } else {
+ if (rc2)
+ rc = -1;
+ i++;
}
}
return rc;
struct api_desc *api;
int i, rc = 0, rc2;
- i = array->count;
- while (i) {
- i--;
+ i = 0;
+ while (i < array->count) {
api = searchrec(array->depends[i]->set, array->depends[i]->name);
- if (!api)
+ if (!api) {
rc = -1;
- else {
- rc2 = start_api(api);
- if (rc2 < 0) {
- rc = rc2;
+ i++;
+ } else {
+ rc2 = api->status;
+ if (rc2 == NOT_STARTED) {
+ rc2 = start_api(api);
+ if (rc2 < 0)
+ rc = rc2;
+ i = 0;
+ } else {
+ if (rc2)
+ rc = -1;
+ i++;
}
}
}
+
return rc;
}
/**
* Starts the service 'api'.
* @param api the api
- * @return a positive number on success
+ * @return zero on success, -1 on error
*/
static int start_api(struct api_desc *api)
{
int rc;
- if (api->status == 0)
+ if (api->status != NOT_STARTED) {
+ if (api->status > 0) {
+ errno = api->status;
+ return -1;
+ }
return 0;
- else if (api->status > 0) {
- errno = api->status;
- return -1;
}
- INFO("API %s starting...", api->name);
+ NOTICE("API %s starting...", api->name);
api->status = EBUSY;
rc = start_array_classes(&api->require.classes);
if (rc < 0)
api->status = errno ?: ECANCELED;
return -1;
}
- NOTICE("API %s started", api->name);
+ INFO("API %s started", api->name);
api->status = 0;
return 0;
}
* @param set the set of API
* @param name the name of the API to get
* @param rec if not zero look also recursively in subsets
- * @return 0 in case of success or -1 in case of error
+ * @return a pointer to the API item in case of success or NULL in case of error
*/
const struct afb_api_item *afb_apiset_lookup_started(struct afb_apiset *set, const char *name, int rec)
{
- struct api_desc *i;
+ struct api_desc *desc;
- i = lookup(set, name, rec);
- if (i)
- return i->status && start_api(i) ? NULL : &i->api;
- errno = ENOENT;
- return NULL;
+ desc = lookup(set, name, rec);
+ if (!desc) {
+ errno = ENOENT;
+ return NULL;
+ }
+ if (start_api(desc)) {
+ errno = desc->status;
+ return NULL;
+ }
+ return &desc->api;
}
/**
* Starts a service by its 'api' name.
* @param set the api set
* @param name name of the service to start
- * @return a positive number on success
+ * @return zero on success, -1 on error
*/
int afb_apiset_start_service(struct afb_apiset *set, const char *name)
{
*/
int afb_apiset_start_all_services(struct afb_apiset *set)
{
+ struct afb_apiset *rootset;
int rc, ret;
int i;
+ rootset = set;
ret = 0;
while (set) {
i = 0;
while (i < set->apis.count) {
- rc = start_api(set->apis.apis[i]);
- if (rc < 0)
- ret = rc;
- i++;
+ rc = set->apis.apis[i]->status;
+ if (rc == NOT_STARTED) {
+ rc = start_api(set->apis.apis[i]);
+ if (rc < 0)
+ ret = rc;
+ set = rootset;
+ i = 0;
+ } else {
+ if (rc)
+ ret = -1;
+ i++;
+ }
}
set = set->subset;
}
return ret;
}
+#if WITH_AFB_HOOK
/**
* Ask to update the hook flags of the 'api'
* @param set the api set
d->api.itf->update_hooks(d->api.closure);
}
}
+#endif
/**
* Set the logmask of the 'api' to 'mask'
return i->api.itf->get_logmask(i->api.closure);
}
-/**
- * Get the description of the API of 'name'
- * @param set the api set
- * @param name the api whose description is required
- * @return the description or NULL
- */
-struct json_object *afb_apiset_describe(struct afb_apiset *set, const char *name)
+void afb_apiset_describe(struct afb_apiset *set, const char *name, void (*describecb)(void *, struct json_object *), void *closure)
{
const struct api_desc *i;
-
- i = name ? searchrec(set, name) : NULL;
- return i && i->api.itf->describe ? i->api.itf->describe(i->api.closure) : NULL;
+ struct json_object *r;
+
+ r = NULL;
+ if (name) {
+ i = searchrec(set, name);
+ if (i) {
+ if (i->api.itf->describe) {
+ i->api.itf->describe(i->api.closure, describecb, closure);
+ return;
+ }
+ }
+ }
+ describecb(closure, r);
}
+
struct get_names {
union {
struct {
if (!a)
errno = ENOENT;
else {
- d = malloc(strlen(required) + sizeof *d);
+ d = malloc(strlen(required) + 1 + sizeof *d);
if (!d)
errno = ENOMEM;
else {