2 * Copyright (C) 2015-2020 "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.
28 #include <sys/types.h>
29 #include <sys/socket.h>
32 #include <json-c/json.h>
34 #define AFB_BINDING_VERSION 3
35 #define AFB_BINDING_NO_ROOT
36 #include <afb/afb-binding.h>
39 #include "afb-apiset.h"
40 #include "afb-api-so-v2.h"
42 #include "afb-trace.h"
43 #include "afb-session.h"
45 #include "afb-supervision.h"
46 #include "afs-supervision.h"
47 #include "afb-stub-ws.h"
48 #include "afb-debug.h"
50 #include "afb-error-text.h"
52 #include "wrap-json.h"
55 /* api and apiset name */
56 static const char supervision_apiname[] = AFS_SUPERVISION_APINAME;
58 static const char supervisor_apiname[] = AFS_SUPERVISOR_APINAME;
61 /* path of the supervision socket */
62 static const char supervisor_socket_path[] = AFS_SUPERVISION_SOCKET;
64 /* mutual exclusion */
65 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
67 /* the standard apiset */
69 struct afb_apiset *apiset;
70 struct json_object *config;
73 /* the supervision apiset (not exported) */
74 static struct afb_apiset *supervision_apiset;
76 /* local api implementation */
77 static void on_supervision_call(void *closure, struct afb_xreq *xreq);
78 static struct afb_api_itf supervision_api_itf =
80 .call = on_supervision_call
83 /* the supervisor link */
84 static struct afb_stub_ws *supervisor;
88 static struct afb_trace *trace;
92 static int open_supervisor_socket(const char *path)
95 struct sockaddr_un addr;
98 /* check path length */
99 length = strlen(path);
101 errno = ENAMETOOLONG;
105 /* create the unix socket */
106 fd = socket(AF_UNIX, SOCK_STREAM, 0);
110 /* prepare the connection address */
111 memset(&addr, 0, sizeof addr);
112 addr.sun_family = AF_UNIX;
113 strcpy(addr.sun_path, path);
114 if (addr.sun_path[0] == '@')
115 addr.sun_path[0] = 0; /* implement abstract sockets */
117 /* connect the socket */
118 rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
126 static void disconnect_supervisor()
128 struct afb_stub_ws *s;
130 INFO("Disconnecting supervision");
131 s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
133 afb_stub_ws_unref(s);
136 struct afb_trace *t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
142 static void on_supervisor_hangup(struct afb_stub_ws *s)
144 if (s && s == supervisor)
145 disconnect_supervisor();
148 /* try to connect to supervisor */
149 static void try_connect_supervisor()
153 struct afs_supervision_initiator initiator;
157 pthread_mutex_lock(&mutex);
159 /* needs to connect? */
160 if (supervisor || !supervision_apiset)
163 /* check existing path */
164 if (supervisor_socket_path[0] != '@' && access(supervisor_socket_path, F_OK)) {
165 INFO("Can't acces socket path %s: %m", supervisor_socket_path);
169 /* socket connection */
170 fd = open_supervisor_socket(supervisor_socket_path);
172 INFO("Can't connect supervision socket to %s: %m", supervisor_socket_path);
177 do { srd = read(fd, &initiator, sizeof initiator); } while(srd < 0 && errno == EINTR);
179 NOTICE("Can't read supervisor %s: %m", supervisor_socket_path);
182 if ((size_t)srd != sizeof initiator) {
183 ERROR("When reading supervisor %s: %m", supervisor_socket_path);
186 if (strnlen(initiator.interface, sizeof initiator.interface) == sizeof initiator.interface) {
187 ERROR("Bad interface of supervisor %s", supervisor_socket_path);
190 if (strcmp(initiator.interface, AFS_SUPERVISION_INTERFACE_1)) {
191 ERROR("Unknown interface %s for supervisor %s", initiator.interface, supervisor_socket_path);
194 if (strnlen(initiator.extra, sizeof initiator.extra) == sizeof initiator.extra) {
195 ERROR("Bad extra of supervisor %s", supervisor_socket_path);
199 /* interprets extras */
200 if (!strcmp(initiator.extra, "CLOSE")) {
201 INFO("Supervisor asks to CLOSE");
204 if (!strcmp(initiator.extra, "WAIT")) {
205 afb_debug_wait("supervisor");
207 if (!strcmp(initiator.extra, "BREAK")) {
208 afb_debug_break("supervisor");
211 /* make the supervisor link */
212 fdev = afb_fdev_create(fd);
214 ERROR("Creation of fdev failed: %m");
217 supervisor = afb_stub_ws_create_server(fdev, supervision_apiname, supervision_apiset);
219 ERROR("Creation of supervisor failed: %m");
222 afb_stub_ws_set_on_hangup(supervisor, on_supervisor_hangup);
224 /* successful termination */
230 pthread_mutex_unlock(&mutex);
233 static void try_connect_supervisor_job(int signum, void *args)
235 INFO("Try to connect supervisor after SIGHUP");
236 try_connect_supervisor();
239 static void on_sighup(int signum)
241 INFO("Supervision received a SIGHUP");
242 jobs_queue(NULL, 0, try_connect_supervisor_job, NULL);
246 * initialize the supervision
248 int afb_supervision_init(struct afb_apiset *apiset, struct json_object *config)
254 if (supervision_apiset)
257 /* create the apiset */
258 supervision_apiset = afb_apiset_create(supervision_apiname, 0);
259 if (!supervision_apiset) {
260 ERROR("Can't create supervision's apiset");
264 /* init the apiset */
265 rc = afb_apiset_add(supervision_apiset, supervision_apiname,
266 (struct afb_api_item){ .itf = &supervision_api_itf, .closure = NULL});
268 ERROR("Can't create supervision's apiset: %m");
269 afb_apiset_unref(supervision_apiset);
270 supervision_apiset = NULL;
274 /* init the globals */
275 global.apiset = apiset;
276 global.config = config;
279 memset(&sa, 0, sizeof sa);
280 sa.sa_handler = on_sighup;
281 rc = sigaction(SIGHUP, &sa, NULL);
283 ERROR("Can't connect supervision to SIGHUP: %m");
285 /* connect to supervision */
286 try_connect_supervisor();
290 /******************************************************************************
291 **** Implementation monitoring verbs
292 ******************************************************************************/
293 static void slist(void *closure, struct afb_session *session)
295 struct json_object *list = closure;
297 json_object_object_add(list, afb_session_uuid(session), NULL);
300 /******************************************************************************
301 **** Implementation monitoring verbs
302 ******************************************************************************/
304 static const char *verbs[] = {
305 "break", "config", "do", "exit", "sclose", "slist", "trace", "wait" };
306 enum { Break , Config , Do , Exit , Sclose , Slist , Trace , Wait };
308 static void on_supervision_call(void *closure, struct afb_xreq *xreq)
311 struct json_object *args, *sub, *list;
312 const char *api, *verb, *uuid;
313 struct afb_session *session;
314 const struct afb_api_item *xapi;
317 struct json_object *drop, *add;
321 /* search the verb */
322 i = (int)(sizeof verbs / sizeof *verbs);
323 while(--i >= 0 && strcasecmp(verbs[i], xreq->request.called_verb));
325 afb_xreq_reply_unknown_verb(xreq);
330 args = afb_xreq_json(xreq);
334 if (wrap_json_unpack(args, "i", &i))
335 wrap_json_unpack(args, "{si}", "code", &i);
336 ERROR("exiting from supervision with code %d -> %d", i, i & 127);
341 if (wrap_json_unpack(args, "s", &uuid))
342 wrap_json_unpack(args, "{ss}", "uuid", &uuid);
344 afb_xreq_reply(xreq, NULL, afb_error_text_invalid_request, NULL);
346 session = afb_session_search(uuid);
348 afb_xreq_reply(xreq, NULL, afb_error_text_unknown_session, NULL);
350 afb_session_close(session);
351 afb_session_unref(session);
353 afb_xreq_reply(xreq, NULL, NULL, NULL);
358 list = json_object_new_object();
359 afb_session_foreach(slist, list);
360 afb_xreq_reply(xreq, list, NULL, NULL);
363 afb_xreq_reply(xreq, json_object_get(global.config), NULL, NULL);
366 req = xreq_to_req_x2(xreq);
369 trace = afb_trace_create(supervisor_apiname, NULL /* not bound to any session */);
372 wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
374 rc = afb_trace_add(req, add, trace);
379 rc = afb_trace_drop(req, drop, trace);
383 afb_req_success(req, NULL, NULL);
385 afb_req_reply(req, NULL, afb_error_text_not_available, NULL);
390 if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub))
391 afb_xreq_reply(xreq, NULL, afb_error_text_invalid_request, NULL);
393 xapi = afb_apiset_lookup_started(global.apiset, api, 1);
395 afb_xreq_reply_unknown_api(xreq);
397 afb_context_change_cred(&xreq->context, NULL);
398 xreq->request.called_api = api;
399 xreq->request.called_verb = verb;
400 xreq->json = json_object_get(sub);
401 xapi->itf->call(xapi->closure, xreq);
402 json_object_put(args);
407 afb_xreq_reply(xreq, NULL, NULL, NULL);
408 afb_debug_wait("supervisor");
411 afb_xreq_reply(xreq, NULL, NULL, NULL);
412 afb_debug_break("supervisor");