/*
- * Copyright (C) 2015, 2016, 2017 "IoT.bzh"
+ * Copyright (C) 2015-2018 "IoT.bzh"
* Author José Bollo <jose.bollo@iot.bzh>
*
* Licensed under the Apache License, Version 2.0 (the "License");
#define NO_PLUGIN_VERBOSE_MACRO
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <systemd/sd-bus.h>
#include <json-c/json.h>
-#include <afb/afb-req-itf.h>
+#include <afb/afb-event.h>
-#include "afb-common.h"
+#include "afb-systemd.h"
#include "afb-session.h"
#include "afb-msg-json.h"
-#include "afb-apis.h"
-#include "afb-api-so.h"
+#include "afb-api.h"
+#include "afb-apiset.h"
+#include "afb-api-dbus.h"
#include "afb-context.h"
+#include "afb-cred.h"
#include "afb-evt.h"
#include "afb-xreq.h"
#include "verbose.h"
struct dbus_memo;
struct dbus_event;
-struct destination;
+struct origin;
/*
* The path given are of the form
struct {
struct sd_bus_slot *slot_call;
struct afb_evt_listener *listener; /* listener for broadcasted events */
- struct destination *destinations;
+ struct origin *origins;
+ struct afb_apiset *apiset;
} server;
};
};
goto error2;
}
api->api++;
- if (!afb_apis_is_valid_api_name(api->api)) {
+ if (!afb_api_is_valid_name(api->api, 1)) {
errno = EINVAL;
goto error2;
}
}
/* choose the bus */
- sdbus = (system ? afb_common_get_system_bus : afb_common_get_user_bus)();
+ sdbus = (system ? afb_systemd_get_system_bus : afb_systemd_get_user_bus)();
if (sdbus == NULL)
goto error2;
struct dbus_event
{
struct dbus_event *next;
- struct afb_event event;
+ struct afb_eventid *eventid;
int id;
int refcount;
};
memo = malloc(sizeof *memo);
if (memo != NULL) {
- afb_xreq_addref(xreq);
+ afb_xreq_unhooked_addref(xreq);
memo->xreq = xreq;
memo->msgid = 0;
memo->api = api;
prv = &(*prv)->next;
}
- afb_xreq_unref(memo->xreq);
+ afb_xreq_unhooked_unref(memo->xreq);
free(memo);
}
/* creates the message */
msg = NULL;
- rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->verb);
+ rc = sd_bus_message_new_method_call(api->sdbus, &msg, api->name, api->path, api->name, xreq->request.verb);
if (rc < 0)
goto error;
sd_bus_message_unref(msg);
}
-static int api_dbus_service_start(void *closure, int share_session, int onneed)
-{
- struct api_dbus *api = closure;
-
- /* not an error when onneed */
- if (onneed != 0)
- return 0;
-
- /* already started: it is an error */
- ERROR("The Dbus binding %s is not a startable service", api->name);
- return -1;
-}
-
/* receives broadcasted events */
static int api_dbus_client_on_broadcast_event(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
{
return 1;
}
-/* search the event */
+/* search the eventid */
static struct dbus_event *api_dbus_client_event_search(struct api_dbus *api, int id, const char *name)
{
struct dbus_event *ev;
ev = api->client.events;
- while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_event_name(ev->event), name)))
+ while (ev != NULL && (ev->id != id || 0 != strcmp(afb_evt_eventid_fullname(ev->eventid), name)))
ev = ev->next;
return ev;
}
-/* adds an event */
+/* adds an eventid */
static void api_dbus_client_event_create(struct api_dbus *api, int id, const char *name)
{
struct dbus_event *ev;
/* no conflict, try to add it */
ev = malloc(sizeof *ev);
if (ev != NULL) {
- ev->event = afb_evt_create_event(name);
- if (ev->event.closure == NULL)
+ ev->eventid = afb_evt_eventid_create(name);
+ if (ev->eventid == NULL)
free(ev);
else {
ev->refcount = 1;
ERROR("can't create event %s, out of memory", name);
}
-/* removes an event */
+/* removes an eventid */
static void api_dbus_client_event_drop(struct api_dbus *api, int id, const char *name)
{
struct dbus_event *ev, **prv;
*prv = ev->next;
/* destroys the event */
- afb_event_drop(ev->event);
+ afb_evt_eventid_unref(ev->eventid);
free(ev);
}
/* destroys the event */
object = json_tokener_parse(data);
- afb_event_push(ev->event, object);
+ afb_evt_eventid_push(ev->eventid, object);
}
/* subscribes an event */
}
/* subscribe the request to the event */
- rc = afb_xreq_subscribe(memo->xreq, ev->event);
+ rc = afb_xreq_subscribe(memo->xreq, ev->eventid);
if (rc < 0)
ERROR("can't subscribe: %m");
}
}
/* unsubscribe the request from the event */
- rc = afb_xreq_unsubscribe(memo->xreq, ev->event);
+ rc = afb_xreq_unsubscribe(memo->xreq, ev->eventid);
if (rc < 0)
ERROR("can't unsubscribe: %m");
}
return 1;
}
+static struct afb_api_itf dbus_api_itf = {
+ .call = api_dbus_client_call
+};
+
/* adds a afb-dbus-service client api */
-int afb_api_dbus_add_client(const char *path)
+int afb_api_dbus_add_client(const char *path, struct afb_apiset *apiset)
{
int rc;
struct api_dbus *api;
/* record it as an API */
afb_api.closure = api;
- afb_api.call = api_dbus_client_call;
- afb_api.service_start = api_dbus_service_start;
- afb_api.update_hooks = NULL;
- if (afb_apis_add(api->api, afb_api) < 0)
+ afb_api.itf = &dbus_api_itf;
+ afb_api.group = NULL;
+ if (afb_apiset_add(apiset, api->api, afb_api) < 0)
goto error2;
return 0;
.remove = afb_api_dbus_server_event_remove
};
-/******************* destination description part for server *****************************/
+/******************* origin description part for server *****************************/
-struct destination
+struct origin
{
- /* link to next different destination */
- struct destination *next;
+ /* link to next different origin */
+ struct origin *next;
/* the server dbus-api */
struct api_dbus *api;
/* count of references */
int refcount;
- /* the destination */
+ /* credentials of the origin */
+ struct afb_cred *cred;
+
+ /* the origin */
char name[1];
};
-static struct destination *afb_api_dbus_server_destination_get(struct api_dbus *api, const char *sender)
+/* get the credentials for the message */
+static void init_origin_creds(struct origin *origin)
{
- struct destination *destination;
+ int rc;
+ sd_bus_creds *c;
+ uid_t uid;
+ gid_t gid;
+ pid_t pid;
+ const char *context;
+
+ rc = sd_bus_get_name_creds(origin->api->sdbus, origin->name,
+ SD_BUS_CREDS_PID|SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_SELINUX_CONTEXT,
+ &c);
+ if (rc < 0)
+ origin->cred = NULL;
+ else {
+ afb_cred_unref(origin->cred);
+ sd_bus_creds_get_uid(c, &uid);
+ sd_bus_creds_get_gid(c, &gid);
+ sd_bus_creds_get_pid(c, &pid);
+ sd_bus_creds_get_selinux_context(c, &context);
+ origin->cred = afb_cred_create(uid, gid, pid, context);
+ sd_bus_creds_unref(c);
+ }
+}
- /* searchs for an existing destination */
- destination = api->server.destinations;
- while (destination != NULL) {
- if (0 == strcmp(destination->name, sender)) {
- destination->refcount++;
- return destination;
+static struct origin *afb_api_dbus_server_origin_get(struct api_dbus *api, const char *sender)
+{
+ struct origin *origin;
+
+ /* searchs for an existing origin */
+ origin = api->server.origins;
+ while (origin != NULL) {
+ if (0 == strcmp(origin->name, sender)) {
+ origin->refcount++;
+ return origin;
}
- destination = destination->next;
+ origin = origin->next;
}
/* not found, create it */
- destination = malloc(strlen(sender) + sizeof *destination);
- if (destination == NULL)
+ origin = malloc(strlen(sender) + sizeof *origin);
+ if (origin == NULL)
errno = ENOMEM;
else {
- destination->api = api;
- destination->refcount = 1;
- strcpy(destination->name, sender);
- destination->next = api->server.destinations;
- api->server.destinations = destination;
+ origin->api = api;
+ origin->refcount = 1;
+ strcpy(origin->name, sender);
+ init_origin_creds(origin);
+ origin->next = api->server.origins;
+ api->server.origins = origin;
}
- return destination;
+ return origin;
}
-static void afb_api_dbus_server_destination_unref(struct destination *destination)
+static void afb_api_dbus_server_origin_unref(struct origin *origin)
{
- if (!--destination->refcount) {
- struct destination **prv;
+ if (!--origin->refcount) {
+ struct origin **prv;
- prv = &destination->api->server.destinations;
- while(*prv != destination)
+ prv = &origin->api->server.origins;
+ while(*prv != origin)
prv = &(*prv)->next;
- *prv = destination->next;
- free(destination);
+ *prv = origin->next;
+ afb_cred_unref(origin->cred);
+ free(origin);
}
}
struct listener
{
- /* link to next different destination */
- struct destination *destination;
+ /* link to next different origin */
+ struct origin *origin;
/* the listener of events */
struct afb_evt_listener *listener;
static void afb_api_dbus_server_listener_free(struct listener *listener)
{
afb_evt_listener_unref(listener->listener);
- afb_api_dbus_server_destination_unref(listener->destination);
+ afb_api_dbus_server_origin_unref(listener->origin);
free(listener);
}
-static struct listener *afb_api_dbus_server_listerner_get(struct api_dbus *api, const char *sender, struct afb_session *session)
+static struct listener *afb_api_dbus_server_listener_get(struct api_dbus *api, const char *sender, struct afb_session *session)
{
int rc;
struct listener *listener;
- struct destination *destination;
+ struct origin *origin;
- /* get the destination */
- destination = afb_api_dbus_server_destination_get(api, sender);
- if (destination == NULL)
+ /* get the origin */
+ origin = afb_api_dbus_server_origin_get(api, sender);
+ if (origin == NULL)
return NULL;
/* retrieves the stored listener */
- listener = afb_session_get_cookie(session, destination);
+ listener = afb_session_get_cookie(session, origin);
if (listener != NULL) {
/* found */
- afb_api_dbus_server_destination_unref(destination);
+ afb_api_dbus_server_origin_unref(origin);
return listener;
}
if (listener == NULL)
errno = ENOMEM;
else {
- listener->destination = destination;
- listener->listener = afb_evt_listener_create(&evt_push_itf, destination);
+ listener->origin = origin;
+ listener->listener = afb_evt_listener_create(&evt_push_itf, origin);
if (listener->listener != NULL) {
- rc = afb_session_set_cookie(session, destination, listener, (void*)afb_api_dbus_server_listener_free);
+ rc = afb_session_set_cookie(session, origin, listener, (void*)afb_api_dbus_server_listener_free);
if (rc == 0)
return listener;
afb_evt_listener_unref(listener->listener);
}
free(listener);
}
- afb_api_dbus_server_destination_unref(destination);
+ afb_api_dbus_server_origin_unref(origin);
return NULL;
}
};
/* decrement the reference count of the request and free/release it on falling to null */
-static void dbus_req_destroy(void *closure)
+static void dbus_req_destroy(struct afb_xreq *xreq)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
afb_context_disconnect(&dreq->xreq.context);
json_object_put(dreq->json);
}
/* get the object of the request */
-static struct json_object *dbus_req_json(void *closure)
+static struct json_object *dbus_req_json(struct afb_xreq *xreq)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
return dreq->json;
}
ERROR("sending the reply failed");
}
-static void dbus_req_success(void *closure, struct json_object *obj, const char *info)
+static void dbus_req_success(struct afb_xreq *xreq, struct json_object *obj, const char *info)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
dbus_req_reply(dreq, RETOK, json_object_to_json_string_ext(obj, JSON_C_TO_STRING_PLAIN), info);
}
-static void dbus_req_fail(void *closure, const char *status, const char *info)
+static void dbus_req_fail(struct afb_xreq *xreq, const char *status, const char *info)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
dbus_req_reply(dreq, RETERR, status, info);
}
-static void afb_api_dbus_server_event_send(struct destination *destination, char order, const char *event, int eventid, const char *data, uint64_t msgid);
+static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid);
-static int dbus_req_subscribe(void *closure, struct afb_event event)
+static int dbus_req_subscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
uint64_t msgid;
int rc;
- rc = afb_evt_add_watch(dreq->listener->listener, event);
+ rc = afb_evt_eventid_add_watch(dreq->listener->listener, eventid);
sd_bus_message_get_cookie(dreq->message, &msgid);
- afb_api_dbus_server_event_send(dreq->listener->destination, 'S', afb_evt_event_name(event), afb_evt_event_id(event), "", msgid);
+ afb_api_dbus_server_event_send(dreq->listener->origin, 'S', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid);
return rc;
}
-static int dbus_req_unsubscribe(void *closure, struct afb_event event)
+static int dbus_req_unsubscribe(struct afb_xreq *xreq, struct afb_eventid *eventid)
{
- struct dbus_req *dreq = closure;
+ struct dbus_req *dreq = CONTAINER_OF_XREQ(struct dbus_req, xreq);
uint64_t msgid;
int rc;
sd_bus_message_get_cookie(dreq->message, &msgid);
- afb_api_dbus_server_event_send(dreq->listener->destination, 'U', afb_evt_event_name(event), afb_evt_event_id(event), "", msgid);
- rc = afb_evt_remove_watch(dreq->listener->listener, event);
+ afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_eventid_fullname(eventid), afb_evt_eventid_id(eventid), "", msgid);
+ rc = afb_evt_eventid_remove_watch(dreq->listener->listener, eventid);
return rc;
}
+static void dbus_req_subcall(
+ struct afb_xreq *xreq,
+ const char *api,
+ const char *verb,
+ struct json_object *args,
+ void (*callback)(void*, int, struct json_object*),
+ void *cb_closure)
+{
+ ERROR("DBUS API doesn't support subcalls, info: %s/%s(%s)", api, verb, json_object_to_json_string(args));
+ callback(cb_closure, 1, afb_msg_json_reply_error("error", "subcall isn't supported", NULL, NULL));
+ json_object_put(args);
+}
+
const struct afb_xreq_query_itf afb_api_dbus_xreq_itf = {
.json = dbus_req_json,
.success = dbus_req_success,
.fail = dbus_req_fail,
.unref = dbus_req_destroy,
.subscribe = dbus_req_subscribe,
- .unsubscribe = dbus_req_unsubscribe
+ .unsubscribe = dbus_req_unsubscribe,
+ .subcall = dbus_req_subcall
};
/******************* server part **********************************/
-static void afb_api_dbus_server_event_send(struct destination *destination, char order, const char *event, int eventid, const char *data, uint64_t msgid)
+static void afb_api_dbus_server_event_send(struct origin *origin, char order, const char *event, int eventid, const char *data, uint64_t msgid)
{
int rc;
struct api_dbus *api;
struct sd_bus_message *msg;
- api = destination->api;
+ api = origin->api;
msg = NULL;
- rc = sd_bus_message_new_method_call(api->sdbus, &msg, destination->name, api->path, api->name, "event");
+ rc = sd_bus_message_new_method_call(api->sdbus, &msg, origin->name, api->path, api->name, "event");
if (rc < 0)
goto error;
goto end;
error:
- ERROR("error while send event %c%s(%d) to %s", order, event, eventid, destination->name);
+ ERROR("error while send event %c%s(%d) to %s", order, event, eventid, origin->name);
end:
sd_bus_message_unref(msg);
}
}
/* connect to the context */
+ afb_xreq_init(&dreq->xreq, &afb_api_dbus_xreq_itf);
if (afb_context_connect(&dreq->xreq.context, uuid, NULL) < 0)
goto out_of_memory;
session = dreq->xreq.context.session;
/* get the listener */
- listener = afb_api_dbus_server_listerner_get(api, sd_bus_message_get_sender(message), session);
+ listener = afb_api_dbus_server_listener_get(api, sd_bus_message_get_sender(message), session);
if (listener == NULL)
goto out_of_memory;
dreq->json = json_object_new_string(dreq->request);
}
dreq->listener = listener;
- dreq->xreq.refcount = 1;
- dreq->xreq.query = dreq;
- dreq->xreq.queryitf = &afb_api_dbus_xreq_itf;
- dreq->xreq.api = api->api;
- dreq->xreq.verb = method;
- afb_apis_call(&dreq->xreq);
- afb_xreq_unref(&dreq->xreq);
+ dreq->xreq.request.api = api->api;
+ dreq->xreq.request.verb = method;
+ afb_xreq_process(&dreq->xreq, api->server.apiset);
return 1;
out_of_memory:
}
/* create the service */
-int afb_api_dbus_add_server(const char *path)
+int afb_api_dbus_add_server(const char *path, struct afb_apiset *apiset)
{
int rc;
struct api_dbus *api;
INFO("afb service over dbus installed, name %s, path %s", api->name, api->path);
api->server.listener = afb_evt_listener_create(&evt_broadcast_itf, api);
+ api->server.apiset = afb_apiset_addref(apiset);
return 0;
error3:
sd_bus_release_name(api->sdbus, api->name);