Update copyright dates
[src/app-framework-binder.git] / src / afb-supervision.c
index ecdcbf2..211c3fd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2016, 2017 "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");
@@ -15,8 +15,9 @@
  * limitations under the License.
  */
 
+#if 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>
 
-#include "afb-cred.h"
+#define AFB_BINDING_VERSION 3
+#include <afb/afb-binding.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-config.h"
+#include "afb-args.h"
 #include "afb-supervision.h"
 #include "afs-supervision.h"
 #include "afb-stub-ws.h"
 #include "afb-debug.h"
+#include "afb-fdev.h"
+#include "afb-error-text.h"
 #include "verbose.h"
 #include "wrap-json.h"
-
-extern struct afb_config *main_config;
+#include "jobs.h"
 
 /* api and apiset name */
-static const char supervision_apiname[] = AFS_SURPERVISION_APINAME_INTERNAL;
+static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
+#if WITH_AFB_TRACE
+static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
+#endif
 
 /* 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;
@@ -73,8 +82,10 @@ static struct afb_api_itf supervision_api_itf =
 /* the supervisor link */
 static struct afb_stub_ws *supervisor;
 
+#if WITH_AFB_TRACE
 /* the trace api */
 static struct afb_trace *trace;
+#endif
 
 /* open the socket */
 static int open_supervisor_socket(const char *path)
@@ -111,20 +122,26 @@ static int open_supervisor_socket(const char *path)
        return fd;
 }
 
-static void cleanup_supervisor(void *nada)
+static void disconnect_supervisor()
 {
+       struct afb_stub_ws *s;
+
+       INFO("Disconnecting supervision");
+       s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
+       if (s)
+               afb_stub_ws_unref(s);
+
+#if WITH_AFB_TRACE
        struct afb_trace *t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
        if (t)
                afb_trace_unref(t);
-       supervisor = NULL;
+#endif
 }
 
-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 */
@@ -133,6 +150,7 @@ static void try_connect_supervisor()
        int fd;
        ssize_t srd;
        struct afs_supervision_initiator initiator;
+       struct fdev *fdev;
 
        /* get the mutex */
        pthread_mutex_lock(&mutex);
@@ -143,18 +161,18 @@ static void try_connect_supervisor()
 
        /* 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);
+               INFO("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);
+               INFO("Can't connect supervision socket to %s: %m", supervisor_socket_path);
                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);
@@ -168,7 +186,7 @@ static void try_connect_supervisor()
                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;
        }
@@ -190,11 +208,17 @@ static void try_connect_supervisor()
        }
 
        /* 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;
@@ -205,15 +229,22 @@ 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;
@@ -231,7 +262,7 @@ int afb_supervision_init()
 
        /* 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);
@@ -239,6 +270,10 @@ int afb_supervision_init()
                return rc;
        }
 
+       /* init the globals */
+       global.apiset = apiset;
+       global.config = config;
+
        /* get SIGHUP */
        memset(&sa, 0, sizeof sa);
        sa.sa_handler = on_sighup;
@@ -257,10 +292,8 @@ int afb_supervision_init()
 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);
+       json_object_object_add(list, afb_session_uuid(session), NULL);
 }
 
 /******************************************************************************
@@ -271,21 +304,24 @@ static const char *verbs[] = {
        "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)
 {
-       int i, rc;
-       struct json_object *args, *drop, *add, *sub, *list;
+       int i;
+       struct json_object *args, *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;
+#if WITH_AFB_TRACE
+       struct json_object *drop, *add;
+       int rc;
+#endif
 
        /* 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;
        }
 
@@ -296,7 +332,7 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
                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:
@@ -304,32 +340,34 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
                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, afb_error_text_invalid_request, NULL);
                else {
                        session = afb_session_search(uuid);
                        if (!session)
-                               afb_xreq_fail(xreq, "not-found", NULL);
+                               afb_xreq_reply(xreq, NULL, afb_error_text_unknown_session, 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_success(xreq, afb_config_json(main_config), NULL);
+               afb_xreq_reply(xreq, json_object_get(global.config), NULL, NULL);
                break;
        case Trace:
+               req = xreq_to_req_x2(xreq);
+#if WITH_AFB_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);
+               add = drop = NULL;
                wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
                if (add) {
                        rc = afb_trace_add(req, add, trace);
@@ -342,20 +380,22 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
                                return;
                }
                afb_req_success(req, NULL, NULL);
+#else
+               afb_req_reply(req, NULL, afb_error_text_not_available, NULL);
+#endif
                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");
+                       afb_xreq_reply(xreq, NULL, afb_error_text_invalid_request, NULL);
                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;
+                               afb_context_change_cred(&xreq->context, NULL);
+                               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);
@@ -363,13 +403,14 @@ static void on_supervision_call(void *closure, struct afb_xreq *xreq)
                }
                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