/*
- * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2016, 2017, 2018 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* limitations under the License.
*/
+#if defined(WITH_SUPERVISION)
+
#define _GNU_SOURCE
-#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
#include <string.h>
#include <errno.h>
#include <sys/un.h>
#include <json-c/json.h>
-#include <afb/afb-binding-v2.h>
+
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.h>
#include "afb-cred.h"
#include "afb-api.h"
#include "afb-xreq.h"
#include "afb-trace.h"
#include "afb-session.h"
+#include "afb-config.h"
#include "afb-supervision.h"
#include "afs-supervision.h"
#include "afb-stub-ws.h"
#include "afb-debug.h"
+#include "afb-fdev.h"
#include "verbose.h"
#include "wrap-json.h"
+#include "jobs.h"
/* api and apiset name */
-static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
+static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
+static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
/* path of the supervision socket */
-static const char supervisor_socket_path[] = AFS_SURPERVISION_SOCKET;
+static const char supervisor_socket_path[] = AFS_SUPERVISION_SOCKET;
/* mutual exclusion */
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
/* the standard apiset */
-extern struct afb_apiset *main_apiset;
+static struct {
+ struct afb_apiset *apiset;
+ struct json_object *config;
+} global;
/* the supervision apiset (not exported) */
static struct afb_apiset *supervision_apiset;
return fd;
}
-static void cleanup_supervisor(void *nada)
+static void disconnect_supervisor()
{
- struct afb_trace *t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
+ struct afb_stub_ws *s;
+ struct afb_trace *t;
+
+ INFO("Disconnecting supervision");
+ s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
+ t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
+ if (s)
+ afb_stub_ws_unref(s);
if (t)
afb_trace_unref(t);
- supervisor = NULL;
}
-static void disconnect_supervisor()
+static void on_supervisor_hangup(struct afb_stub_ws *s)
{
- struct afb_stub_ws *s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
-
- if (s)
- afb_stub_ws_unref(s);
+ if (s && s == supervisor)
+ disconnect_supervisor();
}
/* try to connect to supervisor */
int fd;
ssize_t srd;
struct afs_supervision_initiator initiator;
+ struct fdev *fdev;
/* get the mutex */
pthread_mutex_lock(&mutex);
goto end;
}
- /* negociation */
+ /* negotiation */
do { srd = read(fd, &initiator, sizeof initiator); } while(srd < 0 && errno == EINTR);
if (srd < 0) {
NOTICE("Can't read supervisor %s: %m", supervisor_socket_path);
ERROR("Bad interface of supervisor %s", supervisor_socket_path);
goto end2;
}
- if (strcmp(initiator.interface, AFS_SURPERVISION_INTERFACE_1)) {
+ if (strcmp(initiator.interface, AFS_SUPERVISION_INTERFACE_1)) {
ERROR("Unknown interface %s for supervisor %s", initiator.interface, supervisor_socket_path);
goto end2;
}
}
/* make the supervisor link */
- supervisor = afb_stub_ws_create_server(fd, supervision_apiname, supervision_apiset);
+ fdev = afb_fdev_create(fd);
+ if (!fdev) {
+ ERROR("Creation of fdev failed: %m");
+ goto end2;
+ }
+ supervisor = afb_stub_ws_create_server(fdev, supervision_apiname, supervision_apiset);
if (!supervisor) {
ERROR("Creation of supervisor failed: %m");
- goto end2;
+ goto end;
}
+ afb_stub_ws_set_on_hangup(supervisor, on_supervisor_hangup);
/* successful termination */
goto end;
pthread_mutex_unlock(&mutex);
}
-static void on_sighup(int signum)
+static void try_connect_supervisor_job(int signum, void *args)
{
+ INFO("Try to connect supervisor after SIGHUP");
try_connect_supervisor();
}
+static void on_sighup(int signum)
+{
+ INFO("Supervision received a SIGHUP");
+ jobs_queue(NULL, 0, try_connect_supervisor_job, NULL);
+}
+
/**
- * initalize the supervision
+ * initialize the supervision
*/
-int afb_supervision_init()
+int afb_supervision_init(struct afb_apiset *apiset, struct json_object *config)
{
int rc;
struct sigaction sa;
/* init the apiset */
rc = afb_apiset_add(supervision_apiset, supervision_apiname,
- (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL});
+ (struct afb_api_item){ .itf = &supervision_api_itf, .closure = NULL});
if (rc < 0) {
ERROR("Can't create supervision's apiset: %m");
afb_apiset_unref(supervision_apiset);
return rc;
}
+ /* init the globals */
+ global.apiset = apiset;
+ global.config = config;
+
/* get SIGHUP */
memset(&sa, 0, sizeof sa);
sa.sa_handler = on_sighup;
******************************************************************************/
static const char *verbs[] = {
- "break", "do", "exit", "sclose", "slist", "trace", "wait" };
-enum { Break , Do , Exit , Sclose , Slist , Trace , Wait };
-
+ "break", "config", "do", "exit", "sclose", "slist", "trace", "wait" };
+enum { Break , Config , Do , Exit , Sclose , Slist , Trace , Wait };
static void on_supervision_call(void *closure, struct afb_xreq *xreq)
{
struct json_object *args, *drop, *add, *sub, *list;
const char *api, *verb, *uuid;
struct afb_session *session;
- const struct afb_api *xapi;
- struct afb_req req;
+ const struct afb_api_item *xapi;
+ afb_req_t req;
/* search the verb */
i = (int)(sizeof verbs / sizeof *verbs);
- while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb));
+ while(--i >= 0 && strcasecmp(verbs[i], xreq->request.called_verb));
if (i < 0) {
- afb_xreq_fail_unknown_verb(xreq);
+ afb_xreq_reply_unknown_verb(xreq);
return;
}
i = 0;
if (wrap_json_unpack(args, "i", &i))
wrap_json_unpack(args, "{si}", "code", &i);
- ERROR("existing from supervision with code %d -> %d", i, i & 127);
+ ERROR("exiting from supervision with code %d -> %d", i, i & 127);
exit(i & 127);
break;
case Sclose:
if (wrap_json_unpack(args, "s", &uuid))
wrap_json_unpack(args, "{ss}", "uuid", &uuid);
if (!uuid)
- afb_xreq_fail(xreq, "invalid", NULL);
+ afb_xreq_reply(xreq, NULL, "invalid", NULL);
else {
session = afb_session_search(uuid);
if (!session)
- afb_xreq_fail(xreq, "not-found", NULL);
+ afb_xreq_reply(xreq, NULL, "not-found", NULL);
else {
afb_session_close(session);
afb_session_unref(session);
afb_session_purge();
- afb_xreq_success(xreq, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
}
}
break;
case Slist:
list = json_object_new_object();
afb_session_foreach(slist, list);
- afb_xreq_success(xreq, list, NULL);
+ afb_xreq_reply(xreq, list, NULL, NULL);
+ break;
+ case Config:
+ afb_xreq_reply(xreq, json_object_get(global.config), NULL, NULL);
break;
case Trace:
if (!trace)
- trace = afb_trace_create(supervision_apiname, NULL /* not bound to any session */);
+ trace = afb_trace_create(supervisor_apiname, NULL /* not bound to any session */);
- req = afb_xreq_unstore((struct afb_stored_req*)xreq);
+ req = xreq_to_req_x2(xreq);
+ add = drop = NULL;
wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
if (add) {
rc = afb_trace_add(req, add, trace);
case Do:
sub = NULL;
if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub))
- afb_xreq_fail(xreq, "error", "bad request");
+ afb_xreq_reply(xreq, NULL, "error", "bad request");
else {
- xapi = afb_apiset_lookup_started(main_apiset, api, 1);
+ xapi = afb_apiset_lookup_started(global.apiset, api, 1);
if (!xapi)
- afb_xreq_fail_unknown_api(xreq);
+ afb_xreq_reply_unknown_api(xreq);
else {
afb_cred_unref(xreq->cred);
xreq->cred = NULL;
- xreq->request.api = api;
- xreq->request.verb = verb;
+ xreq->request.called_api = api;
+ xreq->request.called_verb = verb;
xreq->json = json_object_get(sub);
xapi->itf->call(xapi->closure, xreq);
json_object_put(args);
}
break;
case Wait:
- afb_req_success(req, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
afb_debug_wait("supervisor");
break;
case Break:
- afb_req_success(req, NULL, NULL);
+ afb_xreq_reply(xreq, NULL, NULL, NULL);
afb_debug_break("supervisor");
break;
}
}
+#endif