diff options
author | José Bollo <jose.bollo@iot.bzh> | 2017-06-29 22:09:47 +0200 |
---|---|---|
committer | José Bollo <jose.bollo@iot.bzh> | 2018-02-13 10:56:14 +0100 |
commit | b8c9d5de384efcfa53ebdb3f0053d7b3723777e1 (patch) | |
tree | ba1f8d64752fe2df1d8b40827029dcfde0c45f31 | |
parent | 32644e4d8f5413220b6393577ff4790225da6133 (diff) |
supervision: Add supervision and supervisor
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r-- | src/CMakeLists.txt | 12 | ||||
-rw-r--r-- | src/afb-supervision.c | 369 | ||||
-rw-r--r-- | src/afb-supervision.h | 21 | ||||
-rw-r--r-- | src/afs-supervision.h | 48 | ||||
-rw-r--r-- | src/afs-supervisor.c | 529 | ||||
-rw-r--r-- | src/main.c | 5 |
6 files changed, 984 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f0e1d448..353db3b6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 @@ -82,6 +83,17 @@ 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 ########################################### ADD_LIBRARY(afbwsc SHARED afb-ws.c afb-ws-client.c afb-wsj1.c websock.c afb-proto-ws.c jobs-fake.c) diff --git a/src/afb-supervision.c b/src/afb-supervision.c new file mode 100644 index 00000000..a7099a4a --- /dev/null +++ b/src/afb-supervision.c @@ -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 index 00000000..70f8a128 --- /dev/null +++ b/src/afb-supervision.h @@ -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 index 00000000..d33b04d3 --- /dev/null +++ b/src/afs-supervision.h @@ -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 index 00000000..09df3639 --- /dev/null +++ b/src/afs-supervisor.c @@ -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); +} + @@ -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) |