2 * Copyright (C) 2016, 2017 "IoT.bzh"
3 * Author José Bollo <jose.bollo@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
27 #include <sys/types.h>
28 #include <sys/socket.h>
31 #include <systemd/sd-event.h>
32 #include <systemd/sd-daemon.h>
34 #include <uuid/uuid.h>
35 #include <json-c/json.h>
36 #include <afb/afb-binding-v2.h>
38 #include "afs-supervision.h"
39 #include "afb-common.h"
40 #include "afb-session.h"
42 #include "afb-stub-ws.h"
45 #include "afb-api-so-v2.h"
46 #include "afb-api-ws.h"
47 #include "afb-apiset.h"
50 #include "wrap-json.h"
52 /* supervised items */
55 /* link to the next supervised */
56 struct supervised *next;
58 /* credentials of the supervised */
59 struct afb_cred *cred;
61 /* connection with the supervised */
62 struct afb_stub_ws *stub;
65 /* api and apiset name */
66 static const char supervision_apiname[] = AFS_SURPERVISION_APINAME_INTERNAL;
67 static const char supervisor_apiname[] = "supervisor";
70 struct afb_apiset *main_apiset;
72 /* the empty apiset */
73 static struct afb_apiset *empty_apiset;
75 /* supervision socket path */
76 static const char supervision_socket_path[] = AFS_SURPERVISION_SOCKET;
79 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
81 /* list of supervised daemons */
82 static struct supervised *superviseds;
84 /*************************************************************************************/
86 static int afb_init_supervision_api();
88 /*************************************************************************************/
91 * Creates the supervisor socket for 'path' and return it
92 * return -1 in case of failure
94 static int create_supervision_socket(const char *path)
97 struct sockaddr_un addr;
100 /* check the path's length */
101 length = strlen(path);
103 ERROR("Path name of supervision socket too long: %d", (int)length);
104 errno = ENAMETOOLONG;
108 /* create a socket */
109 fd = socket(AF_UNIX, SOCK_STREAM, 0);
111 ERROR("Can't create socket: %m");
115 /* setup the bind to a path */
116 memset(&addr, 0, sizeof addr);
117 addr.sun_family = AF_UNIX;
118 strcpy(addr.sun_path, path);
119 if (addr.sun_path[0] == '@')
120 addr.sun_path[0] = 0; /* abstract sockets */
124 /* binds the socket to the path */
125 rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
127 ERROR("can't bind socket to %s", path);
135 * send on 'fd' an initiator with 'command'
136 * return 0 on success or -1 on failure
138 static int send_initiator(int fd, const char *command)
142 struct afs_supervision_initiator asi;
145 memset(&asi, 0, sizeof asi);
146 strcpy(asi.interface, AFS_SURPERVISION_INTERFACE_1);
148 strncpy(asi.extra, command, sizeof asi.extra - 1);
150 /* send the initiator */
151 swr = write(fd, &asi, sizeof asi);
153 ERROR("Can't send initiator: %m");
155 } else if (swr < sizeof asi) {
156 ERROR("Sending incomplete initiator: %m");
164 * checks whether the incomming supervised represented by its creds
165 * is to be accepted or not.
166 * return 1 if yes or 0 otherwise.
168 static int should_accept(struct afb_cred *cred)
170 return cred && cred->pid != getpid(); /* not me! */
173 static void on_supervised_hangup(struct afb_stub_ws *stub)
175 struct supervised *s, **ps;
176 pthread_mutex_lock(&mutex);
178 while ((s = *ps) && s->stub != stub)
182 afb_stub_ws_unref(stub);
184 pthread_mutex_unlock(&mutex);
188 * create a supervised for socket 'fd' and 'cred'
189 * return 0 in case of success or -1 in case of error
191 static int make_supervised(int fd, struct afb_cred *cred)
193 struct supervised *s;
195 s = malloc(sizeof *s);
200 s->stub = afb_stub_ws_create_client(fd, supervision_apiname, empty_apiset);
205 pthread_mutex_lock(&mutex);
206 s->next = superviseds;
208 pthread_mutex_unlock(&mutex);
209 afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
214 * handles incoming connection on 'sock'
216 static void accept_supervision_link(int sock)
219 struct sockaddr addr;
221 struct afb_cred *cred;
223 lenaddr = (socklen_t)sizeof addr;
224 fd = accept(sock, &addr, &lenaddr);
226 cred = afb_cred_create_for_socket(fd);
227 rc = should_accept(cred);
229 rc = send_initiator(fd, NULL);
231 rc = make_supervised(fd, cred);
236 afb_cred_unref(cred);
242 * handle even on server socket
244 static int listening(sd_event_source *src, int fd, uint32_t revents, void *closure)
246 if ((revents & EPOLLIN) != 0)
247 accept_supervision_link(fd);
248 if ((revents & EPOLLHUP) != 0) {
249 ERROR("supervision socket closed");
257 * initalize the supervision
259 static int init(const char *spec)
265 ERROR("invalid socket spec");
269 rc = afb_session_init(100, 600, "");
270 /* TODO check that value */
272 /* create the apisets */
273 main_apiset = afb_apiset_create(supervisor_apiname, 0);
275 ERROR("Can't create supervisor's apiset");
278 empty_apiset = afb_apiset_create(supervision_apiname, 0);
280 ERROR("Can't create supervision apiset");
285 /* init the main apiset */
286 rc = afb_init_supervision_api();
288 ERROR("Can't create supervision's apiset: %m");
292 /* create the supervision socket */
293 fd = create_supervision_socket(supervision_socket_path);
297 /* listen the socket */
300 ERROR("refused to listen on socket");
304 /* integrate the socket to the loop */
305 rc = sd_event_add_io(afb_common_get_event_loop(),
309 ERROR("handling socket event isn't possible");
313 /* adds the server socket */
314 rc = afb_api_ws_add_server(spec, main_apiset);
316 ERROR("can't start the server socket");
322 /* start should not be null but */
323 static void start(int signum, void *arg)
335 sd_notify(1, "READY=1");
339 * initalize the supervision
341 int main(int ac, char **av)
343 verbosity = Verbosity_Level_Debug;
344 /* enter job processing */
345 jobs_start(3, 0, 10, start, av[1]);
346 WARNING("hoops returned from jobs_enter! [report bug]");
350 /*********************************************************************************************************/
352 static struct afb_binding_data_v2 datav2;
354 static void f_list(struct afb_req req)
357 struct json_object *resu, *item;
358 struct supervised *s;
360 resu = json_object_new_object();
363 sprintf(pid, "%d", (int)s->cred->pid);
365 wrap_json_pack(&item, "{si si si ss ss ss}",
366 "pid", (int)s->cred->pid,
367 "uid", (int)s->cred->uid,
368 "gid", (int)s->cred->gid,
370 "label", s->cred->label,
371 "user", s->cred->user
373 json_object_object_add(resu, pid, item);
376 afb_req_success(req, resu, NULL);
379 static void propagate(struct afb_req req, const char *verb)
381 struct afb_xreq *xreq;
382 struct json_object *args, *item;
383 struct supervised *s;
387 xreq = xreq_from_request(req.closure);
388 args = afb_xreq_json(xreq);
389 if (!json_object_object_get_ex(args, "pid", &item)) {
390 afb_xreq_fail(xreq, "no-pid", NULL);
394 p = json_object_get_int(item);
396 afb_xreq_fail(xreq, "bad-pid", NULL);
400 while (s && p != (int)s->cred->pid)
403 afb_req_fail(req, "unknown-pid", NULL);
406 json_object_object_del(args, "pid");
408 xreq->request.verb = verb;
409 api = afb_stub_ws_client_api(s->stub);
410 api.itf->call(api.closure, xreq);
413 static void f_do(struct afb_req req)
415 propagate(req, NULL);
418 static void f_config(struct afb_req req)
420 propagate(req, NULL);
423 static void f_trace(struct afb_req req)
425 propagate(req, NULL);
428 static void f_sessions(struct afb_req req)
430 propagate(req, "slist");
433 static void f_session_close(struct afb_req req)
435 propagate(req, "sclose");
438 static void f_exit(struct afb_req req)
440 propagate(req, NULL);
443 static void f_debug_wait(struct afb_req req)
445 propagate(req, "wait");
448 static void f_debug_break(struct afb_req req)
450 propagate(req, "break");
453 static const struct afb_auth _afb_auths_v2_supervision[] = {
456 .type = afb_auth_Permission,
457 .text = "urn:AGL:permission:#supervision:platform:access"
461 static const struct afb_verb_v2 _afb_verbs_v2_supervision[] = {
465 .auth = &_afb_auths_v2_supervision[0],
467 .session = AFB_SESSION_NONE_V2
471 .callback = f_config,
472 .auth = &_afb_auths_v2_supervision[0],
474 .session = AFB_SESSION_NONE_V2
479 .auth = &_afb_auths_v2_supervision[0],
481 .session = AFB_SESSION_NONE_V2
486 .auth = &_afb_auths_v2_supervision[0],
488 .session = AFB_SESSION_NONE_V2
492 .callback = f_sessions,
493 .auth = &_afb_auths_v2_supervision[0],
495 .session = AFB_SESSION_NONE_V2
498 .verb = "session-close",
499 .callback = f_session_close,
500 .auth = &_afb_auths_v2_supervision[0],
502 .session = AFB_SESSION_NONE_V2
507 .auth = &_afb_auths_v2_supervision[0],
509 .session = AFB_SESSION_NONE_V2
512 .verb = "debug-wait",
513 .callback = f_debug_wait,
514 .auth = &_afb_auths_v2_supervision[0],
516 .session = AFB_SESSION_NONE_V2
519 .verb = "debug-break",
520 .callback = f_debug_break,
521 .auth = &_afb_auths_v2_supervision[0],
523 .session = AFB_SESSION_NONE_V2
528 static const struct afb_binding_v2 _afb_binding_v2_supervision = {
529 .api = supervisor_apiname,
530 .specification = NULL,
532 .verbs = _afb_verbs_v2_supervision,
539 static int afb_init_supervision_api()
541 return afb_api_so_v2_add_binding(&_afb_binding_v2_supervision, NULL, main_apiset, &datav2);