2 * Copyright (C) 2016, 2017 "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.
19 #define AFB_BINDING_PRAGMA_NO_VERBOSE_MACRO
27 #include <sys/types.h>
28 #include <sys/socket.h>
31 #include <json-c/json.h>
32 #include <afb/afb-binding-v2.h>
36 #include "afb-apiset.h"
37 #include "afb-api-so-v2.h"
39 #include "afb-trace.h"
40 #include "afb-session.h"
41 #include "afb-supervision.h"
42 #include "afs-supervision.h"
43 #include "afb-stub-ws.h"
44 #include "afb-debug.h"
46 #include "wrap-json.h"
48 /* api and apiset name */
49 static const char supervision_apiname[] = AFS_SURPERVISION_APINAME;
51 /* path of the supervision socket */
52 static const char supervisor_socket_path[] = AFS_SURPERVISION_SOCKET;
54 /* mutual exclusion */
55 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
57 /* the standard apiset */
58 extern struct afb_apiset *main_apiset;
60 /* the supervision apiset (not exported) */
61 static struct afb_apiset *supervision_apiset;
63 /* local api implementation */
64 static void on_supervision_call(void *closure, struct afb_xreq *xreq);
65 static struct afb_api_itf supervision_api_itf =
67 .call = on_supervision_call
70 /* the supervisor link */
71 static struct afb_stub_ws *supervisor;
74 static struct afb_trace *trace;
77 static int open_supervisor_socket(const char *path)
80 struct sockaddr_un addr;
83 /* check path length */
84 length = strlen(path);
90 /* create the unix socket */
91 fd = socket(AF_UNIX, SOCK_STREAM, 0);
95 /* prepare the connection address */
96 memset(&addr, 0, sizeof addr);
97 addr.sun_family = AF_UNIX;
98 strcpy(addr.sun_path, path);
99 if (addr.sun_path[0] == '@')
100 addr.sun_path[0] = 0; /* implement abstract sockets */
102 /* connect the socket */
103 rc = connect(fd, (struct sockaddr *) &addr, (socklen_t)(sizeof addr));
111 static void cleanup_supervisor(void *nada)
113 struct afb_trace *t = __atomic_exchange_n(&trace, NULL, __ATOMIC_RELAXED);
119 static void disconnect_supervisor()
121 struct afb_stub_ws *s = __atomic_exchange_n(&supervisor, NULL, __ATOMIC_RELAXED);
124 afb_stub_ws_unref(s);
127 /* try to connect to supervisor */
128 static void try_connect_supervisor()
132 struct afs_supervision_initiator initiator;
135 pthread_mutex_lock(&mutex);
137 /* needs to connect? */
138 if (supervisor || !supervision_apiset)
141 /* check existing path */
142 if (supervisor_socket_path[0] != '@' && access(supervisor_socket_path, F_OK)) {
143 NOTICE("Can't acces socket path %s: %m", supervisor_socket_path);
147 /* socket connection */
148 fd = open_supervisor_socket(supervisor_socket_path);
150 NOTICE("Can't connect supervision socket to %s: %m", supervisor_socket_path);
155 do { srd = read(fd, &initiator, sizeof initiator); } while(srd < 0 && errno == EINTR);
157 NOTICE("Can't read supervisor %s: %m", supervisor_socket_path);
160 if ((size_t)srd != sizeof initiator) {
161 ERROR("When reading supervisor %s: %m", supervisor_socket_path);
164 if (strnlen(initiator.interface, sizeof initiator.interface) == sizeof initiator.interface) {
165 ERROR("Bad interface of supervisor %s", supervisor_socket_path);
168 if (strcmp(initiator.interface, AFS_SURPERVISION_INTERFACE_1)) {
169 ERROR("Unknown interface %s for supervisor %s", initiator.interface, supervisor_socket_path);
172 if (strnlen(initiator.extra, sizeof initiator.extra) == sizeof initiator.extra) {
173 ERROR("Bad extra of supervisor %s", supervisor_socket_path);
177 /* interprets extras */
178 if (!strcmp(initiator.extra, "CLOSE")) {
179 INFO("Supervisor asks to CLOSE");
182 if (!strcmp(initiator.extra, "WAIT")) {
183 afb_debug_wait("supervisor");
185 if (!strcmp(initiator.extra, "BREAK")) {
186 afb_debug_break("supervisor");
189 /* make the supervisor link */
190 supervisor = afb_stub_ws_create_server(fd, supervision_apiname, supervision_apiset);
192 ERROR("Creation of supervisor failed: %m");
196 /* successful termination */
202 pthread_mutex_unlock(&mutex);
205 static void on_sighup(int signum)
207 try_connect_supervisor();
211 * initalize the supervision
213 int afb_supervision_init()
219 if (supervision_apiset)
222 /* create the apiset */
223 supervision_apiset = afb_apiset_create(supervision_apiname, 0);
224 if (!supervision_apiset) {
225 ERROR("Can't create supervision's apiset");
229 /* init the apiset */
230 rc = afb_apiset_add(supervision_apiset, supervision_apiname,
231 (struct afb_api){ .itf = &supervision_api_itf, .closure = NULL});
233 ERROR("Can't create supervision's apiset: %m");
234 afb_apiset_unref(supervision_apiset);
235 supervision_apiset = NULL;
240 memset(&sa, 0, sizeof sa);
241 sa.sa_handler = on_sighup;
242 rc = sigaction(SIGHUP, &sa, NULL);
244 ERROR("Can't connect supervision to SIGHUP: %m");
246 /* connect to supervision */
247 try_connect_supervisor();
251 /******************************************************************************
252 **** Implementation monitoring verbs
253 ******************************************************************************/
254 static void slist(void *closure, struct afb_session *session)
256 struct json_object *list = closure;
257 struct json_object *item;
259 wrap_json_pack(&item, "{ss}", "token", afb_session_token(session));
260 json_object_object_add(list, afb_session_uuid(session), item);
263 /******************************************************************************
264 **** Implementation monitoring verbs
265 ******************************************************************************/
267 static const char *verbs[] = {
268 "break", "do", "exit", "sclose", "slist", "trace", "wait" };
269 enum { Break , Do , Exit , Sclose , Slist , Trace , Wait };
272 static void on_supervision_call(void *closure, struct afb_xreq *xreq)
275 struct json_object *args, *drop, *add, *sub, *list;
276 const char *api, *verb, *uuid;
277 struct afb_session *session;
278 const struct afb_api *xapi;
281 /* search the verb */
282 i = (int)(sizeof verbs / sizeof *verbs);
283 while(--i >= 0 && strcasecmp(verbs[i], xreq->request.verb));
285 afb_xreq_fail_unknown_verb(xreq);
290 args = afb_xreq_json(xreq);
294 if (wrap_json_unpack(args, "i", &i))
295 wrap_json_unpack(args, "{si}", "code", &i);
296 ERROR("existing from supervision with code %d -> %d", i, i & 127);
301 if (wrap_json_unpack(args, "s", &uuid))
302 wrap_json_unpack(args, "{ss}", "uuid", &uuid);
304 afb_xreq_fail(xreq, "invalid", NULL);
306 session = afb_session_search(uuid);
308 afb_xreq_fail(xreq, "not-found", NULL);
310 afb_session_close(session);
311 afb_session_unref(session);
313 afb_xreq_success(xreq, NULL, NULL);
318 list = json_object_new_object();
319 afb_session_foreach(slist, list);
320 afb_xreq_success(xreq, list, NULL);
324 trace = afb_trace_create(supervision_apiname, NULL /* not bound to any session */);
326 req = afb_xreq_unstore((struct afb_stored_req*)xreq);
327 wrap_json_unpack(args, "{s?o s?o}", "add", &add, "drop", &drop);
329 rc = afb_trace_add(req, add, trace);
334 rc = afb_trace_drop(req, drop, trace);
338 afb_req_success(req, NULL, NULL);
342 if (wrap_json_unpack(args, "{ss ss s?o*}", "api", &api, "verb", &verb, "args", &sub))
343 afb_xreq_fail(xreq, "error", "bad request");
345 xapi = afb_apiset_lookup_started(main_apiset, api, 1);
347 afb_xreq_fail_unknown_api(xreq);
349 afb_cred_unref(xreq->cred);
351 xreq->request.api = api;
352 xreq->request.verb = verb;
353 xreq->json = json_object_get(sub);
354 xapi->itf->call(xapi->closure, xreq);
355 json_object_put(args);
360 afb_req_success(req, NULL, NULL);
361 afb_debug_wait("supervisor");
364 afb_req_success(req, NULL, NULL);
365 afb_debug_break("supervisor");