#include <stdio.h>
#include <string.h>
#include <pthread.h>
+#include <fcntl.h>
+#include <math.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
#include <json-c/json.h>
#define AFB_BINDING_VERSION 3
#include <afb/afb-binding.h>
+#if !defined(APINAME)
+#define APINAME "hello"
+#endif
+
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+/**************************************************************************/
+
struct event
{
struct event *next;
return e ? afb_event_broadcast(e->event, json_object_get(args)) : -1;
}
+/**************************************************************************/
+
+struct api
+{
+ struct api *next;
+ afb_api_t api;
+ char name[1];
+};
+
+static struct api *apis = 0;
+
+/* search the api of name */
+static struct api *searchapi(const char *name, struct api ***previous)
+{
+ struct api *a, **p = &apis;
+ while((a = *p) && strcmp(a->name, name))
+ p = &a->next;
+ if (previous)
+ *previous = p;
+ return a;
+}
+
+/**************************************************************************/
+
// Sample Generic Ping Debug API
static void ping(afb_req_t request, json_object *jresp, const char *tag)
{
afb_req_fail(request, "failed", json_object_to_json_string(object));
else
afb_req_success(request, json_object_get(object), NULL);
- afb_req_unref(request);
}
static void subcall (afb_req_t request)
afb_req_success(request, NULL, NULL);
pthread_mutex_unlock(&mutex);
} else if (name != NULL) {
- if (0 > afb_daemon_broadcast_event(name, object))
+ if (0 > afb_daemon_broadcast_event(name, json_object_get(object)))
afb_req_fail(request, "failed", "broadcast error");
else
afb_req_success(request, NULL, NULL);
afb_req_success_f(request, json_object_new_int(uid), "uid is %d", uid);
}
-static int preinit(afb_api_t api)
+static void closess (afb_req_t request)
{
- AFB_NOTICE("hello binding comes to live");
- return 0;
+ afb_req_session_close(request);
+ afb_req_reply(request, NULL, NULL, "session closed");
}
-static int init(afb_api_t api)
+static void setloa (afb_req_t request)
{
- AFB_NOTICE("hello binding starting");
- return 0;
+ int loa = json_object_get_int(afb_req_json(request));
+ afb_req_session_set_LOA(request, loa);
+ afb_req_reply_f(request, NULL, NULL, "LOA set to %d", loa);
}
-static void onevent(afb_api_t api, const char *event, struct json_object *object)
+static void ok (afb_req_t request)
{
- AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+ afb_req_reply_f(request, NULL, NULL, NULL);
+}
+
+static void setctx (afb_req_t request)
+{
+ struct json_object *x = afb_req_json(request);
+ afb_req_context(request, (int)(intptr_t)afb_req_get_vcbdata(request), (void*)json_object_get, (void*)json_object_put, x);
+ afb_req_reply(request, json_object_get(x), NULL, "context set");
+}
+
+static void getctx (afb_req_t request)
+{
+ struct json_object *x = afb_req_context(request, 0, 0, 0, 0);
+ afb_req_reply(request, json_object_get(x), NULL, "returning the context");
+}
+
+static void info (afb_req_t request)
+{
+ afb_req_reply(request, afb_req_get_client_info(request), NULL, NULL);
+}
+
+static void eventloop (afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ struct sd_event *ev = afb_api_get_event_loop(api);
+ afb_req_reply(request, NULL, ev ? NULL : "no-event-loop", NULL);
+}
+
+static void dbus (afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ json_object *json = afb_req_json(request);
+ struct sd_bus *bus = (json_object_get_boolean(json) ? afb_api_get_system_bus : afb_api_get_user_bus)(api);
+ afb_req_reply(request, NULL, bus ? NULL : "no-bus", NULL);
+}
+
+static void replycount (afb_req_t request)
+{
+ json_object *json = afb_req_json(request);
+ int count = json_object_get_int(json);
+ while (count-- > 0)
+ afb_req_reply(request, NULL, NULL, NULL);
+}
+
+static void get(afb_req_t request)
+{
+ struct afb_arg arg = afb_req_get(request, "name");
+ const char *name, *value, *path;
+
+ if (!arg.name || !arg.value)
+ afb_req_reply(request, NULL, "invalid", "the parameter 'name' is missing");
+ else {
+ name = arg.name;
+ value = afb_req_value(request, name);
+ path = afb_req_path(request, name);
+ afb_req_reply_f(request, NULL, NULL, "found for '%s': %s", name, value ?: path ?: "NULL");
+ }
}
+static void ref(afb_req_t request)
+{
+ afb_req_addref(request);
+ afb_req_reply(request, NULL, NULL, NULL);
+ afb_req_unref(request);
+}
+
+static void mute(afb_req_t request)
+{
+}
+
+static void mutebug(afb_req_t request)
+{
+ afb_req_addref(request);
+}
+
+void queue_cb(int signum, void *arg)
+{
+ afb_req_t request = arg;
+ afb_req_reply(request, NULL, NULL, NULL);
+ afb_req_unref(request);
+}
+
+static void queue(afb_req_t request)
+{
+ afb_req_addref(request);
+ afb_api_queue_job(afb_req_get_api(request), queue_cb, request, NULL, 0);
+}
+
+static void settings(afb_req_t request)
+{
+ afb_api_t api = afb_req_get_api(request);
+ struct json_object *object = afb_api_settings(api);
+ afb_req_reply(request, json_object_get(object), NULL, NULL);
+}
+
+static void rootdir (afb_req_t request)
+{
+ ssize_t s;
+ afb_api_t api = afb_req_get_api(request);
+ int fd = afb_api_rootdir_get_fd(api);
+ char buffer[150], root[1025];
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+}
+
+static void locale (afb_req_t request)
+{
+ char buffer[150], root[1025];
+ const char *lang, *file;
+ ssize_t s;
+ json_object *json = afb_req_json(request), *x;
+ afb_api_t api = afb_req_get_api(request);
+ int fd;
+
+ lang = NULL;
+ if (json_object_is_type(json, json_type_string))
+ file = json_object_get_string(json);
+ else {
+ if (!json_object_object_get_ex(json, "file", &x)) {
+ afb_req_reply(request, NULL, "invalid", "no file");
+ return;
+ }
+ file = json_object_get_string(x);
+ if (json_object_object_get_ex(json, "lang", &x))
+ lang = json_object_get_string(x);
+ }
+
+ fd = afb_api_rootdir_open_locale(api, file, O_RDONLY, lang);
+ if (fd < 0)
+ afb_req_reply_f(request, NULL, "error", "can't open %s [%s]: %m", file?:"NULL", lang?:"NULL");
+ else {
+ sprintf(buffer, "/proc/self/fd/%d", fd);
+ s = readlink(buffer, root, sizeof root - 1);
+ if (s < 0)
+ afb_req_reply_f(request, NULL, "error", "can't readlink %s: %m", buffer);
+ else {
+ root[s] = 0;
+ afb_req_reply(request, json_object_new_string(root), NULL, NULL);
+ }
+ close(fd);
+ }
+}
+
+static void in_after (afb_req_t request)
+{
+ int rc;
+ const char *ts, *ty;
+ char *te;
+ double td;
+ struct timespec t;
+
+ /* get the type */
+ ty = afb_req_value(request, "type") ?: "call";
+ if (strcmp(ty, "call") && strcmp(ty, "callsync")
+ && strcmp(ty, "subcall") && strcmp(ty, "subcallsync"))
+ return afb_req_reply(request, NULL, "invalid", "bad type");
+
+ /* get the delay */
+ ts = afb_req_value(request, "delay");
+ if (!ts)
+ return afb_req_reply(request, NULL, "invalid", "no delay");
+ td = strtod(ts, &te);
+ if (*te || td < 0 || td > 3e6) /* a month is the biggest accepted */
+ return afb_req_reply(request, NULL, "invalid", "bad delay");
+
+ /* wait for that time */
+ if (td > 0) {
+ t.tv_nsec = (long)(1e6 * modf(td, &td));
+ t.tv_sec = (time_t)td;
+ do {
+ rc = nanosleep(&t, &t);
+ } while (rc != 0 && errno == EINTR);
+
+ if (rc)
+ return afb_req_reply(request, NULL, "error", "sleep failed");
+ }
+
+ /* do the call */
+ if (!strcmp(ty, "subcallsync"))
+ subcall(request);
+ else if (!strcmp(ty, "subcall"))
+ subcallsync(request);
+ else if (!strcmp(ty, "callsync"))
+ callsync(request);
+ else
+ call(request);
+}
+
+static void *thread_after (void *closure)
+{
+ afb_req_t request = closure;
+ in_after (request);
+ afb_req_unref(request);
+ return NULL;
+}
+
+static void after (afb_req_t request)
+{
+ int rc;
+ pthread_t tid;
+ pthread_attr_t attr;
+
+ afb_req_addref(request);
+
+ pthread_attr_init(&attr);
+ pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ rc =pthread_create(&tid, &attr, thread_after, request);
+ pthread_attr_destroy(&attr);
+
+ if (rc != 0) {
+ afb_req_unref(request);
+ afb_req_reply(request, NULL, "cant-start", NULL);
+ }
+}
+
+static void api (afb_req_t request);
+
+/**
+ * Definition of an authorization entry
+ */
+static struct afb_auth auths[] = {
+ { /* 0 */
+ .type = afb_auth_Or,
+ .first = &auths[1],
+ .next = &auths[9],
+ },
+ { /* 1 */
+ .type = afb_auth_And,
+ .first = &auths[2],
+ .next = &auths[3],
+ },
+ { /* 2 */
+ .type = afb_auth_Yes
+ },
+ { /* 3 */
+ .type = afb_auth_And,
+ .first = &auths[4],
+ .next = &auths[5],
+ },
+ { /* 4 */
+ .type = afb_auth_LOA,
+ .loa = 0
+ },
+ { /* 5 */
+ .type = afb_auth_Or,
+ .first = &auths[6],
+ .next = &auths[7],
+ },
+ { /* 6 */
+ .type = afb_auth_No
+ },
+ { /* 7 */
+ .type = afb_auth_Not,
+ .first = &auths[8]
+ },
+ { /* 8 */
+ .type = afb_auth_Yes
+ },
+ { /* 9 */
+ .type = afb_auth_And,
+ .first = &auths[10],
+ .next = &auths[13],
+ },
+ { /* 10 */
+ .type = afb_auth_Or,
+ .first = &auths[12],
+ .next = &auths[11],
+ },
+ { /* 11 */
+ .type = afb_auth_Not,
+ .first = &auths[13]
+ },
+ { /* 12 */
+ .type = afb_auth_Token
+ },
+ { /* 13 */
+ .type = afb_auth_And,
+ .first = &auths[14],
+ .next = &auths[17],
+ },
+ { /* 14 */
+ .type = afb_auth_Or,
+ .first = &auths[16],
+ .next = &auths[15],
+ },
+ { /* 15 */
+ .type = afb_auth_Not,
+ .first = &auths[16]
+ },
+ { /* 16 */
+ .type = afb_auth_Permission,
+ .text = "permission"
+ },
+ { /* 17 */
+ .type = afb_auth_Yes
+ }
+};
+
+
// NOTE: this sample does not use session to keep test a basic as possible
// in real application most APIs should be protected with AFB_SESSION_CHECK
static const struct afb_verb_v3 verbs[]= {
{ .verb="appid", .callback=appid },
{ .verb="uid", .callback=uid },
{ .verb="exit", .callback=exitnow },
+ { .verb="close", .callback=closess, .session=AFB_SESSION_CLOSE },
+ { .verb="set-loa", .callback=setloa, .auth = &auths[0] },
+ { .verb="has-loa-1", .callback=ok, .session=AFB_SESSION_LOA_1 },
+ { .verb="has-loa-2", .callback=ok, .session=AFB_SESSION_LOA_2 },
+ { .verb="has-loa-3", .callback=ok, .session=AFB_SESSION_LOA_3 },
+ { .verb="setctx", .callback=setctx, .vcbdata = (void*)(intptr_t)1 },
+ { .verb="setctxif", .callback=setctx, .vcbdata = (void*)(intptr_t)0 },
+ { .verb="getctx", .callback=getctx },
+ { .verb="checktok", .callback=ok, .session=AFB_SESSION_CHECK },
+ { .verb="reftok", .callback=ok, .session=AFB_SESSION_CHECK | AFB_SESSION_REFRESH },
+ { .verb="info", .callback=info },
+ { .verb="eventloop", .callback=eventloop },
+ { .verb="dbus", .callback=dbus },
+ { .verb="reply-count", .callback=replycount },
+ { .verb="get", .callback=get},
+ { .verb="ref", .callback=ref},
+ { .verb="rootdir", .callback=rootdir},
+ { .verb="locale", .callback=locale},
+ { .verb="api", .callback=api},
+ { .verb="mute", .callback=mute},
+ { .verb="mutebug", .callback=mutebug},
+ { .verb="queue", .callback=queue},
+ { .verb="settings", .callback=settings},
+ { .verb="after", .callback=after},
{ .verb=NULL}
};
-#if !defined(APINAME)
-#define APINAME "hello3"
+static void pingSample2 (struct afb_req_x1 req)
+{
+ pingSample(req.closure);
+}
+
+static const struct afb_verb_v2 apiverbs2[]= {
+ { .verb="ping", .callback=pingSample2 },
+ { .verb="ping2", .callback=pingSample2 },
+ { .verb=NULL }
+};
+
+static int apipreinit(void *closure, afb_api_t api)
+{
+ afb_api_set_verbs_v2(api, apiverbs2);
+ afb_api_set_verbs_v3(api, verbs);
+ return 0;
+}
+
+static void apiverb (afb_req_t request)
+{
+ afb_req_reply_f(request, json_object_get(afb_req_json(request)), NULL, "api: %s, verb: %s",
+ afb_req_get_called_api(request), afb_req_get_called_verb(request));
+}
+
+static void apievhndl(void *closure, const char *event, struct json_object *args, afb_api_t api)
+{
+ struct json_object *obj = closure;
+ afb_api_verbose(api, 0, NULL, 0, NULL, "the handler of closure(%s) received the event %s(%s)",
+ json_object_get_string(obj), event, json_object_get_string(args));
+}
+
+static void api (afb_req_t request)
+{
+ struct api *sapi, **psapi;
+ const char *action, *apiname, *verbname, *pattern;
+ json_object *json = afb_req_json(request), *x, *closure;
+ afb_api_t api = afb_req_get_api(request), oapi;
+
+ /* get the action */
+ if (!json_object_object_get_ex(json, "action", &x)) {
+ afb_req_reply(request, NULL, "invalid", "no action");
+ goto end;
+ }
+ action = json_object_get_string(x);
+
+ /* get the verb */
+ verbname = json_object_object_get_ex(json, "verb", &x) ?
+ json_object_get_string(x) : NULL;
+
+ /* get the pattern */
+ pattern = json_object_object_get_ex(json, "pattern", &x) ?
+ json_object_get_string(x) : NULL;
+
+ /* get the closure */
+ closure = NULL;
+ json_object_object_get_ex(json, "closure", &closure);
+
+ /* get the api */
+ if (json_object_object_get_ex(json, "api", &x)) {
+ apiname = json_object_get_string(x);
+ sapi = searchapi(apiname, &psapi);
+ oapi = sapi ? sapi->api : NULL;
+ } else {
+ oapi = api;
+ apiname = afb_api_name(api);
+ sapi = searchapi(apiname, &psapi);
+ }
+
+ /* search the sapi */
+ if (!strcasecmp(action, "create")) {
+ if (!apiname) {
+ afb_req_reply(request, NULL, "invalid", "no api");
+ goto end;
+ }
+ if (sapi) {
+ afb_req_reply(request, NULL, "already-exist", NULL);
+ goto end;
+ }
+ sapi = malloc (sizeof * sapi + strlen(apiname));
+ if (!sapi) {
+ afb_req_reply(request, NULL, "out-of-memory", NULL);
+ goto end;
+ }
+ sapi->api = afb_api_new_api(api, apiname, NULL, 1, apipreinit, NULL);
+ if (!sapi->api) {
+ afb_req_reply_f(request, NULL, "cant-create", "%m");
+ goto end;
+ }
+ strcpy(sapi->name, apiname);
+ sapi->next = NULL;
+ *psapi = sapi;
+ } else {
+ if (!oapi) {
+ afb_req_reply(request, NULL, "cant-find-api", NULL);
+ goto end;
+ }
+ if (!strcasecmp(action, "destroy")) {
+ if (!sapi) {
+ afb_req_reply(request, NULL, "cant-destroy", NULL);
+ goto end;
+ }
+ afb_api_delete_api(oapi);
+ *psapi = sapi->next;
+ free(sapi);
+ } else if (!strcasecmp(action, "addverb")) {
+ if (!verbname){
+ afb_req_reply(request, NULL, "invalid", "no verb");
+ goto end;
+ }
+ afb_api_add_verb(oapi, verbname, NULL, apiverb, NULL, NULL, 0, !!strchr(verbname, '*'));
+ } else if (!strcasecmp(action, "delverb")) {
+ if (!verbname){
+ afb_req_reply(request, NULL, "invalid", "no verb");
+ goto end;
+ }
+ afb_api_del_verb(oapi, verbname, NULL);
+ } else if (!strcasecmp(action, "addhandler")) {
+ if (!pattern){
+ afb_req_reply(request, NULL, "invalid", "no pattern");
+ goto end;
+ }
+ afb_api_event_handler_add(oapi, pattern, apievhndl, json_object_get(closure));
+ } else if (!strcasecmp(action, "delhandler")) {
+ if (!pattern){
+ afb_req_reply(request, NULL, "invalid", "no pattern");
+ goto end;
+ }
+ closure = NULL;
+ afb_api_event_handler_del(oapi, pattern, (void**)&closure);
+ json_object_put(closure);
+ } else if (!strcasecmp(action, "seal")) {
+ afb_api_seal(oapi);
+ } else {
+ afb_req_reply_f(request, NULL, "invalid", "unknown action %s", action ?: "NULL");
+ goto end;
+ }
+ }
+ afb_req_reply(request, NULL, NULL, NULL);
+end: return;
+}
+
+/*************************************************************/
+
+static int preinit(afb_api_t api)
+{
+ AFB_NOTICE("hello binding comes to live");
+#if defined(PREINIT_PROVIDE_CLASS)
+ afb_api_provide_class(api, PREINIT_PROVIDE_CLASS);
+#endif
+#if defined(PREINIT_REQUIRE_CLASS)
+ afb_api_require_class(api, PREINIT_REQUIRE_CLASS);
+#endif
+ return 0;
+}
+
+static int init(afb_api_t api)
+{
+ AFB_NOTICE("hello binding starting");
+#if defined(INIT_REQUIRE_API)
+ afb_api_require_api(api, INIT_REQUIRE_API, 1);
#endif
+ afb_api_add_alias(api, api->apiname, "fakename");
+ return 0;
+}
+
+static void onevent(afb_api_t api, const char *event, struct json_object *object)
+{
+ AFB_NOTICE("received event %s(%s)", event, json_object_to_json_string(object));
+}
const struct afb_binding_v3 afbBindingV3 = {
.api = APINAME,