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>
31 #include <afb/afb-binding-v2.h>
34 #include "afb-stub-ws.h"
37 #include "afb-api-so-v2.h"
38 #include "afb-apiset.h"
43 #include "wrap-json.h"
45 #include "afs-supervision.h"
46 #include "afs-supervisor.h"
47 #include "afs-discover.h"
49 /* supervised items */
52 /* link to the next supervised */
53 struct supervised *next;
55 /* credentials of the supervised */
56 struct afb_cred *cred;
58 /* connection with the supervised */
59 struct afb_stub_ws *stub;
62 /* api and apiset name */
63 static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
64 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
66 /* the empty apiset */
67 static struct afb_apiset *empty_apiset;
69 /* supervision socket path */
70 static const char supervision_socket_path[] = AFS_SUPERVISION_SOCKET;
71 static struct fdev *supervision_fdev;
74 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
76 /* list of supervised daemons */
77 static struct supervised *superviseds;
79 /*************************************************************************************/
82 /*************************************************************************************/
85 * Creates the supervisor socket for 'path' and return it
86 * return -1 in case of failure
88 static int create_supervision_socket(const char *path)
91 struct sockaddr_un addr;
94 /* check the path's length */
95 length = strlen(path);
97 ERROR("Path name of supervision socket too long: %d", (int)length);
102 /* create a socket */
103 fd = socket(AF_UNIX, SOCK_STREAM, 0);
105 ERROR("Can't create socket: %m");
109 /* setup the bind to a path */
110 memset(&addr, 0, sizeof addr);
111 addr.sun_family = AF_UNIX;
112 strcpy(addr.sun_path, path);
113 if (addr.sun_path[0] == '@')
114 addr.sun_path[0] = 0; /* abstract sockets */
118 /* binds the socket to the path */
119 rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
121 ERROR("can't bind socket to %s", path);
129 * send on 'fd' an initiator with 'command'
130 * return 0 on success or -1 on failure
132 static int send_initiator(int fd, const char *command)
136 struct afs_supervision_initiator asi;
139 memset(&asi, 0, sizeof asi);
140 strcpy(asi.interface, AFS_SUPERVISION_INTERFACE_1);
142 strncpy(asi.extra, command, sizeof asi.extra - 1);
144 /* send the initiator */
145 swr = write(fd, &asi, sizeof asi);
147 ERROR("Can't send initiator: %m");
149 } else if (swr < sizeof asi) {
150 ERROR("Sending incomplete initiator: %m");
158 * checks whether the incomming supervised represented by its creds
159 * is to be accepted or not.
160 * return 1 if yes or 0 otherwise.
162 static int should_accept(struct afb_cred *cred)
164 return cred && cred->pid != getpid(); /* not me! */
167 static void on_supervised_hangup(struct afb_stub_ws *stub)
169 struct supervised *s, **ps;
170 pthread_mutex_lock(&mutex);
172 while ((s = *ps) && s->stub != stub)
176 afb_stub_ws_unref(stub);
178 pthread_mutex_unlock(&mutex);
182 * create a supervised for socket 'fd' and 'cred'
183 * return 0 in case of success or -1 in case of error
185 static int make_supervised(int fd, struct afb_cred *cred)
187 struct supervised *s;
190 s = malloc(sizeof *s);
194 fdev = afb_fdev_create(fd);
201 s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
206 pthread_mutex_lock(&mutex);
207 s->next = superviseds;
209 pthread_mutex_unlock(&mutex);
210 afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
215 * Search the supervised of 'pid', return it or NULL.
217 static struct supervised *supervised_of_pid(pid_t pid)
219 struct supervised *s;
221 pthread_mutex_lock(&mutex);
223 while (s && pid != s->cred->pid)
225 pthread_mutex_unlock(&mutex);
231 * handles incoming connection on 'sock'
233 static void accept_supervision_link(int sock)
236 struct sockaddr addr;
238 struct afb_cred *cred;
240 lenaddr = (socklen_t)sizeof addr;
241 fd = accept(sock, &addr, &lenaddr);
243 cred = afb_cred_create_for_socket(fd);
244 rc = should_accept(cred);
246 rc = send_initiator(fd, NULL);
248 rc = make_supervised(fd, cred);
253 afb_cred_unref(cred);
259 * handle even on server socket
261 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
263 if ((revents & EPOLLIN) != 0)
264 accept_supervision_link((int)(intptr_t)closure);
265 if ((revents & EPOLLHUP) != 0) {
266 ERROR("supervision socket closed");
273 static void discovered_cb(void *closure, pid_t pid)
275 struct supervised *s;
277 s = supervised_of_pid(pid);
284 int afs_supervisor_discover()
287 afs_discover("afb-daemon", discovered_cb, &n);
291 /*************************************************************************************/
293 static struct afb_binding_data_v2 datav2;
295 static void f_list(struct afb_req req)
298 struct json_object *resu, *item;
299 struct supervised *s;
301 resu = json_object_new_object();
304 sprintf(pid, "%d", (int)s->cred->pid);
306 wrap_json_pack(&item, "{si si si ss ss ss}",
307 "pid", (int)s->cred->pid,
308 "uid", (int)s->cred->uid,
309 "gid", (int)s->cred->gid,
311 "label", s->cred->label,
312 "user", s->cred->user
314 json_object_object_add(resu, pid, item);
317 afb_req_success(req, resu, NULL);
320 static void f_discover(struct afb_req req)
322 afs_supervisor_discover();
323 afb_req_success(req, NULL, NULL);
326 static void propagate(struct afb_req req, const char *verb)
328 struct afb_xreq *xreq;
329 struct json_object *args, *item;
330 struct supervised *s;
334 xreq = xreq_from_request(req.closure);
335 args = afb_xreq_json(xreq);
336 if (!json_object_object_get_ex(args, "pid", &item)) {
337 afb_xreq_fail(xreq, "no-pid", NULL);
341 p = json_object_get_int(item);
343 afb_xreq_fail(xreq, "bad-pid", NULL);
346 s = supervised_of_pid((pid_t)p);
348 afb_req_fail(req, "unknown-pid", NULL);
351 json_object_object_del(args, "pid");
353 xreq->request.verb = verb;
354 api = afb_stub_ws_client_api(s->stub);
355 api.itf->call(api.closure, xreq);
358 static void f_do(struct afb_req req)
360 propagate(req, NULL);
363 static void f_config(struct afb_req req)
365 propagate(req, NULL);
368 static void f_trace(struct afb_req req)
370 propagate(req, NULL);
373 static void f_sessions(struct afb_req req)
375 propagate(req, "slist");
378 static void f_session_close(struct afb_req req)
380 propagate(req, "sclose");
383 static void f_exit(struct afb_req req)
385 propagate(req, NULL);
386 afb_req_success(req, NULL, NULL);
389 static void f_debug_wait(struct afb_req req)
391 propagate(req, "wait");
392 afb_req_success(req, NULL, NULL);
395 static void f_debug_break(struct afb_req req)
397 propagate(req, "break");
398 afb_req_success(req, NULL, NULL);
401 /*************************************************************************************/
404 * initalize the supervisor
406 static int init_supervisor()
410 /* create an empty set for superviseds */
411 empty_apiset = afb_apiset_create(supervision_apiname, 0);
413 ERROR("Can't create supervision apiset");
417 /* create the supervision socket */
418 fd = create_supervision_socket(supervision_socket_path);
422 /* listen the socket */
425 ERROR("refused to listen on socket");
429 /* integrate the socket to the loop */
430 supervision_fdev = afb_fdev_create(fd);
432 ERROR("handling socket event isn't possible");
435 fdev_set_events(supervision_fdev, EPOLLIN);
436 fdev_set_callback(supervision_fdev, listening, (void*)(intptr_t)fd);
441 /*************************************************************************************/
443 static const struct afb_auth _afb_auths_v2_supervisor[] = {
446 .type = afb_auth_Permission,
447 .text = "urn:AGL:permission:#supervision:platform:access"
451 static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = {
455 .auth = &_afb_auths_v2_supervisor[0],
457 .session = AFB_SESSION_CHECK_V2
461 .callback = f_config,
462 .auth = &_afb_auths_v2_supervisor[0],
464 .session = AFB_SESSION_CHECK_V2
469 .auth = &_afb_auths_v2_supervisor[0],
471 .session = AFB_SESSION_CHECK_V2
476 .auth = &_afb_auths_v2_supervisor[0],
478 .session = AFB_SESSION_CHECK_V2
482 .callback = f_sessions,
483 .auth = &_afb_auths_v2_supervisor[0],
485 .session = AFB_SESSION_CHECK_V2
488 .verb = "session-close",
489 .callback = f_session_close,
490 .auth = &_afb_auths_v2_supervisor[0],
492 .session = AFB_SESSION_CHECK_V2
497 .auth = &_afb_auths_v2_supervisor[0],
499 .session = AFB_SESSION_CHECK_V2
502 .verb = "debug-wait",
503 .callback = f_debug_wait,
504 .auth = &_afb_auths_v2_supervisor[0],
506 .session = AFB_SESSION_CHECK_V2
509 .verb = "debug-break",
510 .callback = f_debug_break,
511 .auth = &_afb_auths_v2_supervisor[0],
513 .session = AFB_SESSION_CHECK_V2
517 .callback = f_discover,
518 .auth = &_afb_auths_v2_supervisor[0],
520 .session = AFB_SESSION_CHECK_V2
525 static const struct afb_binding_v2 _afb_binding_v2_supervisor = {
526 .api = supervisor_apiname,
527 .specification = NULL,
529 .verbs = _afb_verbs_v2_supervisor,
531 .init = init_supervisor,
536 int afs_supervisor_add(struct afb_apiset *apiset)
538 return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2);