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