#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-itf.h>
#include "afb-common.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)) {
errno = EINVAL;
goto error2;
}
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;
}
+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;
+ 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_event event)
{
- 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);
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_event_name(event), afb_evt_event_id(event), "", 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_event event)
{
- 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);
+ afb_api_dbus_server_event_send(dreq->listener->origin, 'U', afb_evt_event_name(event), afb_evt_event_id(event), "", msgid);
rc = afb_evt_remove_watch(dreq->listener->listener, event);
return rc;
}
/******************* 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);
+ 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);