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 "afb-systemd.h"
39 #include "afb-session.h"
41 #include "afb-stub-ws.h"
44 #include "afb-api-so-v2.h"
45 #include "afb-api-ws.h"
46 #include "afb-apiset.h"
50 #include "wrap-json.h"
51 #include "process-name.h"
53 #include "afs-supervision.h"
54 #include "afs-supervisor.h"
55 #include "afs-discover.h"
57 /* supervised items */
60 /* link to the next supervised */
61 struct supervised *next;
63 /* credentials of the supervised */
64 struct afb_cred *cred;
66 /* connection with the supervised */
67 struct afb_stub_ws *stub;
70 /* api and apiset name */
71 static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
72 static const char supervisor_apiname[] = AFS_SURPERVISOR_APINAME;
74 /* the empty apiset */
75 static struct afb_apiset *empty_apiset;
77 /* supervision socket path */
78 static const char supervision_socket_path[] = AFS_SURPERVISION_SOCKET;
81 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
83 /* list of supervised daemons */
84 static struct supervised *superviseds;
86 /*************************************************************************************/
89 /*************************************************************************************/
92 * Creates the supervisor socket for 'path' and return it
93 * return -1 in case of failure
95 static int create_supervision_socket(const char *path)
98 struct sockaddr_un addr;
101 /* check the path's length */
102 length = strlen(path);
104 ERROR("Path name of supervision socket too long: %d", (int)length);
105 errno = ENAMETOOLONG;
109 /* create a socket */
110 fd = socket(AF_UNIX, SOCK_STREAM, 0);
112 ERROR("Can't create socket: %m");
116 /* setup the bind to a path */
117 memset(&addr, 0, sizeof addr);
118 addr.sun_family = AF_UNIX;
119 strcpy(addr.sun_path, path);
120 if (addr.sun_path[0] == '@')
121 addr.sun_path[0] = 0; /* abstract sockets */
125 /* binds the socket to the path */
126 rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
128 ERROR("can't bind socket to %s", path);
136 * send on 'fd' an initiator with 'command'
137 * return 0 on success or -1 on failure
139 static int send_initiator(int fd, const char *command)
143 struct afs_supervision_initiator asi;
146 memset(&asi, 0, sizeof asi);
147 strcpy(asi.interface, AFS_SURPERVISION_INTERFACE_1);
149 strncpy(asi.extra, command, sizeof asi.extra - 1);
151 /* send the initiator */
152 swr = write(fd, &asi, sizeof asi);
154 ERROR("Can't send initiator: %m");
156 } else if (swr < sizeof asi) {
157 ERROR("Sending incomplete initiator: %m");
165 * checks whether the incomming supervised represented by its creds
166 * is to be accepted or not.
167 * return 1 if yes or 0 otherwise.
169 static int should_accept(struct afb_cred *cred)
171 return cred && cred->pid != getpid(); /* not me! */
174 static void on_supervised_hangup(struct afb_stub_ws *stub)
176 struct supervised *s, **ps;
177 pthread_mutex_lock(&mutex);
179 while ((s = *ps) && s->stub != stub)
183 afb_stub_ws_unref(stub);
185 pthread_mutex_unlock(&mutex);
189 * create a supervised for socket 'fd' and 'cred'
190 * return 0 in case of success or -1 in case of error
192 static int make_supervised(int fd, struct afb_cred *cred)
194 struct supervised *s;
197 s = malloc(sizeof *s);
201 fdev = afb_fdev_create(fd);
208 s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
213 pthread_mutex_lock(&mutex);
214 s->next = superviseds;
216 pthread_mutex_unlock(&mutex);
217 afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
222 * Search the supervised of 'pid', return it or NULL.
224 static struct supervised *supervised_of_pid(pid_t pid)
226 struct supervised *s;
228 pthread_mutex_lock(&mutex);
230 while (s && pid != s->cred->pid)
232 pthread_mutex_unlock(&mutex);
238 * handles incoming connection on 'sock'
240 static void accept_supervision_link(int sock)
243 struct sockaddr addr;
245 struct afb_cred *cred;
247 lenaddr = (socklen_t)sizeof addr;
248 fd = accept(sock, &addr, &lenaddr);
250 cred = afb_cred_create_for_socket(fd);
251 rc = should_accept(cred);
253 rc = send_initiator(fd, NULL);
255 rc = make_supervised(fd, cred);
260 afb_cred_unref(cred);
266 * handle even on server socket
268 static int listening(sd_event_source *src, int fd, uint32_t revents, void *closure)
270 if ((revents & EPOLLIN) != 0)
271 accept_supervision_link(fd);
272 if ((revents & EPOLLHUP) != 0) {
273 ERROR("supervision socket closed");
281 static void discovered_cb(void *closure, pid_t pid)
283 struct supervised *s;
285 s = supervised_of_pid(pid);
292 int afs_supervisor_discover()
295 afs_discover("afb-daemon", discovered_cb, &n);
299 /*************************************************************************************/
301 static struct afb_binding_data_v2 datav2;
303 static void f_list(struct afb_req req)
306 struct json_object *resu, *item;
307 struct supervised *s;
309 resu = json_object_new_object();
312 sprintf(pid, "%d", (int)s->cred->pid);
314 wrap_json_pack(&item, "{si si si ss ss ss}",
315 "pid", (int)s->cred->pid,
316 "uid", (int)s->cred->uid,
317 "gid", (int)s->cred->gid,
319 "label", s->cred->label,
320 "user", s->cred->user
322 json_object_object_add(resu, pid, item);
325 afb_req_success(req, resu, NULL);
328 static void f_discover(struct afb_req req)
330 afs_supervisor_discover();
331 afb_req_success(req, NULL, NULL);
334 static void propagate(struct afb_req req, const char *verb)
336 struct afb_xreq *xreq;
337 struct json_object *args, *item;
338 struct supervised *s;
342 xreq = xreq_from_request(req.closure);
343 args = afb_xreq_json(xreq);
344 if (!json_object_object_get_ex(args, "pid", &item)) {
345 afb_xreq_fail(xreq, "no-pid", NULL);
349 p = json_object_get_int(item);
351 afb_xreq_fail(xreq, "bad-pid", NULL);
354 s = supervised_of_pid((pid_t)p);
356 afb_req_fail(req, "unknown-pid", NULL);
359 json_object_object_del(args, "pid");
361 xreq->request.verb = verb;
362 api = afb_stub_ws_client_api(s->stub);
363 api.itf->call(api.closure, xreq);
366 static void f_do(struct afb_req req)
368 propagate(req, NULL);
371 static void f_config(struct afb_req req)
373 propagate(req, NULL);
376 static void f_trace(struct afb_req req)
378 propagate(req, NULL);
381 static void f_sessions(struct afb_req req)
383 propagate(req, "slist");
386 static void f_session_close(struct afb_req req)
388 propagate(req, "sclose");
391 static void f_exit(struct afb_req req)
393 propagate(req, NULL);
396 static void f_debug_wait(struct afb_req req)
398 propagate(req, "wait");
401 static void f_debug_break(struct afb_req req)
403 propagate(req, "break");
406 /*************************************************************************************/
409 * initalize the supervisor
411 static int init_supervisor()
415 /* create an empty set for superviseds */
416 empty_apiset = afb_apiset_create(supervision_apiname, 0);
418 ERROR("Can't create supervision apiset");
422 /* create the supervision socket */
423 fd = create_supervision_socket(supervision_socket_path);
427 /* listen the socket */
430 ERROR("refused to listen on socket");
434 /* integrate the socket to the loop */
435 rc = sd_event_add_io(afb_systemd_get_event_loop(),
439 ERROR("handling socket event isn't possible");
446 /*************************************************************************************/
448 static const struct afb_auth _afb_auths_v2_supervisor[] = {
451 .type = afb_auth_Permission,
452 .text = "urn:AGL:permission:#supervision:platform:access"
456 static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = {
460 .auth = &_afb_auths_v2_supervisor[0],
462 .session = AFB_SESSION_NONE_V2
466 .callback = f_config,
467 .auth = &_afb_auths_v2_supervisor[0],
469 .session = AFB_SESSION_NONE_V2
474 .auth = &_afb_auths_v2_supervisor[0],
476 .session = AFB_SESSION_NONE_V2
481 .auth = &_afb_auths_v2_supervisor[0],
483 .session = AFB_SESSION_NONE_V2
487 .callback = f_sessions,
488 .auth = &_afb_auths_v2_supervisor[0],
490 .session = AFB_SESSION_NONE_V2
493 .verb = "session-close",
494 .callback = f_session_close,
495 .auth = &_afb_auths_v2_supervisor[0],
497 .session = AFB_SESSION_NONE_V2
502 .auth = &_afb_auths_v2_supervisor[0],
504 .session = AFB_SESSION_NONE_V2
507 .verb = "debug-wait",
508 .callback = f_debug_wait,
509 .auth = &_afb_auths_v2_supervisor[0],
511 .session = AFB_SESSION_NONE_V2
514 .verb = "debug-break",
515 .callback = f_debug_break,
516 .auth = &_afb_auths_v2_supervisor[0],
518 .session = AFB_SESSION_NONE_V2
522 .callback = f_discover,
523 .auth = &_afb_auths_v2_supervisor[0],
525 .session = AFB_SESSION_NONE_V2
530 static const struct afb_binding_v2 _afb_binding_v2_supervisor = {
531 .api = supervisor_apiname,
532 .specification = NULL,
534 .verbs = _afb_verbs_v2_supervisor,
536 .init = init_supervisor,
541 int afs_supervisor_add(struct afb_apiset *apiset)
543 return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2);