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 setctx (afb_req_t request)
472 struct json_object *x = afb_req_json(request);
473 afb_req_context(request, (int)(intptr_t)afb_req_get_vcbdata(request), (void*)json_object_get, (void*)json_object_put, x);
474 afb_req_reply(request, json_object_get(x), NULL, "context set");
477 static void getctx (afb_req_t request)
479 struct json_object *x = afb_req_context(request, 0, 0, 0, 0);
480 afb_req_reply(request, json_object_get(x), NULL, "returning the context");
483 static void info (afb_req_t request)
485 afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
488 static void eventloop (afb_req_t request)
490 afb_api_t api = afb_req_get_api(request);
491 struct sd_event *ev = afb_api_get_event_loop(api);
492 afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
495 static void dbus (afb_req_t request)
497 afb_api_t api = afb_req_get_api(request);
498 json_object *json = afb_req_json(request);
499 struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
500 afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
503 static void replycount (afb_req_t request)
505 json_object *json = afb_req_json(request);
506 int count = json_object_get_int(json);
508 afb_req_reply(request, NULL, NULL, NULL);
511 static void get(afb_req_t request)
513 struct afb_arg arg = afb_req_get(request, "name");
514 const char *name, *value, *path;
516 if (!arg.name || !arg.value)
517 afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
520 value = afb_req_value(request, name);
521 path = afb_req_path(request, name);
522 afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
526 static void ref(afb_req_t request)
528 afb_req_addref(request);
529 afb_req_reply(request, NULL, NULL, NULL);
530 afb_req_unref(request);
533 static void rootdir (afb_req_t request)
536 afb_api_t api = afb_req_get_api(request);
537 int fd = afb_api_rootdir_get_fd(api);
538 char buffer[150], root[1025];
539 sprintf(buffer, "/proc/self/fd/%d", fd);
540 s = readlink(buffer, root, sizeof root - 1);
542 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
545 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
549 static void locale (afb_req_t request)
551 char buffer[150], root[1025];
552 const char *lang, *file;
554 json_object *json = afb_req_json(request), *x;
555 afb_api_t api = afb_req_get_api(request);
559 if (json_object_is_type(json, json_type_string))
560 file = json_object_get_string(json);
562 if (!json_object_object_get_ex(json, "file", &x)) {
563 afb_req_reply(request, NULL, "invalid", "no file");
566 file = json_object_get_string(x);
567 if (json_object_object_get_ex(json, "lang", &x))
568 lang = json_object_get_string(x);
571 fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
573 afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
575 sprintf(buffer, "/proc/self/fd/%d", fd);
576 s = readlink(buffer, root, sizeof root - 1);
578 afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
581 afb_req_reply(request, json_object_new_string(root), NULL, NULL);
587 static void api (afb_req_t request);
589 // NOTE: this sample does not use session to keep test a basic as possible
590 // in real application most APIs should be protected with AFB_SESSION_CHECK
591 static const struct afb_verb_v3 verbs[]= {
592 { .verb="ping", .callback=pingSample },
593 { .verb="pingfail", .callback=pingFail },
594 { .verb="pingnull", .callback=pingNull },
595 { .verb="pingbug", .callback=pingBug },
596 { .verb="pingJson", .callback=pingJson },
597 { .verb="pingevent", .callback=pingEvent },
598 { .verb="subcall", .callback=subcall },
599 { .verb="subcallreq", .callback=subcallreq },
600 { .verb="subcallsync", .callback=subcallsync },
601 { .verb="eventadd", .callback=eventadd },
602 { .verb="eventdel", .callback=eventdel },
603 { .verb="eventsub", .callback=eventsub },
604 { .verb="eventunsub", .callback=eventunsub },
605 { .verb="eventpush", .callback=eventpush },
606 { .verb="call", .callback=call },
607 { .verb="callsync", .callback=callsync },
608 { .verb="verbose", .callback=verbose },
609 { .verb="broadcast", .callback=broadcast },
610 { .verb="hasperm", .callback=hasperm },
611 { .verb="appid", .callback=appid },
612 { .verb="uid", .callback=uid },
613 { .verb="exit", .callback=exitnow },
614 { .verb="close", .callback=closess },
615 { .verb="set-loa", .callback=setloa },
616 { .verb="setctx", .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
617 { .verb="setctxif", .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
618 { .verb="getctx", .callback=getctx },
619 { .verb="info", .callback=info },
620 { .verb="eventloop", .callback=eventloop },
621 { .verb="dbus", .callback=dbus },
622 { .verb="reply-count", .callback=replycount },
623 { .verb="get", .callback=get},
624 { .verb="ref", .callback=ref},
625 { .verb="rootdir", .callback=rootdir},
626 { .verb="locale", .callback=locale},
627 { .verb="api", .callback=api},
631 static void pingSample2 (struct afb_req_x1 req)
633 pingSample(req.closure);
636 static const struct afb_verb_v2 apiverbs2[]= {
637 { .verb="ping", .callback=pingSample2 },
638 { .verb="ping2", .callback=pingSample2 },
642 static int apipreinit(void *closure, afb_api_t api)
644 afb_api_set_verbs_v2(api, apiverbs2);
645 afb_api_set_verbs_v3(api, verbs);
649 static void apiverb (afb_req_t request)
651 afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
652 afb_req_get_called_api(request), afb_req_get_called_verb(request));
655 static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
657 struct json_object *obj = closure;
658 afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
659 json_object_get_string(obj), event, json_object_get_string(args));
662 static void api (afb_req_t request)
664 struct api *sapi, **psapi;
665 const char *action, *apiname, *verbname, *pattern;
666 json_object *json = afb_req_json(request), *x, *closure;
667 afb_api_t api = afb_req_get_api(request), oapi;
670 if (!json_object_object_get_ex(json, "action", &x)) {
671 afb_req_reply(request, NULL, "invalid", "no action");
674 action = json_object_get_string(x);
677 verbname = json_object_object_get_ex(json, "verb", &x) ?
678 json_object_get_string(x) : NULL;
680 /* get the pattern */
681 pattern = json_object_object_get_ex(json, "pattern", &x) ?
682 json_object_get_string(x) : NULL;
684 /* get the closure */
686 json_object_object_get_ex(json, "closure", &closure);
689 if (json_object_object_get_ex(json, "api", &x)) {
690 apiname = json_object_get_string(x);
691 sapi = searchapi(apiname, &psapi);
692 oapi = sapi ? sapi->api : NULL;
695 apiname = afb_api_name(api);
696 sapi = searchapi(apiname, &psapi);
699 /* search the sapi */
700 if (!strcasecmp(action, "create")) {
702 afb_req_reply(request, NULL, "invalid", "no api");
706 afb_req_reply(request, NULL, "already-exist", NULL);
709 sapi = malloc (sizeof * sapi + strlen(apiname));
711 afb_req_reply(request, NULL, "out-of-memory", NULL);
714 sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
716 afb_req_reply_f(request, NULL, "cant-create", "%m");
719 strcpy(sapi->name, apiname);
724 afb_req_reply(request, NULL, "cant-find-api", NULL);
727 if (!strcasecmp(action, "destroy")) {
729 afb_req_reply(request, NULL, "cant-destroy", NULL);
732 afb_api_delete_api(oapi);
735 } else if (!strcasecmp(action, "addverb")) {
737 afb_req_reply(request, NULL, "invalid", "no verb");
740 afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
741 } else if (!strcasecmp(action, "delverb")) {
743 afb_req_reply(request, NULL, "invalid", "no verb");
746 afb_api_del_verb(oapi, verbname, NULL);
747 } else if (!strcasecmp(action, "addhandler")) {
749 afb_req_reply(request, NULL, "invalid", "no pattern");
752 afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
753 } else if (!strcasecmp(action, "delhandler")) {
755 afb_req_reply(request, NULL, "invalid", "no pattern");
759 afb_api_event_handler_del(oapi, pattern, (void**)&closure);
760 json_object_put(closure);
761 } else if (!strcasecmp(action, "seal")) {
764 afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
768 afb_req_reply(request, NULL, NULL, NULL);
772 /*************************************************************/
774 static int preinit(afb_api_t api)
776 AFB_NOTICE("hello binding comes to live");
777 #if defined(PREINIT_PROVIDE_CLASS)
778 afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
780 #if defined(PREINIT_REQUIRE_CLASS)
781 afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
786 static int init(afb_api_t api)
788 AFB_NOTICE("hello binding starting");
789 #if defined(INIT_REQUIRE_API)
790 afb_api_require_api(api, INIT_REQUIRE_API, 1);
792 afb_api_add_alias(api, api->apiname, "fakename");
796 static void onevent(afb_api_t api, const char *event, struct json_object *object)
798 AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
801 const struct afb_binding_v3 afbBindingV3 = {
803 .specification = NULL,