supervision: Add supervision and supervisor
authorJosé Bollo <jose.bollo@iot.bzh>
Thu, 29 Jun 2017 20:09:47 +0000 (22:09 +0200)
committerJosé Bollo <jose.bollo@iot.bzh>
Tue, 13 Feb 2018 09:56:14 +0000 (10:56 +0100)
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
src/CMakeLists.txt
src/afb-supervision.c [new file with mode: 0644]
src/afb-supervision.h [new file with mode: 0644]
src/afs-supervision.h [new file with mode: 0644]
src/afs-supervisor.c [new file with mode: 0644]
src/main.c

index f0e1d44..353db3b 100644 (file)
@@ -52,6 +52,7 @@ ADD_LIBRARY(afb-lib STATIC
        afb-proto-ws.c
        afb-session.c
        afb-stub-ws.c
+       afb-supervision.c
        afb-trace.c
        afb-websock.c
        afb-ws-client.c
@@ -81,6 +82,17 @@ TARGET_LINK_LIBRARIES(afb-daemon
 INSTALL(TARGETS afb-daemon
         RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
 
+###########################################
+# build and install afb-daemon
+###########################################
+ADD_EXECUTABLE(afs-supervisor afs-supervisor.c)
+TARGET_LINK_LIBRARIES(afs-supervisor
+       afb-lib
+       ${link_libraries}
+)
+INSTALL(TARGETS afs-supervisor
+        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
+
 ###########################################
 # build and install libafbwsc
 ###########################################
diff --git a/src/afb-supervision.c b/src/afb-supervision.c
new file mode 100644 (file)
index 0000000..a7099a4
--- /dev/null
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+#define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
+
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <json-c/json.h>
+#include <afb/afb-binding-v2.h>
+
+#include "afb-cred.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-api-so-v2.h"
+#include "afb-xreq.h"
+#include "afb-trace.h"
+#include "afb-session.h"
+#include "afb-supervision.h"
+#include "afs-supervision.h"
+#include "afb-stub-ws.h"
+#include "afb-debug.h"
+#include "verbose.h"
+#include "wrap-json.h"
+
+/* api and apiset name */
+static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
+
+/* path of the supervision socket */
+static const char supervisor_socket_path[] = AFS_SURPERVISION_SOCKET;
+
+/* mutual exclusion */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* the standard apiset */
+extern struct afb_apiset *main_apiset;
+
+/* the supervision apiset (not exported) */
+static struct afb_apiset *supervision_apiset;
+
+/* local api implementation */
+static void on_supervision_call(void *closure, struct afb_xreq *xreq);
+static struct afb_api_itf supervision_api_itf =
+{
+       .call = on_supervision_call
+};
+
+/* the supervisor link */
+static struct afb_stub_ws *supervisor;
+
+/* the trace api */
+static struct afb_trace *trace;
+
+/* open the socket */
+static int open_supervisor_socket(const char *path)
+{
+       int fd, rc;
+       struct sockaddr_un addr;
+       size_t length;
+
+       /* check path length */
+       length = strlen(path);
+       if (length >= 108) {
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       /* create the unix socket */
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0)
+               return fd;
+
+       /* prepare the connection address */
+       memset(&addr, 0, sizeof addr);
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, path);
+       if (addr.sun_path[0] == '@')
+               addr.sun_path[0] = 0; /* implement abstract sockets */
+
+       /* connect the socket */
+       rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
+       if (rc < 0) {
+               close(fd);
+               return rc;
+       }
+       return fd;
+}
+
+static void cleanup_supervisor(void *nada)
+{
+       struct afb_trace *t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
+       if (t)
+               afb_trace_unref(t);
+       supervisor = NULL;
+}
+
+static void disconnect_supervisor()
+{
+       struct afb_stub_ws *s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
+
+       if (s)
+               afb_stub_ws_unref(s);
+}
+
+/* try to connect to supervisor */
+static void try_connect_supervisor()
+{
+       int fd;
+       ssize_t srd;
+       struct afs_supervision_initiator initiator;
+
+       /* get the mutex */
+       pthread_mutex_lock(&mutex);
+
+       /* needs to connect? */
+       if (supervisor || !supervision_apiset)
+               goto end;
+
+       /* check existing path */
+       if (supervisor_socket_path[0] != '@' && access(supervisor_socket_path, F_OK)) {
+               NOTICE("Can't acces socket path %s: %m", supervisor_socket_path);
+               goto end;
+       }
+
+       /* socket connection */
+       fd = open_supervisor_socket(supervisor_socket_path);
+       if (fd < 0) {
+               NOTICE("Can't connect supervision socket to %s: %m", supervisor_socket_path);
+               goto end;
+       }
+
+       /* negociation */
+       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);
+               goto end2;
+       }
+       if ((size_t)srd != sizeof initiator) {
+               ERROR("When reading supervisor %s: %m", supervisor_socket_path);
+               goto end2;
+       }
+       if (strnlen(initiator.interface, sizeof initiator.interface) == sizeof initiator.interface) {
+               ERROR("Bad interface of supervisor %s", supervisor_socket_path);
+               goto end2;
+       }
+       if (strcmp(initiator.interface, AFS_SURPERVISION_INTERFACE_1)) {
+               ERROR("Unknown interface %s for supervisor %s", initiator.interface, supervisor_socket_path);
+               goto end2;
+       }
+       if (strnlen(initiator.extra, sizeof initiator.extra) == sizeof initiator.extra) {
+               ERROR("Bad extra of supervisor %s", supervisor_socket_path);
+               goto end2;
+       }
+
+       /* interprets extras */
+       if (!strcmp(initiator.extra, "CLOSE")) {
+               INFO("Supervisor asks to CLOSE");
+               goto end2;
+       }
+       if (!strcmp(initiator.extra, "WAIT")) {
+               afb_debug_wait("supervisor");
+       }
+       if (!strcmp(initiator.extra, "BREAK")) {
+               afb_debug_break("supervisor");
+       }
+
+       /* make the supervisor link */
+       supervisor = afb_stub_ws_create_server(fd, supervision_apiname, supervision_apiset);
+       if (!supervisor) {
+               ERROR("Creation of supervisor failed: %m");
+               goto end2;
+       }
+
+       /* successful termination */
+       goto end;
+
+end2:
+       close(fd);
+end:
+       pthread_mutex_unlock(&mutex);
+}
+
+static void on_sighup(int signum)
+{
+       try_connect_supervisor();
+}
+
+/**
+ * initalize the supervision
+ */
+int afb_supervision_init()
+{
+       int rc;
+       struct sigaction sa;
+
+       /* don't reinit */
+       if (supervision_apiset)
+               return 0;
+
+       /* create the apiset */
+       supervision_apiset = afb_apiset_create(supervision_apiname, 0);
+       if (!supervision_apiset) {
+               ERROR("Can't create supervision's apiset");
+               return -1;
+       }
+
+       /* init the apiset */
+       rc = afb_apiset_add(supervision_apiset, supervision_apiname,
+                       (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL});
+       if (rc < 0) {
+               ERROR("Can't create supervision's apiset: %m");
+               afb_apiset_unref(supervision_apiset);
+               supervision_apiset = NULL;
+               return rc;
+       }
+
+       /* get SIGHUP */
+       memset(&sa, 0, sizeof sa);
+       sa.sa_handler = on_sighup;
+       rc = sigaction(SIGHUP, &sa, NULL);
+       if (rc < 0)
+               ERROR("Can't connect supervision to SIGHUP: %m");
+
+       /* connect to supervision */
+       try_connect_supervisor();
+       return 0;
+}
+
+/******************************************************************************
+**** Implementation monitoring verbs
+******************************************************************************/
+static void slist(void *closure, struct afb_session *session)
+{
+       struct json_object *list = closure;
+       struct json_object *item;
+
+       wrap_json_pack(&item, "{ss}", "token", afb_session_token(session));
+       json_object_object_add(list, afb_session_uuid(session), item);
+}
+
+/******************************************************************************
+**** Implementation monitoring verbs
+******************************************************************************/
+
+static const char *verbs[] = {
+       "break", "do", "exit", "sclose", "slist", "trace", "wait" };
+enum  {  Break ,  Do ,  Exit ,  Sclose ,  Slist ,  Trace ,  Wait  };
+
+
+static void on_supervision_call(void *closure, struct afb_xreq *xreq)
+{
+       int i, rc;
+       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;
+
+       /* search the verb */
+       i = (int)(sizeof verbs / sizeof *verbs);
+       while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb));
+       if (i < 0) {
+               afb_xreq_fail_unknown_verb(xreq);
+               return;
+       }
+
+       /* process */
+       args = afb_xreq_json(xreq);
+       switch(i) {
+       case Exit:
+               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);
+               exit(i & 127);
+               break;
+       case Sclose:
+               uuid = NULL;
+               if (wrap_json_unpack(args, "s", &uuid))
+                       wrap_json_unpack(args, "{ss}", "uuid", &uuid);
+               if (!uuid)
+                       afb_xreq_fail(xreq, "invalid", NULL);
+               else {
+                       session = afb_session_search(uuid);
+                       if (!session)
+                               afb_xreq_fail(xreq, "not-found", NULL);
+                       else {
+                               afb_session_close(session);
+                               afb_session_unref(session);
+                               afb_session_purge();
+                               afb_xreq_success(xreq, NULL, NULL);
+                       }
+               }
+               break;
+       case Slist:
+               list = json_object_new_object();
+               afb_session_foreach(slist, list);
+               afb_xreq_success(xreq, list, NULL);
+               break;
+       case Trace:
+               if (!trace)
+                       trace = afb_trace_create(supervision_apiname, NULL /* not bound to any session */);
+
+               req = afb_xreq_unstore((struct afb_stored_req*)xreq);
+               wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
+               if (add) {
+                       rc = afb_trace_add(req, add, trace);
+                       if (rc)
+                               return;
+               }
+               if (drop) {
+                       rc = afb_trace_drop(req, drop, trace);
+                       if (rc)
+                               return;
+               }
+               afb_req_success(req, NULL, NULL);
+               break;
+       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");
+               else {
+                       xapi = afb_apiset_lookup_started(main_apiset, api, 1);
+                       if (!xapi)
+                               afb_xreq_fail_unknown_api(xreq);
+                       else {
+                               afb_cred_unref(xreq->cred);
+                               xreq->cred = NULL;
+                               xreq->request.api = api;
+                               xreq->request.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_debug_wait("supervisor");
+               break;
+       case Break:
+               afb_req_success(req, NULL, NULL);
+               afb_debug_break("supervisor");
+               break;
+       }
+}
+
diff --git a/src/afb-supervision.h b/src/afb-supervision.h
new file mode 100644 (file)
index 0000000..70f8a12
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+extern int afb_supervision_init();
diff --git a/src/afs-supervision.h b/src/afs-supervision.h
new file mode 100644 (file)
index 0000000..d33b04d
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+/*
+ * CAUTION!
+ * the default setting uses an abstract socket path
+ * be aware that this setting doesn't allow to enforce
+ * DAC for accessing the socket and then would allow
+ * anyone to create a such socket and usurpate the
+ * supervisor.
+ */
+#if !defined(AFS_SURPERVISION_SOCKET)
+#  define AFS_SURPERVISION_SOCKET "@urn:AGL:afs:supervision:socket" /* abstract */
+#endif
+
+/*
+ * generated using
+ * uuid -v 5 ns:URL urn:AGL:afs:supervision:interface:1
+ */
+#define AFS_SURPERVISION_INTERFACE_1 "86040e8d-eee5-5900-a129-3edb8da3ed46"
+
+
+/**
+ * packet initialy sent by monitor at start
+ */
+struct afs_supervision_initiator
+{
+       char interface[37];     /**< zero terminated interface uuid */
+       char extra[27];         /**< zero terminated extra computed here to be 64-37 */
+};
+
+#define AFS_SURPERVISION_APINAME "$"
diff --git a/src/afs-supervisor.c b/src/afs-supervisor.c
new file mode 100644 (file)
index 0000000..09df363
--- /dev/null
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2016, 2017 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <systemd/sd-event.h>
+#include <systemd/sd-daemon.h>
+
+#include <uuid/uuid.h>
+#include <json-c/json.h>
+#include <afb/afb-binding-v2.h>
+
+#include "afs-supervision.h"
+#include "afb-common.h"
+#include "afb-session.h"
+#include "afb-cred.h"
+#include "afb-stub-ws.h"
+#include "afb-api.h"
+#include "afb-xreq.h"
+#include "afb-api-so-v2.h"
+#include "afb-api-ws.h"
+#include "afb-apiset.h"
+#include "jobs.h"
+#include "verbose.h"
+#include "wrap-json.h"
+
+/* supervised items */
+struct supervised
+{
+       /* link to the next supervised */
+       struct supervised *next;
+
+       /* credentials of the supervised */
+       struct afb_cred *cred;
+
+       /* connection with the supervised */
+       struct afb_stub_ws *stub;
+};
+
+/* api and apiset name */
+static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
+
+/* the main apiset */
+struct afb_apiset *main_apiset;
+
+/* the empty apiset */
+static struct afb_apiset *empty_apiset;
+
+/* supervision socket path */
+static const char supervision_socket_path[] = AFS_SURPERVISION_SOCKET;
+
+/* global mutex */
+static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+
+/* list of supervised daemons */
+static struct supervised *superviseds;
+
+/*************************************************************************************/
+
+static int afb_init_supervision_api();
+
+/*************************************************************************************/
+
+/**
+ * Creates the supervisor socket for 'path' and return it
+ * return -1 in case of failure
+ */
+static int create_supervision_socket(const char *path)
+{
+       int fd, rc;
+       struct sockaddr_un addr;
+       size_t length;
+
+       /* check the path's length */
+       length = strlen(path);
+       if (length >= 108) {
+               ERROR("Path name of supervision socket too long: %d", (int)length);
+               errno = ENAMETOOLONG;
+               return -1;
+       }
+
+       /* create a socket */
+       fd = socket(AF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               ERROR("Can't create socket: %m");
+               return fd;
+       }
+
+       /* setup the bind to a path */
+       memset(&addr, 0, sizeof addr);
+       addr.sun_family = AF_UNIX;
+       strcpy(addr.sun_path, path);
+       if (addr.sun_path[0] == '@')
+               addr.sun_path[0] = 0; /* abstract sockets */
+       else
+               unlink(path);
+
+       /* binds the socket to the path */
+       rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
+       if (rc < 0) {
+               ERROR("can't bind socket to %s", path);
+               close(fd);
+               return rc;
+       }
+       return fd;
+}
+
+/**
+ * send on 'fd' an initiator with 'command'
+ * return 0 on success or -1 on failure
+ */
+static int send_initiator(int fd, const char *command)
+{
+       int rc;
+       ssize_t swr;
+       struct afs_supervision_initiator asi;
+
+       /* set  */
+       memset(&asi, 0, sizeof asi);
+       strcpy(asi.interface, AFS_SURPERVISION_INTERFACE_1);
+       if (command)
+               strncpy(asi.extra, command, sizeof asi.extra - 1);
+
+       /* send the initiator */
+       swr = write(fd, &asi, sizeof asi);
+       if (swr < 0) {
+               ERROR("Can't send initiator: %m");
+               rc = -1;
+       } else if (swr < sizeof asi) {
+               ERROR("Sending incomplete initiator: %m");
+               rc = -1;
+       } else
+               rc = 0;
+       return rc;
+}
+
+/*
+ * checks whether the incomming supervised represented by its creds
+ * is to be accepted or not.
+ * return 1 if yes or 0 otherwise.
+ */
+static int should_accept(struct afb_cred *cred)
+{
+       return cred && cred->pid != getpid(); /* not me! */
+}
+
+static void on_supervised_hangup(struct afb_stub_ws *stub)
+{
+       struct supervised *s, **ps;
+       pthread_mutex_lock(&mutex);
+       ps = &superviseds;
+       while ((s = *ps) && s->stub != stub)
+               ps = &s->next;
+       if (s) {
+               *ps = s->next;
+               afb_stub_ws_unref(stub);
+       }
+       pthread_mutex_unlock(&mutex);
+}
+
+/*
+ * create a supervised for socket 'fd' and 'cred'
+ * return 0 in case of success or -1 in case of error
+ */
+static int make_supervised(int fd, struct afb_cred *cred)
+{
+       struct supervised *s;
+
+       s = malloc(sizeof *s);
+       if (!s)
+               return -1;
+
+       s->cred = cred;
+       s->stub = afb_stub_ws_create_client(fd, supervision_apiname, empty_apiset);
+       if (!s->stub) {
+               free(s);
+               return -1;
+       }
+       pthread_mutex_lock(&mutex);
+       s->next = superviseds;
+       superviseds = s;
+       pthread_mutex_unlock(&mutex);
+       afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
+       return 0;
+}
+
+/*
+ * handles incoming connection on 'sock'
+ */
+static void accept_supervision_link(int sock)
+{
+       int rc, fd;
+       struct sockaddr addr;
+       socklen_t lenaddr;
+       struct afb_cred *cred;
+
+       lenaddr = (socklen_t)sizeof addr;
+       fd = accept(sock, &addr, &lenaddr);
+       if (fd >= 0) {
+               cred = afb_cred_create_for_socket(fd);
+               rc = should_accept(cred);
+               if (rc) {
+                       rc = send_initiator(fd, NULL);
+                       if (!rc) {
+                               rc = make_supervised(fd, cred);
+                               if (!rc)
+                                       return;
+                       }
+               }
+               afb_cred_unref(cred);
+               close(fd);
+       }
+}
+
+/*
+ * handle even on server socket
+ */
+static int listening(sd_event_source *src, int fd, uint32_t revents, void *closure)
+{
+       if ((revents & EPOLLIN) != 0)
+               accept_supervision_link(fd);
+       if ((revents & EPOLLHUP) != 0) {
+               ERROR("supervision socket closed");
+               exit(1);
+       }
+       return 0;
+}
+
+
+/**
+ * initalize the supervision
+ */
+static int init(const char *spec)
+{
+       int rc, fd;
+
+       /* check argument */
+       if (!spec) {
+               ERROR("invalid socket spec");
+               return -1;
+       }
+
+       rc = afb_session_init(100, 600, "");
+       /* TODO check that value */
+
+       /* create the apisets */
+       main_apiset = afb_apiset_create(supervision_apiname, 0);
+       if (!main_apiset) {
+               ERROR("Can't create supervision's apiset");
+               return -1;
+       }
+       empty_apiset = afb_apiset_create(supervision_apiname, 0);
+       if (!empty_apiset) {
+               ERROR("Can't create supervised apiset");
+               return -1;
+       }
+
+
+       /* init the main apiset */
+       rc = afb_init_supervision_api();
+       if (rc < 0) {
+               ERROR("Can't create supervision's apiset: %m");
+               return -1;
+       }
+
+       /* create the supervision socket */
+       fd = create_supervision_socket(supervision_socket_path);
+       if (fd < 0)
+               return fd;
+
+       /* listen the socket */
+       rc = listen(fd, 5);
+       if (rc < 0) {
+               ERROR("refused to listen on socket");
+               return rc;
+       }
+
+       /* integrate the socket to the loop */
+       rc = sd_event_add_io(afb_common_get_event_loop(),
+                               NULL, fd, EPOLLIN,
+                               listening, NULL);
+       if (rc < 0) {
+               ERROR("handling socket event isn't possible");
+               return rc;
+       }
+
+       /* adds the server socket */
+       rc = afb_api_ws_add_server(spec, main_apiset);
+       if (rc < 0) {
+               ERROR("can't start the server socket");
+               return -1;
+       }
+       return 0;
+}
+
+/* start should not be null but */
+static void start(int signum, void *arg)
+{
+       char *xpath = arg;
+       int rc;
+
+       if (signum)
+               exit(1);
+
+       rc = init(xpath);
+       if (rc)
+               exit(1);
+
+       sd_notify(1, "READY=1");
+}
+
+/**
+ * initalize the supervision
+ */
+int main(int ac, char **av)
+{
+       /* enter job processing */
+       jobs_start(3, 0, 10, start, av[1]);
+       WARNING("hoops returned from jobs_enter! [report bug]");
+       return 1;
+}
+
+/*********************************************************************************************************/
+
+static struct afb_binding_data_v2 datav2;
+
+static void f_list(struct afb_req req)
+{
+       char pid[50];
+       struct json_object *resu, *item;
+       struct supervised *s;
+
+       resu = json_object_new_object();
+       s = superviseds;
+       while (s) {
+               sprintf(pid, "%d", (int)s->cred->pid);
+               item = NULL;
+               wrap_json_pack(&item, "{si si si ss ss ss}",
+                               "pid", (int)s->cred->pid,
+                               "uid", (int)s->cred->uid,
+                               "gid", (int)s->cred->gid,
+                               "id", s->cred->id,
+                               "label", s->cred->label,
+                               "user", s->cred->user
+                               );
+               json_object_object_add(resu, pid, item);
+               s = s->next;
+       }
+       afb_req_success(req, resu, NULL);
+}
+
+static void propagate(struct afb_req req, const char *verb)
+{
+       struct afb_xreq *xreq;
+       struct json_object *args, *item;
+       struct supervised *s;
+       struct afb_api api;
+       int p;
+
+       xreq = xreq_from_request(req.closure);
+       args = afb_xreq_json(xreq);
+       if (!json_object_object_get_ex(args, "pid", &item)) {
+               afb_xreq_fail(xreq, "no-pid", NULL);
+               return;
+       }
+       errno = 0;
+       p = json_object_get_int(item);
+       if (!p && errno) {
+               afb_xreq_fail(xreq, "bad-pid", NULL);
+               return;
+       }
+       s = superviseds;
+       while (s && p != (int)s->cred->pid)
+               s = s->next;
+       if (!s) {
+               afb_req_fail(req, "unknown-pid", NULL);
+               return;
+       }
+       json_object_object_del(args, "pid");
+       if (verb)
+               xreq->request.verb = verb;
+       api = afb_stub_ws_client_api(s->stub);
+       api.itf->call(api.closure, xreq);
+}
+
+static void f_do(struct afb_req req)
+{
+       propagate(req, NULL);
+}
+
+static void f_trace(struct afb_req req)
+{
+       propagate(req, NULL);
+}
+
+static void f_sessions(struct afb_req req)
+{
+       propagate(req, "slist");
+}
+
+static void f_session_close(struct afb_req req)
+{
+       propagate(req, "sclose");
+}
+
+static void f_exit(struct afb_req req)
+{
+       propagate(req, NULL);
+}
+
+static void f_debug_wait(struct afb_req req)
+{
+       propagate(req, "wait");
+}
+
+static void f_debug_break(struct afb_req req)
+{
+       propagate(req, "break");
+}
+
+static const struct afb_auth _afb_auths_v2_supervision[] = {
+       /* 0 */
+       {
+               .type = afb_auth_Permission,
+               .text = "urn:AGL:permission:#supervision:platform:access"
+       }
+};
+
+static const struct afb_verb_v2 _afb_verbs_v2_supervision[] = {
+    {
+        .verb = "list",
+        .callback = f_list,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "do",
+        .callback = f_do,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "trace",
+        .callback = f_trace,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "sessions",
+        .callback = f_sessions,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "session-close",
+        .callback = f_session_close,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "exit",
+        .callback = f_exit,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "debug-wait",
+        .callback = f_debug_wait,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    {
+        .verb = "debug-break",
+        .callback = f_debug_break,
+        .auth = &_afb_auths_v2_supervision[0],
+        .info = NULL,
+        .session = AFB_SESSION_NONE_V2
+    },
+    { .verb = NULL }
+};
+
+static const struct afb_binding_v2 _afb_binding_v2_supervision = {
+    .api = supervision_apiname,
+    .specification = NULL,
+    .info = NULL,
+    .verbs = _afb_verbs_v2_supervision,
+    .preinit = NULL,
+    .init = NULL,
+    .onevent = NULL,
+    .noconcurrency = 0
+};
+
+static int afb_init_supervision_api()
+{
+       return afb_api_so_v2_add_binding(&_afb_binding_v2_supervision, NULL, main_apiset, &datav2);
+}
+
index b8bad94..c05556d 100644 (file)
@@ -54,6 +54,7 @@
 #include "sd-fds.h"
 #include "afb-debug.h"
 #include "process-name.h"
+#include "afb-supervision.h"
 
 /*
    if SELF_PGROUP == 0 the launched command is the group leader
@@ -571,6 +572,10 @@ static void start(int signum, void *arg)
                ERROR("failed to setup monitor");
                goto error;
        }
+       if (afb_supervision_init() < 0) {
+               ERROR("failed to setup supervision");
+               goto error;
+       }
 
        /* install hooks */
        if (config->tracereq)