2 * Copyright (C) 2015-2018 "IoT.bzh"
3 * Author "Fulup Ar Foll"
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.
23 #include <sys/types.h>
26 #include <json-c/json.h>
28 #define AFB_BINDING_VERSION 3
29 #include <afb/afb-binding.h>
32 #define APINAME "hello3"
35 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
37 /**************************************************************************/
46 static struct event *events = 0;
48 /* searchs the event of tag */
49 static struct event *event_get(const char *tag)
51 struct event *e = events;
52 while(e && strcmp(e->tag, tag))
57 /* deletes the event of tag */
58 static int event_del(const char *tag)
68 while(*p != e) p = &(*p)->next;
72 afb_event_unref(e->event);
77 /* creates the event of tag */
78 static int event_add(const char *tag, const char *name)
87 e = malloc(strlen(tag) + sizeof *e);
92 e->event = afb_daemon_make_event(name);
93 if (!e->event) { free(e); return -1; }
101 static int event_subscribe(afb_req_t request, const char *tag)
105 return e ? afb_req_subscribe(request, e->event) : -1;
108 static int event_unsubscribe(afb_req_t request, const char *tag)
112 return e ? afb_req_unsubscribe(request, e->event) : -1;
115 static int event_push(struct json_object *args, const char *tag)
119 return e ? afb_event_push(e->event, json_object_get(args)) : -1;
122 static int event_broadcast(struct json_object *args, const char *tag)
126 return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
129 /**************************************************************************/
138 static struct api *apis = 0;
140 /* search the api of name */
141 static struct api *searchapi(const char *name, struct api ***previous)
143 struct api *a, **p = &apis;
144 while((a = *p) && strcmp(a->name, name))
151 /**************************************************************************/
153 // Sample Generic Ping Debug API
154 static void ping(afb_req_t request, json_object *jresp, const char *tag)
156 static int pingcount = 0;
157 json_object *query = afb_req_json(request);
158 afb_req_success_f(request, jresp, "Ping Binder Daemon tag=%s count=%d query=%s", tag, ++pingcount, json_object_to_json_string(query));
161 static void pingSample (afb_req_t request)
163 ping(request, json_object_new_string ("Some String"), "pingSample");
166 static void pingFail (afb_req_t request)
168 afb_req_fail(request, "failed", "Ping Binder Daemon fails");
171 static void pingNull (afb_req_t request)
173 ping(request, NULL, "pingNull");
176 static void pingBug (afb_req_t request)
178 ping(NULL, NULL, "pingBug");
181 static void pingEvent(afb_req_t request)
183 json_object *query = afb_req_json(request);
184 afb_daemon_broadcast_event("event", json_object_get(query));
185 ping(request, json_object_get(query), "event");
189 // For samples https://linuxprograms.wordpress.com/2010/05/20/json-c-libjson-tutorial/
190 static void pingJson (afb_req_t request) {
191 json_object *jresp, *embed;
193 jresp = json_object_new_object();
194 json_object_object_add(jresp, "myString", json_object_new_string ("Some String"));
195 json_object_object_add(jresp, "myInt", json_object_new_int (1234));
197 embed = json_object_new_object();
198 json_object_object_add(embed, "subObjString", json_object_new_string ("Some String"));
199 json_object_object_add(embed, "subObjInt", json_object_new_int (5678));
201 json_object_object_add(jresp,"eobj", embed);
203 ping(request, jresp, "pingJson");
206 static void subcallcb (void *prequest, int status, json_object *object, afb_req_t request)
209 afb_req_fail(request, "failed", json_object_to_json_string(object));
211 afb_req_success(request, json_object_get(object), NULL);
214 static void subcall (afb_req_t request)
216 const char *api = afb_req_value(request, "api");
217 const char *verb = afb_req_value(request, "verb");
218 const char *args = afb_req_value(request, "args");
219 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
222 afb_req_fail(request, "failed", "bad arguments");
224 afb_req_subcall_legacy(request, api, verb, object, subcallcb, NULL);
227 static void subcallreqcb (void *prequest, int status, json_object *object, afb_req_t request)
230 afb_req_fail(request, "failed", json_object_to_json_string(object));
232 afb_req_success(request, json_object_get(object), NULL);
235 static void subcallreq (afb_req_t request)
237 const char *api = afb_req_value(request, "api");
238 const char *verb = afb_req_value(request, "verb");
239 const char *args = afb_req_value(request, "args");
240 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
243 afb_req_fail(request, "failed", "bad arguments");
245 afb_req_subcall_legacy(request, api, verb, object, subcallreqcb, NULL);
248 static void subcallsync (afb_req_t request)
251 const char *api = afb_req_value(request, "api");
252 const char *verb = afb_req_value(request, "verb");
253 const char *args = afb_req_value(request, "args");
254 json_object *result, *object = api && verb && args ? json_tokener_parse(args) : NULL;
257 afb_req_fail(request, "failed", "bad arguments");
259 rc = afb_req_subcall_sync_legacy(request, api, verb, object, &result);
261 afb_req_success(request, result, NULL);
263 afb_req_fail(request, "failed", json_object_to_json_string(result));
264 json_object_put(result);
269 static void eventadd (afb_req_t request)
271 const char *tag = afb_req_value(request, "tag");
272 const char *name = afb_req_value(request, "name");
274 pthread_mutex_lock(&mutex);
275 if (tag == NULL || name == NULL)
276 afb_req_fail(request, "failed", "bad arguments");
277 else if (0 != event_add(tag, name))
278 afb_req_fail(request, "failed", "creation error");
280 afb_req_success(request, NULL, NULL);
281 pthread_mutex_unlock(&mutex);
284 static void eventdel (afb_req_t request)
286 const char *tag = afb_req_value(request, "tag");
288 pthread_mutex_lock(&mutex);
290 afb_req_fail(request, "failed", "bad arguments");
291 else if (0 != event_del(tag))
292 afb_req_fail(request, "failed", "deletion error");
294 afb_req_success(request, NULL, NULL);
295 pthread_mutex_unlock(&mutex);
298 static void eventsub (afb_req_t request)
300 const char *tag = afb_req_value(request, "tag");
302 pthread_mutex_lock(&mutex);
304 afb_req_fail(request, "failed", "bad arguments");
305 else if (0 != event_subscribe(request, tag))
306 afb_req_fail(request, "failed", "subscription error");
308 afb_req_success(request, NULL, NULL);
309 pthread_mutex_unlock(&mutex);
312 static void eventunsub (afb_req_t request)
314 const char *tag = afb_req_value(request, "tag");
316 pthread_mutex_lock(&mutex);
318 afb_req_fail(request, "failed", "bad arguments");
319 else if (0 != event_unsubscribe(request, tag))
320 afb_req_fail(request, "failed", "unsubscription error");
322 afb_req_success(request, NULL, NULL);
323 pthread_mutex_unlock(&mutex);
326 static void eventpush (afb_req_t request)
328 const char *tag = afb_req_value(request, "tag");
329 const char *data = afb_req_value(request, "data");
330 json_object *object = data ? json_tokener_parse(data) : NULL;
332 pthread_mutex_lock(&mutex);
334 afb_req_fail(request, "failed", "bad arguments");
335 else if (0 > event_push(object, tag))
336 afb_req_fail(request, "failed", "push error");
338 afb_req_success(request, NULL, NULL);
339 pthread_mutex_unlock(&mutex);
340 json_object_put(object);
343 static void callcb (void *prequest, json_object *object, const char *error, const char *info, afb_api_t api)
345 afb_req_t request = prequest;
346 afb_req_reply(request, json_object_get(object), error, info);
347 afb_req_unref(request);
350 static void call (afb_req_t request)
352 const char *api = afb_req_value(request, "api");
353 const char *verb = afb_req_value(request, "verb");
354 const char *args = afb_req_value(request, "args");
355 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
357 afb_service_call(api, verb, object, callcb, afb_req_addref(request));
360 static void callsync (afb_req_t request)
362 const char *api = afb_req_value(request, "api");
363 const char *verb = afb_req_value(request, "verb");
364 const char *args = afb_req_value(request, "args");
365 json_object *object = api && verb && args ? json_tokener_parse(args) : NULL;
369 afb_service_call_sync(api, verb, object, &result, &error, &info);
370 afb_req_reply(request, result, error, info);
375 static void verbose (afb_req_t request)
378 json_object *query = afb_req_json(request), *l;
380 if (json_object_is_type(query,json_type_int))
381 level = json_object_get_int(query);
382 else if (json_object_object_get_ex(query, "level", &l) && json_object_is_type(l, json_type_int))
383 level = json_object_get_int(l);
385 if (!json_object_object_get_ex(query,"message",&l))
388 AFB_REQ_VERBOSE(request, level, "verbose called for %s", json_object_get_string(l));
389 afb_req_success(request, NULL, NULL);
392 static void exitnow (afb_req_t request)
395 json_object *query = afb_req_json(request), *l;
397 if (json_object_is_type(query,json_type_int))
398 code = json_object_get_int(query);
399 else if (json_object_object_get_ex(query, "code", &l) && json_object_is_type(l, json_type_int))
400 code = json_object_get_int(l);
402 if (!json_object_object_get_ex(query,"reason",&l))
405 AFB_REQ_NOTICE(request, "in phase of exiting with code %d, reason: %s", code, l ? json_object_get_string(l) : "unknown");
406 afb_req_success(request, NULL, NULL);
410 static void broadcast(afb_req_t request)
412 const char *tag = afb_req_value(request, "tag");
413 const char *name = afb_req_value(request, "name");
414 const char *data = afb_req_value(request, "data");
415 json_object *object = data ? json_tokener_parse(data) : NULL;
418 pthread_mutex_lock(&mutex);
419 if (0 > event_broadcast(object, tag))
420 afb_req_fail(request, "failed", "broadcast error");
422 afb_req_success(request, NULL, NULL);
423 pthread_mutex_unlock(&mutex);
424 } else if (name != NULL) {
425 if (0 > afb_daemon_broadcast_event(name, object))
426 afb_req_fail(request, "failed", "broadcast error");
428 afb_req_success(request, NULL, NULL);
430 afb_req_fail(request, "failed", "bad arguments");
432 json_object_put(object);
435 static void hasperm (afb_req_t request)
437 const char *perm = afb_req_value(request, "perm");
438 if (afb_req_has_permission(request, perm))
439 afb_req_success_f(request, NULL, "permission %s granted", perm?:"(null)");
441 afb_req_fail_f(request, "not-granted", "permission %s NOT granted", perm?:"(null)");
444 static void appid (afb_req_t request)
446 char *aid = afb_req_get_application_id(request);
447 afb_req_success_f(request, aid ? json_object_new_string(aid) : NULL, "application is %s", aid?:"?");
451 static void uid (afb_req_t request)
453 int uid = afb_req_get_uid(request);
454 afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
457 static void closess (afb_req_t request)
459 afb_req_session_close(request);
460 afb_req_reply(request, NULL, NULL, "session closed");
463 static void setloa (afb_req_t request)
465 int loa = json_object_get_int(afb_req_json(request));
466 afb_req_session_set_LOA(request, loa);
467 afb_req_reply_f(request, NULL, NULL, "LOA set to %d", loa);
470 static void ok (afb_req_t request)
472 afb_req_reply_f(request, NULL, NULL, NULL);
475 static void setctx (afb_req_t request)
477 struct json_object *x = afb_req_json(request);
478 afb_req_context(request, (int)(intptr_t)afb_req_get_vcbdata(request), (void*)json_object_get, (void*)json_object_put, x);
479 afb_req_reply(request, json_object_get(x), NULL, "context set");
482 static void getctx (afb_req_t request)
484 struct json_object *x = afb_req_context(request, 0, 0, 0, 0);
485 afb_req_reply(request, json_object_get(x), NULL, "returning the context");
488 static void info (afb_req_t request)
490 afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
493 static void eventloop (afb_req_t request)
495 afb_api_t api = afb_req_get_api(request);
496 struct sd_event *ev = afb_api_get_event_loop(api);
497 afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
500 static void dbus (afb_req_t request)
502 afb_api_t api = afb_req_get_api(request);
503 json_object *json = afb_req_json(request);
504 struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
505 afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
508 static void replycount (afb_req_t request)
510 json_object *json = afb_req_json(request);
511 int count = json_object_get_int(json);
513 afb_req_reply(request, NULL, NULL, NULL);
516 static void get(afb_req_t request)
518 struct afb_arg arg = afb_req_get(request, "name");
519 const char *name, *value, *path;
521 if (!arg.name || !arg.value)
522 afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
525 value = afb_req_value(request, name);
526 path = afb_req_path(request, name);
527 afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
531 static void ref(afb_req_t request)
533 afb_req_addref(request);
534 afb_req_reply(request, NULL, NULL, NULL);
535 afb_req_unref(request);
538 static void mute(afb_req_t request)
542 static void mutebug(afb_req_t request)
544 afb_req_addref(request);
547 void queue_cb(int signum, void *arg)
549 afb_req_t request = arg;
550 afb_req_reply(request, NULL, NULL, NULL);
551 afb_req_unref(request);
554 static void queue(afb_req_t request)
556 afb_req_addref(request);
557 afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
560 static void settings(afb_req_t request)
562 afb_api_t api = afb_req_get_api(request);
563 struct json_object *object = afb_api_settings(api);
564 afb_req_reply(request, json_object_get(object), NULL, NULL);
567 static void rootdir (afb_req_t request)
570 afb_api_t api = afb_req_get_api(request);
571 int fd = afb_api_rootdir_get_fd(api);
572 char buffer[150], root[1025];
573 sprintf(buffer, "/proc/self/fd/%d", fd);
574 s = readlink(buffer, root, sizeof root - 1);
576 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
579 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
583 static void locale (afb_req_t request)
585 char buffer[150], root[1025];
586 const char *lang, *file;
588 json_object *json = afb_req_json(request), *x;
589 afb_api_t api = afb_req_get_api(request);
593 if (json_object_is_type(json, json_type_string))
594 file = json_object_get_string(json);
596 if (!json_object_object_get_ex(json, "file", &x)) {
597 afb_req_reply(request, NULL, "invalid", "no file");
600 file = json_object_get_string(x);
601 if (json_object_object_get_ex(json, "lang", &x))
602 lang = json_object_get_string(x);
605 fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
607 afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
609 sprintf(buffer, "/proc/self/fd/%d", fd);
610 s = readlink(buffer, root, sizeof root - 1);
612 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
615 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
621 static void api (afb_req_t request);
624 * Definition of an authorization entry
626 static struct afb_auth auths[] = {
633 .type = afb_auth_And,
641 .type = afb_auth_And,
646 .type = afb_auth_LOA,
658 .type = afb_auth_Not,
665 .type = afb_auth_And,
675 .type = afb_auth_Not,
679 .type = afb_auth_Token
682 .type = afb_auth_And,
692 .type = afb_auth_Not,
696 .type = afb_auth_Permission,
705 // NOTE: this sample does not use session to keep test a basic as possible
706 // in real application most APIs should be protected with AFB_SESSION_CHECK
707 static const struct afb_verb_v3 verbs[]= {
708 { .verb="ping", .callback=pingSample },
709 { .verb="pingfail", .callback=pingFail },
710 { .verb="pingnull", .callback=pingNull },
711 { .verb="pingbug", .callback=pingBug },
712 { .verb="pingJson", .callback=pingJson },
713 { .verb="pingevent", .callback=pingEvent },
714 { .verb="subcall", .callback=subcall },
715 { .verb="subcallreq", .callback=subcallreq },
716 { .verb="subcallsync", .callback=subcallsync },
717 { .verb="eventadd", .callback=eventadd },
718 { .verb="eventdel", .callback=eventdel },
719 { .verb="eventsub", .callback=eventsub },
720 { .verb="eventunsub", .callback=eventunsub },
721 { .verb="eventpush", .callback=eventpush },
722 { .verb="call", .callback=call },
723 { .verb="callsync", .callback=callsync },
724 { .verb="verbose", .callback=verbose },
725 { .verb="broadcast", .callback=broadcast },
726 { .verb="hasperm", .callback=hasperm },
727 { .verb="appid", .callback=appid },
728 { .verb="uid", .callback=uid },
729 { .verb="exit", .callback=exitnow },
730 { .verb="close", .callback=closess, .session=AFB_SESSION_CLOSE },
731 { .verb="set-loa", .callback=setloa, .auth = &auths[0] },
732 { .verb="has-loa-1", .callback=ok, .session=AFB_SESSION_LOA_1 },
733 { .verb="has-loa-2", .callback=ok, .session=AFB_SESSION_LOA_2 },
734 { .verb="has-loa-3", .callback=ok, .session=AFB_SESSION_LOA_3 },
735 { .verb="setctx", .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
736 { .verb="setctxif", .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
737 { .verb="getctx", .callback=getctx },
738 { .verb="reftok", .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
739 { .verb="info", .callback=info },
740 { .verb="eventloop", .callback=eventloop },
741 { .verb="dbus", .callback=dbus },
742 { .verb="reply-count", .callback=replycount },
743 { .verb="get", .callback=get},
744 { .verb="ref", .callback=ref},
745 { .verb="rootdir", .callback=rootdir},
746 { .verb="locale", .callback=locale},
747 { .verb="api", .callback=api},
748 { .verb="mute", .callback=mute},
749 { .verb="mutebug", .callback=mutebug},
750 { .verb="queue", .callback=queue},
751 { .verb="settings", .callback=settings},
755 static void pingSample2 (struct afb_req_x1 req)
757 pingSample(req.closure);
760 static const struct afb_verb_v2 apiverbs2[]= {
761 { .verb="ping", .callback=pingSample2 },
762 { .verb="ping2", .callback=pingSample2 },
766 static int apipreinit(void *closure, afb_api_t api)
768 afb_api_set_verbs_v2(api, apiverbs2);
769 afb_api_set_verbs_v3(api, verbs);
773 static void apiverb (afb_req_t request)
775 afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
776 afb_req_get_called_api(request), afb_req_get_called_verb(request));
779 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
781 struct json_object *obj = closure;
782 afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
783 json_object_get_string(obj), event, json_object_get_string(args));
786 static void api (afb_req_t request)
788 struct api *sapi, **psapi;
789 const char *action, *apiname, *verbname, *pattern;
790 json_object *json = afb_req_json(request), *x, *closure;
791 afb_api_t api = afb_req_get_api(request), oapi;
794 if (!json_object_object_get_ex(json, "action", &x)) {
795 afb_req_reply(request, NULL, "invalid", "no action");
798 action = json_object_get_string(x);
801 verbname = json_object_object_get_ex(json, "verb", &x) ?
802 json_object_get_string(x) : NULL;
804 /* get the pattern */
805 pattern = json_object_object_get_ex(json, "pattern", &x) ?
806 json_object_get_string(x) : NULL;
808 /* get the closure */
810 json_object_object_get_ex(json, "closure", &closure);
813 if (json_object_object_get_ex(json, "api", &x)) {
814 apiname = json_object_get_string(x);
815 sapi = searchapi(apiname, &psapi);
816 oapi = sapi ? sapi->api : NULL;
819 apiname = afb_api_name(api);
820 sapi = searchapi(apiname, &psapi);
823 /* search the sapi */
824 if (!strcasecmp(action, "create")) {
826 afb_req_reply(request, NULL, "invalid", "no api");
830 afb_req_reply(request, NULL, "already-exist", NULL);
833 sapi = malloc (sizeof * sapi + strlen(apiname));
835 afb_req_reply(request, NULL, "out-of-memory", NULL);
838 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
840 afb_req_reply_f(request, NULL, "cant-create", "%m");
843 strcpy(sapi->name, apiname);
848 afb_req_reply(request, NULL, "cant-find-api", NULL);
851 if (!strcasecmp(action, "destroy")) {
853 afb_req_reply(request, NULL, "cant-destroy", NULL);
856 afb_api_delete_api(oapi);
859 } else if (!strcasecmp(action, "addverb")) {
861 afb_req_reply(request, NULL, "invalid", "no verb");
864 afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
865 } else if (!strcasecmp(action, "delverb")) {
867 afb_req_reply(request, NULL, "invalid", "no verb");
870 afb_api_del_verb(oapi, verbname, NULL);
871 } else if (!strcasecmp(action, "addhandler")) {
873 afb_req_reply(request, NULL, "invalid", "no pattern");
876 afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
877 } else if (!strcasecmp(action, "delhandler")) {
879 afb_req_reply(request, NULL, "invalid", "no pattern");
883 afb_api_event_handler_del(oapi, pattern, (void**)&closure);
884 json_object_put(closure);
885 } else if (!strcasecmp(action, "seal")) {
888 afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
892 afb_req_reply(request, NULL, NULL, NULL);
896 /*************************************************************/
898 static int preinit(afb_api_t api)
900 AFB_NOTICE("hello binding comes to live");
901 #if defined(PREINIT_PROVIDE_CLASS)
902 afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
904 #if defined(PREINIT_REQUIRE_CLASS)
905 afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
910 static int init(afb_api_t api)
912 AFB_NOTICE("hello binding starting");
913 #if defined(INIT_REQUIRE_API)
914 afb_api_require_api(api, INIT_REQUIRE_API, 1);
916 afb_api_add_alias(api, api->apiname, "fakename");
920 static void onevent(afb_api_t api, const char *event, struct json_object *object)
922 AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
925 const struct afb_binding_v3 afbBindingV3 = {
927 .specification = NULL,