2 * Copyright (C) 2016-2019 "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"
42 #include "afb-socket.h"
46 #include "wrap-json.h"
48 #include "afs-supervision.h"
49 #include "afs-supervisor.h"
50 #include "afs-discover.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_SUPERVISION_APINAME;
67 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
69 /* the empty apiset */
70 static struct afb_apiset *empty_apiset;
72 /* supervision socket path */
73 static const char supervision_socket_path[] = AFS_SUPERVISION_SOCKET;
74 static struct fdev *supervision_fdev;
77 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
79 /* list of supervised daemons */
80 static struct supervised *superviseds;
83 static afb_event_t event_add_pid;
84 static afb_event_t event_del_pid;
86 /*************************************************************************************/
89 /*************************************************************************************/
92 * send on 'fd' an initiator with 'command'
93 * return 0 on success or -1 on failure
95 static int send_initiator(int fd, const char *command)
99 struct afs_supervision_initiator asi;
102 memset(&asi, 0, sizeof asi);
103 strcpy(asi.interface, AFS_SUPERVISION_INTERFACE_1);
105 strncpy(asi.extra, command, sizeof asi.extra - 1);
107 /* send the initiator */
108 swr = write(fd, &asi, sizeof asi);
110 ERROR("Can't send initiator: %m");
112 } else if (swr < sizeof asi) {
113 ERROR("Sending incomplete initiator: %m");
121 * checks whether the incoming supervised represented by its creds
122 * is to be accepted or not.
123 * return 1 if yes or 0 otherwise.
125 static int should_accept(struct afb_cred *cred)
127 return cred && cred->pid != getpid(); /* not me! */
130 static void on_supervised_hangup(struct afb_stub_ws *stub)
132 struct supervised *s, **ps;
134 /* Search the supervised of the ws-stub */
135 pthread_mutex_lock(&mutex);
137 while ((s = *ps) && s->stub != stub)
140 /* unlink the supervised if found */
143 pthread_mutex_unlock(&mutex);
145 /* forgive the ws-stub */
146 afb_stub_ws_unref(stub);
148 /* forgive the supervised */
150 afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
151 afb_cred_unref(s->cred);
157 * create a supervised for socket 'fd' and 'cred'
158 * return 0 in case of success or -1 in case of error
160 static int make_supervised(int fd, struct afb_cred *cred)
162 struct supervised *s;
165 s = malloc(sizeof *s);
169 fdev = afb_fdev_create(fd);
176 s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
181 pthread_mutex_lock(&mutex);
182 s->next = superviseds;
184 pthread_mutex_unlock(&mutex);
185 afb_stub_ws_set_on_hangup(s->stub, on_supervised_hangup);
190 * Search the supervised of 'pid', return it or NULL.
192 static struct supervised *supervised_of_pid(pid_t pid)
194 struct supervised *s;
196 pthread_mutex_lock(&mutex);
198 while (s && pid != s->cred->pid)
200 pthread_mutex_unlock(&mutex);
206 * handles incoming connection on 'sock'
208 static void accept_supervision_link(int sock)
211 struct sockaddr addr;
213 struct afb_cred *cred;
215 lenaddr = (socklen_t)sizeof addr;
216 fd = accept(sock, &addr, &lenaddr);
218 cred = afb_cred_create_for_socket(fd);
219 rc = should_accept(cred);
221 rc = send_initiator(fd, NULL);
223 rc = make_supervised(fd, cred);
225 afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
230 afb_cred_unref(cred);
236 * handle even on server socket
238 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
240 if ((revents & EPOLLHUP) != 0) {
241 ERROR("supervision socket closed");
244 if ((revents & EPOLLIN) != 0)
245 accept_supervision_link((int)(intptr_t)closure);
250 static void discovered_cb(void *closure, pid_t pid)
252 struct supervised *s;
254 s = supervised_of_pid(pid);
261 int afs_supervisor_discover()
264 afs_discover("afb-daemon", discovered_cb, &n);
268 /*************************************************************************************/
270 static void f_subscribe(afb_req_t req)
272 struct json_object *args = afb_req_json(req);
275 revoke = json_object_is_type(args, json_type_boolean)
276 && !json_object_get_boolean(args);
280 ok = !afb_req_subscribe(req, event_add_pid)
281 && !afb_req_subscribe(req, event_del_pid);
284 afb_req_unsubscribe(req, event_add_pid);
285 afb_req_unsubscribe(req, event_del_pid);
287 afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
290 static void f_list(afb_req_t req)
293 struct json_object *resu, *item;
294 struct supervised *s;
296 resu = json_object_new_object();
299 sprintf(pid, "%d", (int)s->cred->pid);
301 wrap_json_pack(&item, "{si si si ss ss ss}",
302 "pid", (int)s->cred->pid,
303 "uid", (int)s->cred->uid,
304 "gid", (int)s->cred->gid,
306 "label", s->cred->label,
307 "user", s->cred->user
309 json_object_object_add(resu, pid, item);
312 afb_req_success(req, resu, NULL);
315 static void f_discover(afb_req_t req)
317 afs_supervisor_discover();
318 afb_req_success(req, NULL, NULL);
321 static void propagate(afb_req_t req, const char *verb)
323 struct afb_xreq *xreq;
324 struct json_object *args, *item;
325 struct supervised *s;
326 struct afb_api_item api;
329 xreq = xreq_from_req_x2(req);
330 args = afb_xreq_json(xreq);
332 /* extract the pid */
333 if (!json_object_object_get_ex(args, "pid", &item)) {
334 afb_xreq_reply(xreq, NULL, "no-pid", NULL);
338 p = json_object_get_int(item);
340 afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
344 /* get supervised of pid */
345 s = supervised_of_pid((pid_t)p);
347 afb_req_reply(req, NULL, "unknown-pid", NULL);
350 json_object_object_del(args, "pid");
352 /* replace the verb to call if needed */
354 xreq->request.called_verb = verb;
357 api = afb_stub_ws_client_api(s->stub);
358 api.itf->call(api.closure, xreq);
361 static void f_do(afb_req_t req)
363 propagate(req, NULL);
366 static void f_config(afb_req_t req)
368 propagate(req, NULL);
371 static void f_trace(afb_req_t req)
373 propagate(req, NULL);
376 static void f_sessions(afb_req_t req)
378 propagate(req, "slist");
381 static void f_session_close(afb_req_t req)
383 propagate(req, "sclose");
386 static void f_exit(afb_req_t req)
388 propagate(req, NULL);
389 afb_req_success(req, NULL, NULL);
392 static void f_debug_wait(afb_req_t req)
394 propagate(req, "wait");
395 afb_req_success(req, NULL, NULL);
398 static void f_debug_break(afb_req_t req)
400 propagate(req, "break");
401 afb_req_success(req, NULL, NULL);
404 /*************************************************************************************/
407 * initialize the supervisor
409 static int init_supervisor(afb_api_t api)
411 event_add_pid = afb_api_make_event(api, "add-pid");
412 if (!afb_event_is_valid(event_add_pid)) {
413 ERROR("Can't create added event");
417 event_del_pid = afb_api_make_event(api, "del-pid");
418 if (!afb_event_is_valid(event_del_pid)) {
419 ERROR("Can't create deleted event");
423 /* create an empty set for superviseds */
424 empty_apiset = afb_apiset_create(supervision_apiname, 0);
426 ERROR("Can't create supervision apiset");
430 /* create the supervision socket */
431 supervision_fdev = afb_socket_open_fdev(supervision_socket_path, 1);
432 if (!supervision_fdev)
435 fdev_set_events(supervision_fdev, EPOLLIN);
436 fdev_set_callback(supervision_fdev, listening,
437 (void*)(intptr_t)fdev_fd(supervision_fdev));
442 /*************************************************************************************/
444 static const struct afb_auth _afb_auths_v2_supervisor[] = {
447 .type = afb_auth_Permission,
448 .text = "urn:AGL:permission:#supervision:platform:access"
452 static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
455 .callback = f_subscribe,
456 .auth = &_afb_auths_v2_supervisor[0],
458 .session = AFB_SESSION_CHECK_X2
463 .auth = &_afb_auths_v2_supervisor[0],
465 .session = AFB_SESSION_CHECK_X2
469 .callback = f_config,
470 .auth = &_afb_auths_v2_supervisor[0],
472 .session = AFB_SESSION_CHECK_X2
477 .auth = &_afb_auths_v2_supervisor[0],
479 .session = AFB_SESSION_CHECK_X2
484 .auth = &_afb_auths_v2_supervisor[0],
486 .session = AFB_SESSION_CHECK_X2
490 .callback = f_sessions,
491 .auth = &_afb_auths_v2_supervisor[0],
493 .session = AFB_SESSION_CHECK_X2
496 .verb = "session-close",
497 .callback = f_session_close,
498 .auth = &_afb_auths_v2_supervisor[0],
500 .session = AFB_SESSION_CHECK_X2
505 .auth = &_afb_auths_v2_supervisor[0],
507 .session = AFB_SESSION_CHECK_X2
510 .verb = "debug-wait",
511 .callback = f_debug_wait,
512 .auth = &_afb_auths_v2_supervisor[0],
514 .session = AFB_SESSION_CHECK_X2
517 .verb = "debug-break",
518 .callback = f_debug_break,
519 .auth = &_afb_auths_v2_supervisor[0],
521 .session = AFB_SESSION_CHECK_X2
525 .callback = f_discover,
526 .auth = &_afb_auths_v2_supervisor[0],
528 .session = AFB_SESSION_CHECK_X2
533 static const struct afb_binding_v3 _afb_binding_supervisor = {
534 .api = supervisor_apiname,
535 .specification = NULL,
537 .verbs = _afb_verbs_supervisor,
539 .init = init_supervisor,
544 int afs_supervisor_add(
545 struct afb_apiset *declare_set,
546 struct afb_apiset * call_set)
548 return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);