2 * Copyright (C) 2016, 2017, 2018 "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.
26 #include <sys/types.h>
27 #include <sys/socket.h>
30 #include <json-c/json.h>
32 #define AFB_BINDING_VERSION 3
33 #include <afb/afb-binding.h>
36 #include "afb-stub-ws.h"
39 #include "afb-api-v3.h"
40 #include "afb-apiset.h"
45 #include "wrap-json.h"
47 #include "afs-supervision.h"
48 #include "afs-supervisor.h"
49 #include "afs-discover.h"
51 /* supervised items */
54 /* link to the next supervised */
55 struct supervised *next;
57 /* credentials of the supervised */
58 struct afb_cred *cred;
60 /* connection with the supervised */
61 struct afb_stub_ws *stub;
64 /* api and apiset name */
65 static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
66 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
68 /* the empty apiset */
69 static struct afb_apiset *empty_apiset;
71 /* supervision socket path */
72 static const char supervision_socket_path[] = AFS_SUPERVISION_SOCKET;
73 static struct fdev *supervision_fdev;
76 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
78 /* list of supervised daemons */
79 static struct supervised *superviseds;
82 static afb_event_t event_add_pid;
83 static afb_event_t event_del_pid;
85 /*************************************************************************************/
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_SUPERVISION_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 incoming 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 pthread_mutex_unlock(&mutex);
183 afb_stub_ws_unref(stub);
185 afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
186 afb_cred_unref(s->cred);
192 * create a supervised for socket 'fd' and 'cred'
193 * return 0 in case of success or -1 in case of error
195 static int make_supervised(int fd, struct afb_cred *cred)
197 struct supervised *s;
200 s = malloc(sizeof *s);
204 fdev = afb_fdev_create(fd);
211 s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
216 pthread_mutex_lock(&mutex);
217 s->next = superviseds;
219 pthread_mutex_unlock(&mutex);
220 afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
225 * Search the supervised of 'pid', return it or NULL.
227 static struct supervised *supervised_of_pid(pid_t pid)
229 struct supervised *s;
231 pthread_mutex_lock(&mutex);
233 while (s && pid != s->cred->pid)
235 pthread_mutex_unlock(&mutex);
241 * handles incoming connection on 'sock'
243 static void accept_supervision_link(int sock)
246 struct sockaddr addr;
248 struct afb_cred *cred;
250 lenaddr = (socklen_t)sizeof addr;
251 fd = accept(sock, &addr, &lenaddr);
253 cred = afb_cred_create_for_socket(fd);
254 rc = should_accept(cred);
256 rc = send_initiator(fd, NULL);
258 rc = make_supervised(fd, cred);
260 afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
265 afb_cred_unref(cred);
271 * handle even on server socket
273 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
275 if ((revents & EPOLLIN) != 0)
276 accept_supervision_link((int)(intptr_t)closure);
277 if ((revents & EPOLLHUP) != 0) {
278 ERROR("supervision socket closed");
285 static void discovered_cb(void *closure, pid_t pid)
287 struct supervised *s;
289 s = supervised_of_pid(pid);
296 int afs_supervisor_discover()
299 afs_discover("afb-daemon", discovered_cb, &n);
303 /*************************************************************************************/
305 static void f_subscribe(afb_req_t req)
307 struct json_object *args = afb_req_json(req);
310 revoke = json_object_is_type(args, json_type_boolean)
311 && !json_object_get_boolean(args);
315 ok = !afb_req_subscribe(req, event_add_pid)
316 && !afb_req_subscribe(req, event_del_pid);
319 afb_req_unsubscribe(req, event_add_pid);
320 afb_req_unsubscribe(req, event_del_pid);
322 afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
325 static void f_list(afb_req_t req)
328 struct json_object *resu, *item;
329 struct supervised *s;
331 resu = json_object_new_object();
334 sprintf(pid, "%d", (int)s->cred->pid);
336 wrap_json_pack(&item, "{si si si ss ss ss}",
337 "pid", (int)s->cred->pid,
338 "uid", (int)s->cred->uid,
339 "gid", (int)s->cred->gid,
341 "label", s->cred->label,
342 "user", s->cred->user
344 json_object_object_add(resu, pid, item);
347 afb_req_success(req, resu, NULL);
350 static void f_discover(afb_req_t req)
352 afs_supervisor_discover();
353 afb_req_success(req, NULL, NULL);
356 static void propagate(afb_req_t req, const char *verb)
358 struct afb_xreq *xreq;
359 struct json_object *args, *item;
360 struct supervised *s;
361 struct afb_api_item api;
364 xreq = xreq_from_req_x2(req);
365 args = afb_xreq_json(xreq);
366 if (!json_object_object_get_ex(args, "pid", &item)) {
367 afb_xreq_reply(xreq, NULL, "no-pid", NULL);
371 p = json_object_get_int(item);
373 afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
376 s = supervised_of_pid((pid_t)p);
378 afb_req_reply(req, NULL, "unknown-pid", NULL);
381 json_object_object_del(args, "pid");
383 xreq->request.called_verb = verb;
384 api = afb_stub_ws_client_api(s->stub);
385 api.itf->call(api.closure, xreq);
388 static void f_do(afb_req_t req)
390 propagate(req, NULL);
393 static void f_config(afb_req_t req)
395 propagate(req, NULL);
398 static void f_trace(afb_req_t req)
400 propagate(req, NULL);
403 static void f_sessions(afb_req_t req)
405 propagate(req, "slist");
408 static void f_session_close(afb_req_t req)
410 propagate(req, "sclose");
413 static void f_exit(afb_req_t req)
415 propagate(req, NULL);
416 afb_req_success(req, NULL, NULL);
419 static void f_debug_wait(afb_req_t req)
421 propagate(req, "wait");
422 afb_req_success(req, NULL, NULL);
425 static void f_debug_break(afb_req_t req)
427 propagate(req, "break");
428 afb_req_success(req, NULL, NULL);
431 /*************************************************************************************/
434 * initialize the supervisor
436 static int init_supervisor(afb_api_t api)
440 event_add_pid = afb_api_make_event(api, "add-pid");
441 if (!afb_event_is_valid(event_add_pid)) {
442 ERROR("Can't create added event");
446 event_del_pid = afb_api_make_event(api, "del-pid");
447 if (!afb_event_is_valid(event_del_pid)) {
448 ERROR("Can't create deleted event");
452 /* create an empty set for superviseds */
453 empty_apiset = afb_apiset_create(supervision_apiname, 0);
455 ERROR("Can't create supervision apiset");
459 /* create the supervision socket */
460 fd = create_supervision_socket(supervision_socket_path);
464 /* listen the socket */
467 ERROR("refused to listen on socket");
471 /* integrate the socket to the loop */
472 supervision_fdev = afb_fdev_create(fd);
474 ERROR("handling socket event isn't possible");
477 fdev_set_events(supervision_fdev, EPOLLIN);
478 fdev_set_callback(supervision_fdev, listening, (void*)(intptr_t)fd);
483 /*************************************************************************************/
485 static const struct afb_auth _afb_auths_v2_supervisor[] = {
488 .type = afb_auth_Permission,
489 .text = "urn:AGL:permission:#supervision:platform:access"
493 static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
496 .callback = f_subscribe,
497 .auth = &_afb_auths_v2_supervisor[0],
499 .session = AFB_SESSION_CHECK_X2
504 .auth = &_afb_auths_v2_supervisor[0],
506 .session = AFB_SESSION_CHECK_X2
510 .callback = f_config,
511 .auth = &_afb_auths_v2_supervisor[0],
513 .session = AFB_SESSION_CHECK_X2
518 .auth = &_afb_auths_v2_supervisor[0],
520 .session = AFB_SESSION_CHECK_X2
525 .auth = &_afb_auths_v2_supervisor[0],
527 .session = AFB_SESSION_CHECK_X2
531 .callback = f_sessions,
532 .auth = &_afb_auths_v2_supervisor[0],
534 .session = AFB_SESSION_CHECK_X2
537 .verb = "session-close",
538 .callback = f_session_close,
539 .auth = &_afb_auths_v2_supervisor[0],
541 .session = AFB_SESSION_CHECK_X2
546 .auth = &_afb_auths_v2_supervisor[0],
548 .session = AFB_SESSION_CHECK_X2
551 .verb = "debug-wait",
552 .callback = f_debug_wait,
553 .auth = &_afb_auths_v2_supervisor[0],
555 .session = AFB_SESSION_CHECK_X2
558 .verb = "debug-break",
559 .callback = f_debug_break,
560 .auth = &_afb_auths_v2_supervisor[0],
562 .session = AFB_SESSION_CHECK_X2
566 .callback = f_discover,
567 .auth = &_afb_auths_v2_supervisor[0],
569 .session = AFB_SESSION_CHECK_X2
574 static const struct afb_binding_v3 _afb_binding_supervisor = {
575 .api = supervisor_apiname,
576 .specification = NULL,
578 .verbs = _afb_verbs_supervisor,
580 .init = init_supervisor,
585 int afs_supervisor_add(
586 struct afb_apiset *declare_set,
587 struct afb_apiset * call_set)
589 return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);