supervisor: Make it a HTTP server
[src/app-framework-binder.git] / src / afs-supervisor.c
1 /*
2  * Copyright (C) 2016, 2017 "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 <fcntl.h>
26 #include <pthread.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <sys/un.h>
30
31 #include <systemd/sd-event.h>
32 #include <systemd/sd-daemon.h>
33
34 #include <uuid/uuid.h>
35 #include <json-c/json.h>
36 #include <afb/afb-binding-v2.h>
37
38 #include "afb-systemd.h"
39 #include "afb-session.h"
40 #include "afb-cred.h"
41 #include "afb-stub-ws.h"
42 #include "afb-api.h"
43 #include "afb-xreq.h"
44 #include "afb-api-so-v2.h"
45 #include "afb-api-ws.h"
46 #include "afb-apiset.h"
47 #include "afb-fdev.h"
48 #include "jobs.h"
49 #include "verbose.h"
50 #include "wrap-json.h"
51 #include "process-name.h"
52
53 #include "afs-supervision.h"
54 #include "afs-supervisor.h"
55 #include "afs-discover.h"
56
57 /* supervised items */
58 struct supervised
59 {
60         /* link to the next supervised */
61         struct supervised *next;
62
63         /* credentials of the supervised */
64         struct afb_cred *cred;
65
66         /* connection with the supervised */
67         struct afb_stub_ws *stub;
68 };
69
70 /* api and apiset name */
71 static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
72 static const char supervisor_apiname[] = AFS_SURPERVISOR_APINAME;
73
74 /* the empty apiset */
75 static struct afb_apiset *empty_apiset;
76
77 /* supervision socket path */
78 static const char supervision_socket_path[] = AFS_SURPERVISION_SOCKET;
79
80 /* global mutex */
81 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
82
83 /* list of supervised daemons */
84 static struct supervised *superviseds;
85
86 /*************************************************************************************/
87
88
89 /*************************************************************************************/
90
91 /**
92  * Creates the supervisor socket for 'path' and return it
93  * return -1 in case of failure
94  */
95 static int create_supervision_socket(const char *path)
96 {
97         int fd, rc;
98         struct sockaddr_un addr;
99         size_t length;
100
101         /* check the path's length */
102         length = strlen(path);
103         if (length >= 108) {
104                 ERROR("Path name of supervision socket too long: %d", (int)length);
105                 errno = ENAMETOOLONG;
106                 return -1;
107         }
108
109         /* create a socket */
110         fd = socket(AF_UNIX, SOCK_STREAM, 0);
111         if (fd < 0) {
112                 ERROR("Can't create socket: %m");
113                 return fd;
114         }
115
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 */
122         else
123                 unlink(path);
124
125         /* binds the socket to the path */
126         rc = bind(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
127         if (rc < 0) {
128                 ERROR("can't bind socket to %s", path);
129                 close(fd);
130                 return rc;
131         }
132         return fd;
133 }
134
135 /**
136  * send on 'fd' an initiator with 'command'
137  * return 0 on success or -1 on failure
138  */
139 static int send_initiator(int fd, const char *command)
140 {
141         int rc;
142         ssize_t swr;
143         struct afs_supervision_initiator asi;
144
145         /* set  */
146         memset(&asi, 0, sizeof asi);
147         strcpy(asi.interface, AFS_SURPERVISION_INTERFACE_1);
148         if (command)
149                 strncpy(asi.extra, command, sizeof asi.extra - 1);
150
151         /* send the initiator */
152         swr = write(fd, &asi, sizeof asi);
153         if (swr < 0) {
154                 ERROR("Can't send initiator: %m");
155                 rc = -1;
156         } else if (swr < sizeof asi) {
157                 ERROR("Sending incomplete initiator: %m");
158                 rc = -1;
159         } else
160                 rc = 0;
161         return rc;
162 }
163
164 /*
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.
168  */
169 static int should_accept(struct afb_cred *cred)
170 {
171         return cred && cred->pid != getpid(); /* not me! */
172 }
173
174 static void on_supervised_hangup(struct afb_stub_ws *stub)
175 {
176         struct supervised *s, **ps;
177         pthread_mutex_lock(&mutex);
178         ps = &superviseds;
179         while ((s = *ps) && s->stub != stub)
180                 ps = &s->next;
181         if (s) {
182                 *ps = s->next;
183                 afb_stub_ws_unref(stub);
184         }
185         pthread_mutex_unlock(&mutex);
186 }
187
188 /*
189  * create a supervised for socket 'fd' and 'cred'
190  * return 0 in case of success or -1 in case of error
191  */
192 static int make_supervised(int fd, struct afb_cred *cred)
193 {
194         struct supervised *s;
195         struct fdev *fdev;
196
197         s = malloc(sizeof *s);
198         if (!s)
199                 return -1;
200
201         fdev = afb_fdev_create(fd);
202         if (!fdev) {
203                 free(s);
204                 return -1;
205         }
206
207         s->cred = cred;
208         s->stub = afb_stub_ws_create_client(fdev, supervision_apiname, empty_apiset);
209         if (!s->stub) {
210                 free(s);
211                 return -1;
212         }
213         pthread_mutex_lock(&mutex);
214         s->next = superviseds;
215         superviseds = s;
216         pthread_mutex_unlock(&mutex);
217         afb_stub_ws_on_hangup(s->stub, on_supervised_hangup);
218         return 0;
219 }
220
221 /**
222  * Search the supervised of 'pid', return it or NULL.
223  */
224 static struct supervised *supervised_of_pid(pid_t pid)
225 {
226         struct supervised *s;
227
228         pthread_mutex_lock(&mutex);
229         s = superviseds;
230         while (s && pid != s->cred->pid)
231                 s = s->next;
232         pthread_mutex_unlock(&mutex);
233
234         return s;
235 }
236
237 /*
238  * handles incoming connection on 'sock'
239  */
240 static void accept_supervision_link(int sock)
241 {
242         int rc, fd;
243         struct sockaddr addr;
244         socklen_t lenaddr;
245         struct afb_cred *cred;
246
247         lenaddr = (socklen_t)sizeof addr;
248         fd = accept(sock, &addr, &lenaddr);
249         if (fd >= 0) {
250                 cred = afb_cred_create_for_socket(fd);
251                 rc = should_accept(cred);
252                 if (rc) {
253                         rc = send_initiator(fd, NULL);
254                         if (!rc) {
255                                 rc = make_supervised(fd, cred);
256                                 if (!rc)
257                                         return;
258                         }
259                 }
260                 afb_cred_unref(cred);
261                 close(fd);
262         }
263 }
264
265 /*
266  * handle even on server socket
267  */
268 static int listening(sd_event_source *src, int fd, uint32_t revents, void *closure)
269 {
270         if ((revents & EPOLLIN) != 0)
271                 accept_supervision_link(fd);
272         if ((revents & EPOLLHUP) != 0) {
273                 ERROR("supervision socket closed");
274                 exit(1);
275         }
276         return 0;
277 }
278
279 /*
280  */
281 static void discovered_cb(void *closure, pid_t pid)
282 {
283         struct supervised *s;
284
285         s = supervised_of_pid(pid);
286         if (!s) {
287                 (*(int*)closure)++;
288                 kill(pid, SIGHUP);
289         }
290 }
291
292 int afs_supervisor_discover()
293 {
294         int n = 0;
295         afs_discover("afb-daemon", discovered_cb, &n);
296         return n;
297 }
298
299 /*************************************************************************************/
300
301 static struct afb_binding_data_v2 datav2;
302
303 static void f_list(struct afb_req req)
304 {
305         char pid[50];
306         struct json_object *resu, *item;
307         struct supervised *s;
308
309         resu = json_object_new_object();
310         s = superviseds;
311         while (s) {
312                 sprintf(pid, "%d", (int)s->cred->pid);
313                 item = NULL;
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,
318                                 "id", s->cred->id,
319                                 "label", s->cred->label,
320                                 "user", s->cred->user
321                                 );
322                 json_object_object_add(resu, pid, item);
323                 s = s->next;
324         }
325         afb_req_success(req, resu, NULL);
326 }
327
328 static void f_discover(struct afb_req req)
329 {
330         afs_supervisor_discover();
331         afb_req_success(req, NULL, NULL);
332 }
333
334 static void propagate(struct afb_req req, const char *verb)
335 {
336         struct afb_xreq *xreq;
337         struct json_object *args, *item;
338         struct supervised *s;
339         struct afb_api api;
340         int p;
341
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);
346                 return;
347         }
348         errno = 0;
349         p = json_object_get_int(item);
350         if (!p && errno) {
351                 afb_xreq_fail(xreq, "bad-pid", NULL);
352                 return;
353         }
354         s = supervised_of_pid((pid_t)p);
355         if (!s) {
356                 afb_req_fail(req, "unknown-pid", NULL);
357                 return;
358         }
359         json_object_object_del(args, "pid");
360         if (verb)
361                 xreq->request.verb = verb;
362         api = afb_stub_ws_client_api(s->stub);
363         api.itf->call(api.closure, xreq);
364 }
365
366 static void f_do(struct afb_req req)
367 {
368         propagate(req, NULL);
369 }
370
371 static void f_config(struct afb_req req)
372 {
373         propagate(req, NULL);
374 }
375
376 static void f_trace(struct afb_req req)
377 {
378         propagate(req, NULL);
379 }
380
381 static void f_sessions(struct afb_req req)
382 {
383         propagate(req, "slist");
384 }
385
386 static void f_session_close(struct afb_req req)
387 {
388         propagate(req, "sclose");
389 }
390
391 static void f_exit(struct afb_req req)
392 {
393         propagate(req, NULL);
394 }
395
396 static void f_debug_wait(struct afb_req req)
397 {
398         propagate(req, "wait");
399 }
400
401 static void f_debug_break(struct afb_req req)
402 {
403         propagate(req, "break");
404 }
405
406 /*************************************************************************************/
407
408 /**
409  * initalize the supervisor
410  */
411 static int init_supervisor()
412 {
413         int rc, fd;
414
415         /* create an empty set for superviseds */
416         empty_apiset = afb_apiset_create(supervision_apiname, 0);
417         if (!empty_apiset) {
418                 ERROR("Can't create supervision apiset");
419                 return -1;
420         }
421
422         /* create the supervision socket */
423         fd = create_supervision_socket(supervision_socket_path);
424         if (fd < 0)
425                 return fd;
426
427         /* listen the socket */
428         rc = listen(fd, 5);
429         if (rc < 0) {
430                 ERROR("refused to listen on socket");
431                 return rc;
432         }
433
434         /* integrate the socket to the loop */
435         rc = sd_event_add_io(afb_systemd_get_event_loop(),
436                                 NULL, fd, EPOLLIN,
437                                 listening, NULL);
438         if (rc < 0) {
439                 ERROR("handling socket event isn't possible");
440                 return rc;
441         }
442
443         return 0;
444 }
445
446 /*************************************************************************************/
447
448 static const struct afb_auth _afb_auths_v2_supervisor[] = {
449         /* 0 */
450         {
451                 .type = afb_auth_Permission,
452                 .text = "urn:AGL:permission:#supervision:platform:access"
453         }
454 };
455
456 static const struct afb_verb_v2 _afb_verbs_v2_supervisor[] = {
457     {
458         .verb = "list",
459         .callback = f_list,
460         .auth = &_afb_auths_v2_supervisor[0],
461         .info = NULL,
462         .session = AFB_SESSION_NONE_V2
463     },
464     {
465         .verb = "config",
466         .callback = f_config,
467         .auth = &_afb_auths_v2_supervisor[0],
468         .info = NULL,
469         .session = AFB_SESSION_NONE_V2
470     },
471     {
472         .verb = "do",
473         .callback = f_do,
474         .auth = &_afb_auths_v2_supervisor[0],
475         .info = NULL,
476         .session = AFB_SESSION_NONE_V2
477     },
478     {
479         .verb = "trace",
480         .callback = f_trace,
481         .auth = &_afb_auths_v2_supervisor[0],
482         .info = NULL,
483         .session = AFB_SESSION_NONE_V2
484     },
485     {
486         .verb = "sessions",
487         .callback = f_sessions,
488         .auth = &_afb_auths_v2_supervisor[0],
489         .info = NULL,
490         .session = AFB_SESSION_NONE_V2
491     },
492     {
493         .verb = "session-close",
494         .callback = f_session_close,
495         .auth = &_afb_auths_v2_supervisor[0],
496         .info = NULL,
497         .session = AFB_SESSION_NONE_V2
498     },
499     {
500         .verb = "exit",
501         .callback = f_exit,
502         .auth = &_afb_auths_v2_supervisor[0],
503         .info = NULL,
504         .session = AFB_SESSION_NONE_V2
505     },
506     {
507         .verb = "debug-wait",
508         .callback = f_debug_wait,
509         .auth = &_afb_auths_v2_supervisor[0],
510         .info = NULL,
511         .session = AFB_SESSION_NONE_V2
512     },
513     {
514         .verb = "debug-break",
515         .callback = f_debug_break,
516         .auth = &_afb_auths_v2_supervisor[0],
517         .info = NULL,
518         .session = AFB_SESSION_NONE_V2
519     },
520     {
521         .verb = "discover",
522         .callback = f_discover,
523         .auth = &_afb_auths_v2_supervisor[0],
524         .info = NULL,
525         .session = AFB_SESSION_NONE_V2
526     },
527     { .verb = NULL }
528 };
529
530 static const struct afb_binding_v2 _afb_binding_v2_supervisor = {
531     .api = supervisor_apiname,
532     .specification = NULL,
533     .info = NULL,
534     .verbs = _afb_verbs_v2_supervisor,
535     .preinit = NULL,
536     .init = init_supervisor,
537     .onevent = NULL,
538     .noconcurrency = 0
539 };
540
541 int afs_supervisor_add(struct afb_apiset *apiset)
542 {
543         return afb_api_so_v2_add_binding(&_afb_binding_v2_supervisor, NULL, apiset, &datav2);
544 }
545