Update copyright dates
[src/app-framework-binder.git] / src / afs-supervisor.c
1 /*
2  * Copyright (C) 2015-2020 "IoT.bzh"
3  * Author José Bollo <jose.bollo@iot.bzh>
4  *
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
8  *
9  *   http://www.apache.org/licenses/LICENSE-2.0
10  *
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.
16  */
17
18 #define _GNU_SOURCE
19
20 #include <stdio.h>
21 #include <string.h>
22 #include <errno.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <pthread.h>
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <sys/un.h>
29
30 #include <json-c/json.h>
31
32 #define AFB_BINDING_VERSION 3
33 #include <afb/afb-binding.h>
34
35 #include "afb-cred.h"
36 #include "afb-stub-ws.h"
37 #include "afb-api.h"
38 #include "afb-xreq.h"
39 #include "afb-api-v3.h"
40 #include "afb-apiset.h"
41 #include "afb-fdev.h"
42 #include "afb-socket.h"
43
44 #include "fdev.h"
45 #include "verbose.h"
46 #include "wrap-json.h"
47
48 #include "afs-supervision.h"
49 #include "afs-supervisor.h"
50 #include "afs-discover.h"
51
52 /* supervised items */
53 struct supervised
54 {
55         /* link to the next supervised */
56         struct supervised *next;
57
58         /* credentials of the supervised */
59         struct afb_cred *cred;
60
61         /* connection with the supervised */
62         struct afb_stub_ws *stub;
63 };
64
65 /* api and apiset name */
66 static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
67 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
68
69 /* the empty apiset */
70 static struct afb_apiset *empty_apiset;
71
72 /* supervision socket path */
73 static const char supervision_socket_path[] = AFS_SUPERVISION_SOCKET;
74 static struct fdev *supervision_fdev;
75
76 /* global mutex */
77 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
78
79 /* list of supervised daemons */
80 static struct supervised *superviseds;
81
82 /* events */
83 static afb_event_t event_add_pid;
84 static afb_event_t event_del_pid;
85
86 /*************************************************************************************/
87
88
89 /*************************************************************************************/
90
91 /**
92  * send on 'fd' an initiator with 'command'
93  * return 0 on success or -1 on failure
94  */
95 static int send_initiator(int fd, const char *command)
96 {
97         int rc;
98         ssize_t swr;
99         struct afs_supervision_initiator asi;
100
101         /* set  */
102         memset(&asi, 0, sizeof asi);
103         strcpy(asi.interface, AFS_SUPERVISION_INTERFACE_1);
104         if (command)
105                 strncpy(asi.extra, command, sizeof asi.extra - 1);
106
107         /* send the initiator */
108         swr = write(fd, &asi, sizeof asi);
109         if (swr < 0) {
110                 ERROR("Can't send initiator: %m");
111                 rc = -1;
112         } else if (swr < sizeof asi) {
113                 ERROR("Sending incomplete initiator: %m");
114                 rc = -1;
115         } else
116                 rc = 0;
117         return rc;
118 }
119
120 /*
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.
124  */
125 static int should_accept(struct afb_cred *cred)
126 {
127         return cred && cred->pid != getpid(); /* not me! */
128 }
129
130 static void on_supervised_hangup(struct afb_stub_ws *stub)
131 {
132         struct supervised *s, **ps;
133
134         /* Search the supervised of the ws-stub */
135         pthread_mutex_lock(&mutex);
136         ps = &superviseds;
137         while ((s = *ps) && s->stub != stub)
138                 ps = &s->next;
139
140         /* unlink the supervised if found */
141         if (s)
142                 *ps = s->next;
143         pthread_mutex_unlock(&mutex);
144
145         /* forgive the ws-stub */
146         afb_stub_ws_unref(stub);
147
148         /* forgive the supervised */
149         if (s) {
150                 afb_event_push(event_del_pid, json_object_new_int((int)s->cred->pid));
151                 afb_cred_unref(s->cred);
152                 free(s);
153         }
154 }
155
156 /*
157  * create a supervised for socket 'fd' and 'cred'
158  * return 0 in case of success or -1 in case of error
159  */
160 static int make_supervised(int fd, struct afb_cred *cred)
161 {
162         struct supervised *s;
163         struct fdev *fdev;
164
165         s = malloc(sizeof *s);
166         if (!s)
167                 return -1;
168
169         fdev = afb_fdev_create(fd);
170         if (!fdev) {
171                 free(s);
172                 return -1;
173         }
174
175         s->cred = cred;
176         s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
177         if (!s->stub) {
178                 free(s);
179                 return -1;
180         }
181         pthread_mutex_lock(&mutex);
182         s->next = superviseds;
183         superviseds = s;
184         pthread_mutex_unlock(&mutex);
185         afb_stub_ws_set_on_hangup(s->stub, on_supervised_hangup);
186         return 0;
187 }
188
189 /**
190  * Search the supervised of 'pid', return it or NULL.
191  */
192 static struct supervised *supervised_of_pid(pid_t pid)
193 {
194         struct supervised *s;
195
196         pthread_mutex_lock(&mutex);
197         s = superviseds;
198         while (s && pid != s->cred->pid)
199                 s = s->next;
200         pthread_mutex_unlock(&mutex);
201
202         return s;
203 }
204
205 /*
206  * handles incoming connection on 'sock'
207  */
208 static void accept_supervision_link(int sock)
209 {
210         int rc, fd;
211         struct sockaddr addr;
212         socklen_t lenaddr;
213         struct afb_cred *cred;
214
215         lenaddr = (socklen_t)sizeof addr;
216         fd = accept(sock, &addr, &lenaddr);
217         if (fd >= 0) {
218                 cred = afb_cred_create_for_socket(fd);
219                 rc = should_accept(cred);
220                 if (rc) {
221                         rc = send_initiator(fd, NULL);
222                         if (!rc) {
223                                 rc = make_supervised(fd, cred);
224                                 if (!rc) {
225                                         afb_event_push(event_add_pid, json_object_new_int((int)cred->pid));
226                                         return;
227                                 }
228                         }
229                 }
230                 afb_cred_unref(cred);
231                 close(fd);
232         }
233 }
234
235 /*
236  * handle even on server socket
237  */
238 static void listening(void *closure, uint32_t revents, struct fdev *fdev)
239 {
240         if ((revents & EPOLLHUP) != 0) {
241                 ERROR("supervision socket closed");
242                 exit(1);
243         }
244         if ((revents & EPOLLIN) != 0)
245                 accept_supervision_link((int)(intptr_t)closure);
246 }
247
248 /*
249  */
250 static void discovered_cb(void *closure, pid_t pid)
251 {
252         struct supervised *s;
253
254         s = supervised_of_pid(pid);
255         if (!s) {
256                 (*(int*)closure)++;
257                 kill(pid, SIGHUP);
258         }
259 }
260
261 int afs_supervisor_discover()
262 {
263         int n = 0;
264         afs_discover("afb-daemon", discovered_cb, &n);
265         return n;
266 }
267
268 /*************************************************************************************/
269
270 static void f_subscribe(afb_req_t req)
271 {
272         struct json_object *args = afb_req_json(req);
273         int revoke, ok;
274
275         revoke = json_object_is_type(args, json_type_boolean)
276                 && !json_object_get_boolean(args);
277
278         ok = 1;
279         if (!revoke) {
280                 ok = !afb_req_subscribe(req, event_add_pid)
281                         && !afb_req_subscribe(req, event_del_pid);
282         }
283         if (revoke || !ok) {
284                 afb_req_unsubscribe(req, event_add_pid);
285                 afb_req_unsubscribe(req, event_del_pid);
286         }
287         afb_req_reply(req, NULL, ok ? NULL : "error", NULL);
288 }
289
290 static void f_list(afb_req_t req)
291 {
292         char pid[50];
293         struct json_object *resu, *item;
294         struct supervised *s;
295
296         resu = json_object_new_object();
297         s = superviseds;
298         while (s) {
299                 sprintf(pid, "%d", (int)s->cred->pid);
300                 item = NULL;
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,
305                                 "id", s->cred->id,
306                                 "label", s->cred->label,
307                                 "user", s->cred->user
308                                 );
309                 json_object_object_add(resu, pid, item);
310                 s = s->next;
311         }
312         afb_req_success(req, resu, NULL);
313 }
314
315 static void f_discover(afb_req_t req)
316 {
317         afs_supervisor_discover();
318         afb_req_success(req, NULL, NULL);
319 }
320
321 static void propagate(afb_req_t req, const char *verb)
322 {
323         struct afb_xreq *xreq;
324         struct json_object *args, *item;
325         struct supervised *s;
326         struct afb_api_item api;
327         int p;
328
329         xreq = xreq_from_req_x2(req);
330         args = afb_xreq_json(xreq);
331
332         /* extract the pid */
333         if (!json_object_object_get_ex(args, "pid", &item)) {
334                 afb_xreq_reply(xreq, NULL, "no-pid", NULL);
335                 return;
336         }
337         errno = 0;
338         p = json_object_get_int(item);
339         if (!p && errno) {
340                 afb_xreq_reply(xreq, NULL, "bad-pid", NULL);
341                 return;
342         }
343
344         /* get supervised of pid */
345         s = supervised_of_pid((pid_t)p);
346         if (!s) {
347                 afb_req_reply(req, NULL, "unknown-pid", NULL);
348                 return;
349         }
350         json_object_object_del(args, "pid");
351
352         /* replace the verb to call if needed */
353         if (verb)
354                 xreq->request.called_verb = verb;
355
356         /* call it now */
357         api = afb_stub_ws_client_api(s->stub);
358         api.itf->call(api.closure, xreq);
359 }
360
361 static void f_do(afb_req_t req)
362 {
363         propagate(req, NULL);
364 }
365
366 static void f_config(afb_req_t req)
367 {
368         propagate(req, NULL);
369 }
370
371 static void f_trace(afb_req_t req)
372 {
373         propagate(req, NULL);
374 }
375
376 static void f_sessions(afb_req_t req)
377 {
378         propagate(req, "slist");
379 }
380
381 static void f_session_close(afb_req_t req)
382 {
383         propagate(req, "sclose");
384 }
385
386 static void f_exit(afb_req_t req)
387 {
388         propagate(req, NULL);
389         afb_req_success(req, NULL, NULL);
390 }
391
392 static void f_debug_wait(afb_req_t req)
393 {
394         propagate(req, "wait");
395         afb_req_success(req, NULL, NULL);
396 }
397
398 static void f_debug_break(afb_req_t req)
399 {
400         propagate(req, "break");
401         afb_req_success(req, NULL, NULL);
402 }
403
404 /*************************************************************************************/
405
406 /**
407  * initialize the supervisor
408  */
409 static int init_supervisor(afb_api_t api)
410 {
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");
414                 return -1;
415         }
416
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");
420                 return -1;
421         }
422
423         /* create an empty set for superviseds */
424         empty_apiset = afb_apiset_create(supervision_apiname, 0);
425         if (!empty_apiset) {
426                 ERROR("Can't create supervision apiset");
427                 return -1;
428         }
429
430         /* create the supervision socket */
431         supervision_fdev = afb_socket_open_fdev(supervision_socket_path, 1);
432         if (!supervision_fdev)
433                 return -1;
434
435         fdev_set_events(supervision_fdev, EPOLLIN);
436         fdev_set_callback(supervision_fdev, listening,
437                           (void*)(intptr_t)fdev_fd(supervision_fdev));
438
439         return 0;
440 }
441
442 /*************************************************************************************/
443
444 static const struct afb_auth _afb_auths_v2_supervisor[] = {
445         /* 0 */
446         {
447                 .type = afb_auth_Permission,
448                 .text = "urn:AGL:permission:#supervision:platform:access"
449         }
450 };
451
452 static const struct afb_verb_v3 _afb_verbs_supervisor[] = {
453     {
454         .verb = "subscribe",
455         .callback = f_subscribe,
456         .auth = &_afb_auths_v2_supervisor[0],
457         .info = NULL,
458         .session = AFB_SESSION_CHECK_X2
459     },
460     {
461         .verb = "list",
462         .callback = f_list,
463         .auth = &_afb_auths_v2_supervisor[0],
464         .info = NULL,
465         .session = AFB_SESSION_CHECK_X2
466     },
467     {
468         .verb = "config",
469         .callback = f_config,
470         .auth = &_afb_auths_v2_supervisor[0],
471         .info = NULL,
472         .session = AFB_SESSION_CHECK_X2
473     },
474     {
475         .verb = "do",
476         .callback = f_do,
477         .auth = &_afb_auths_v2_supervisor[0],
478         .info = NULL,
479         .session = AFB_SESSION_CHECK_X2
480     },
481     {
482         .verb = "trace",
483         .callback = f_trace,
484         .auth = &_afb_auths_v2_supervisor[0],
485         .info = NULL,
486         .session = AFB_SESSION_CHECK_X2
487     },
488     {
489         .verb = "sessions",
490         .callback = f_sessions,
491         .auth = &_afb_auths_v2_supervisor[0],
492         .info = NULL,
493         .session = AFB_SESSION_CHECK_X2
494     },
495     {
496         .verb = "session-close",
497         .callback = f_session_close,
498         .auth = &_afb_auths_v2_supervisor[0],
499         .info = NULL,
500         .session = AFB_SESSION_CHECK_X2
501     },
502     {
503         .verb = "exit",
504         .callback = f_exit,
505         .auth = &_afb_auths_v2_supervisor[0],
506         .info = NULL,
507         .session = AFB_SESSION_CHECK_X2
508     },
509     {
510         .verb = "debug-wait",
511         .callback = f_debug_wait,
512         .auth = &_afb_auths_v2_supervisor[0],
513         .info = NULL,
514         .session = AFB_SESSION_CHECK_X2
515     },
516     {
517         .verb = "debug-break",
518         .callback = f_debug_break,
519         .auth = &_afb_auths_v2_supervisor[0],
520         .info = NULL,
521         .session = AFB_SESSION_CHECK_X2
522     },
523     {
524         .verb = "discover",
525         .callback = f_discover,
526         .auth = &_afb_auths_v2_supervisor[0],
527         .info = NULL,
528         .session = AFB_SESSION_CHECK_X2
529     },
530     { .verb = NULL }
531 };
532
533 static const struct afb_binding_v3 _afb_binding_supervisor = {
534     .api = supervisor_apiname,
535     .specification = NULL,
536     .info = NULL,
537     .verbs = _afb_verbs_supervisor,
538     .preinit = NULL,
539     .init = init_supervisor,
540     .onevent = NULL,
541     .noconcurrency = 0
542 };
543
544 int afs_supervisor_add(
545                 struct afb_apiset *declare_set,
546                 struct afb_apiset * call_set)
547 {
548         return -!afb_api_v3_from_binding(&_afb_binding_supervisor, declare_set, call_set);
549 }
550