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;
177 /* Search the supervised of the ws-stub */
178 pthread_mutex_lock(&mutex);
180 while ((s = *ps) && s->stub != stub)
183 /* unlink the supervised if found */
186 pthread_mutex_unlock(&mutex);
188 /* forgive the ws-stub */
189 afb_stub_ws_unref(stub);
191 /* forgive the supervised */
193 afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
194 afb_cred_unref(s->cred);
200 * create a supervised for socket 'fd' and 'cred'
201 * return 0 in case of success or -1 in case of error
203 static int make_supervised(int fd, struct afb_cred *cred)
205 struct supervised *s;
208 s = malloc(sizeof *s);
212 fdev = afb_fdev_create(fd);
219 s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
224 pthread_mutex_lock(&mutex);
225 s->next = superviseds;
227 pthread_mutex_unlock(&mutex);
228 afb_stub_ws_set_on_hangup(s->stub, on_supervised_hangup);
233 * Search the supervised of 'pid', return it or NULL.
235 static struct supervised *supervised_of_pid(pid_t pid)
237 struct supervised *s;
239 pthread_mutex_lock(&mutex);
241 while (s && pid != s->cred->pid)
243 pthread_mutex_unlock(&mutex);
249 * handles incoming connection on 'sock'
251 static void accept_supervision_link(int sock)
254 struct sockaddr addr;
256 struct afb_cred *cred;
258 lenaddr = (socklen_t)sizeof addr;
259 fd = accept(sock, &addr, &lenaddr);
261 cred = afb_cred_create_for_socket(fd);
262 rc = should_accept(cred);
264 rc = send_initiator(fd, NULL);
266 rc = make_supervised(fd, cred);
268 afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
273 afb_cred_unref(cred);
279 * handle even on server socket
281 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
283 if ((revents & EPOLLIN) != 0)
284 accept_supervision_link((int)(intptr_t)closure);
285 if ((revents & EPOLLHUP) != 0) {
286 ERROR("supervision socket closed");
293 static void discovered_cb(void *closure, pid_t pid)
295 struct supervised *s;
297 s = supervised_of_pid(pid);
304 int afs_supervisor_discover()
307 afs_discover("afb-daemon", discovered_cb, &n);
311 /*************************************************************************************/
313 static void f_subscribe(afb_req_t req)
315 struct json_object *args = afb_req_json(req);
318 revoke = json_object_is_type(args, json_type_boolean)
319 && !json_object_get_boolean(args);
323 ok = !afb_req_subscribe(req, event_add_pid)
324 && !afb_req_subscribe(req, event_del_pid);
327 afb_req_unsubscribe(req, event_add_pid);
328 afb_req_unsubscribe(req, event_del_pid);
330 afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
333 static void f_list(afb_req_t req)
336 struct json_object *resu, *item;
337 struct supervised *s;
339 resu = json_object_new_object();
342 sprintf(pid, "%d", (int)s->cred->pid);
344 wrap_json_pack(&item, "{si si si ss ss ss}",
345 "pid", (int)s->cred->pid,
346 "uid", (int)s->cred->uid,
347 "gid", (int)s->cred->gid,
349 "label", s->cred->label,
350 "user", s->cred->user
352 json_object_object_add(resu, pid, item);
355 afb_req_success(req, resu, NULL);
358 static void f_discover(afb_req_t req)
360 afs_supervisor_discover();
361 afb_req_success(req, NULL, NULL);
364 static void propagate(afb_req_t req, const char *verb)
366 struct afb_xreq *xreq;
367 struct json_object *args, *item;
368 struct supervised *s;
369 struct afb_api_item api;
372 xreq = xreq_from_req_x2(req);
373 args = afb_xreq_json(xreq);
375 /* extract the pid */
376 if (!json_object_object_get_ex(args, "pid", &item)) {
377 afb_xreq_reply(xreq, NULL, "no-pid", NULL);
381 p = json_object_get_int(item);
383 afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
387 /* get supervised of pid */
388 s = supervised_of_pid((pid_t)p);
390 afb_req_reply(req, NULL, "unknown-pid", NULL);
393 json_object_object_del(args, "pid");
395 /* replace the verb to call if needed */
397 xreq->request.called_verb = verb;
400 api = afb_stub_ws_client_api(s->stub);
401 api.itf->call(api.closure, xreq);
404 static void f_do(afb_req_t req)
406 propagate(req, NULL);
409 static void f_config(afb_req_t req)
411 propagate(req, NULL);
414 static void f_trace(afb_req_t req)
416 propagate(req, NULL);
419 static void f_sessions(afb_req_t req)
421 propagate(req, "slist");
424 static void f_session_close(afb_req_t req)
426 propagate(req, "sclose");
429 static void f_exit(afb_req_t req)
431 propagate(req, NULL);
432 afb_req_success(req, NULL, NULL);
435 static void f_debug_wait(afb_req_t req)
437 propagate(req, "wait");
438 afb_req_success(req, NULL, NULL);
441 static void f_debug_break(afb_req_t req)
443 propagate(req, "break");
444 afb_req_success(req, NULL, NULL);
447 /*************************************************************************************/
450 * initialize the supervisor
452 static int init_supervisor(afb_api_t api)
456 event_add_pid = afb_api_make_event(api, "add-pid");
457 if (!afb_event_is_valid(event_add_pid)) {
458 ERROR("Can't create added event");
462 event_del_pid = afb_api_make_event(api, "del-pid");
463 if (!afb_event_is_valid(event_del_pid)) {
464 ERROR("Can't create deleted event");
468 /* create an empty set for superviseds */
469 empty_apiset = afb_apiset_create(supervision_apiname, 0);
471 ERROR("Can't create supervision apiset");
475 /* create the supervision socket */
476 fd = create_supervision_socket(supervision_socket_path);
480 /* listen the socket */
483 ERROR("refused to listen on socket");
487 /* integrate the socket to the loop */
488 supervision_fdev = afb_fdev_create(fd);
490 ERROR("handling socket event isn't possible");
493 fdev_set_events(supervision_fdev, EPOLLIN);
494 fdev_set_callback(supervision_fdev, listening, (void*)(intptr_t)fd);
499 /*************************************************************************************/
501 static const struct afb_auth _afb_auths_v2_supervisor[] = {
504 .type = afb_auth_Permission,
505 .text = "urn:AGL:permission:#supervision:platform:access"
509 static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
512 .callback = f_subscribe,
513 .auth = &_afb_auths_v2_supervisor[0],
515 .session = AFB_SESSION_CHECK_X2
520 .auth = &_afb_auths_v2_supervisor[0],
522 .session = AFB_SESSION_CHECK_X2
526 .callback = f_config,
527 .auth = &_afb_auths_v2_supervisor[0],
529 .session = AFB_SESSION_CHECK_X2
534 .auth = &_afb_auths_v2_supervisor[0],
536 .session = AFB_SESSION_CHECK_X2
541 .auth = &_afb_auths_v2_supervisor[0],
543 .session = AFB_SESSION_CHECK_X2
547 .callback = f_sessions,
548 .auth = &_afb_auths_v2_supervisor[0],
550 .session = AFB_SESSION_CHECK_X2
553 .verb = "session-close",
554 .callback = f_session_close,
555 .auth = &_afb_auths_v2_supervisor[0],
557 .session = AFB_SESSION_CHECK_X2
562 .auth = &_afb_auths_v2_supervisor[0],
564 .session = AFB_SESSION_CHECK_X2
567 .verb = "debug-wait",
568 .callback = f_debug_wait,
569 .auth = &_afb_auths_v2_supervisor[0],
571 .session = AFB_SESSION_CHECK_X2
574 .verb = "debug-break",
575 .callback = f_debug_break,
576 .auth = &_afb_auths_v2_supervisor[0],
578 .session = AFB_SESSION_CHECK_X2
582 .callback = f_discover,
583 .auth = &_afb_auths_v2_supervisor[0],
585 .session = AFB_SESSION_CHECK_X2
590 static const struct afb_binding_v3 _afb_binding_supervisor = {
591 .api = supervisor_apiname,
592 .specification = NULL,
594 .verbs = _afb_verbs_supervisor,
596 .init = init_supervisor,
601 int afs_supervisor_add(
602 struct afb_apiset *declare_set,
603 struct afb_apiset * call_set)
605 return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);