*/
#include "config.h"
-
#include "gkdbus.h"
#include "glib-unix.h"
+#include "glibintl.h"
+#include "kdbus.h"
+#include "gkdbusconnection.h"
+#include <gio/gio.h>
#include <errno.h>
#include <string.h>
#include <sys/mman.h>
+#include <sys/ioctl.h>
#include <stdio.h>
+#include <stdint.h>
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
#include <glib/gstdio.h>
+#include <glib/glib-private.h>
#include <gio/gio.h>
#include <gio/gunixfdlist.h>
#include "glibintl.h"
#include "gunixfdmessage.h"
-#include "gdbusprivate.h"
-#include "kdbus.h"
-
-
-/**
- * SECTION:gkdbus
- * @short_description: Low-level kdbus object
- * @include: gio/gio.h
- *
- * A #GKdbus is a lowlevel adapter for kdbus IPC solution. It is meant
- * to replace DBUS as fundamental IPC solution for Linux, however it
- * is still experimental work in progress. You may find detailed
- * description in kdbus.txt at https://github.com/gregkh/kdbus
- *
- */
-
-/* Size of memory registered with kdbus for receiving messages */
-#define KDBUS_POOL_SIZE (16 * 1024 * 1024)
-
-#define ALIGN8(l) (((l) + 7) & ~7)
-#define ALIGN8_PTR(p) ((void*) ALIGN8((gulong) p))
+#define KDBUS_POOL_SIZE (16 * 1024LU * 1024LU)
+#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
+#define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p))
#define KDBUS_ITEM_HEADER_SIZE G_STRUCT_OFFSET(struct kdbus_item, data)
-#define KDBUS_ITEM_SIZE(s) ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
+#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
#define KDBUS_ITEM_NEXT(item) \
- (typeof(item))(((guint8 *)item) + ALIGN8((item)->size))
-
-#define KDBUS_ITEM_FOREACH(item, head, first) \
- for (item = (head)->first; \
- ((guint8 *)(item) < (guint8 *)(head) + (head)->size) && \
- ((guint8 *)(item) >= (guint8 *)(head)); \
+ (typeof(item))(((guint8 *)item) + KDBUS_ALIGN8((item)->size))
+#define KDBUS_ITEM_FOREACH(item, head, first) \
+ for (item = (head)->first; \
+ (guint8 *)(item) < (guint8 *)(head) + (head)->size; \
item = KDBUS_ITEM_NEXT(item))
#define g_alloca0(x) memset(g_alloca(x), '\0', (x))
-/**
- * use systemd-bus-drvierd (from systemd) which implements the all
- * org.freedesktop.DBus methods on kdbus
- */
-
-#define SYSTEMD_BUS_DRIVERD
-
-
-/* GBusNameOwnerReturnFlags */
-typedef enum
-{
- G_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER = 1, /* Caller is now the primary owner of the name, replacing any previous owner */
- G_BUS_REQUEST_NAME_REPLY_IN_QUEUE = 2, /* The name already had an owner, the application will be placed in a queue */
- G_BUS_REQUEST_NAME_REPLY_EXISTS = 3, /* The name already has an owner */
- G_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER = 4 /* The application trying to request ownership of a name is already the owner of it */
-} GBusNameOwnerReturnFlags;
-
-
-/* GBusReleaseNameReturnFlags */
-typedef enum
-{
- G_BUS_RELEASE_NAME_REPLY_RELEASED = 1, /* The caller has released his claim on the given name */
- G_BUS_RELEASE_NAME_REPLY_NON_EXISTENT = 2, /* The given name does not exist on this bus*/
- G_BUS_RELEASE_NAME_REPLY_NOT_OWNER = 3 /* The caller not waiting in the queue to own this name*/
-} GBusReleaseNameReturnFlags;
-
-
-/* GBusStartServiceReturnFlags */
-typedef enum
-{
- G_BUS_START_REPLY_SUCCESS = 1, /* The service was successfully started */
- G_BUS_START_REPLY_ALREADY_RUNNING = 2, /* A connection already owns the given name */
-} GBusStartServiceReturnFlags;
-
-
-/* GBusCredentialsFlags */
-typedef enum
-{
- G_BUS_CREDS_PID = 1,
- G_BUS_CREDS_UID = 2,
- G_BUS_CREDS_UNIQUE_NAME = 3,
- G_BUS_CREDS_SELINUX_CONTEXT = 4
-} GBusCredentialsFlags;
-
-
static void g_kdbus_initable_iface_init (GInitableIface *iface);
static gboolean g_kdbus_initable_init (GInitable *initable,
GCancellable *cancellable,
G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
g_kdbus_initable_iface_init));
+/* GBusCredentialsFlags */
+typedef enum
+{
+ G_BUS_CREDS_PID = 1,
+ G_BUS_CREDS_UID = 2,
+ G_BUS_CREDS_UNIQUE_NAME = 3,
+ G_BUS_CREDS_SELINUX_CONTEXT = 4
+} GBusCredentialsFlags;
+/* GKdbusPrivate struct */
struct _GKdbusPrivate
{
gint fd;
- gchar *path;
+
gchar *kdbus_buffer;
- GSList *kdbus_msg_items;
+
+ gchar *unique_name;
guint64 unique_id;
- guint64 hello_flags;
- guint64 attach_flags;
- guint closed : 1;
- guint inited : 1;
- guint timeout;
- guint timed_out : 1;
- guchar bus_id[16];
- struct kdbus_msg *kmsg;
- GString *msg_sender;
- GString *msg_destination;
+
+ guint64 flags;
+ guint64 attach_flags_send;
+ guint64 attach_flags_recv;
gsize bloom_size;
guint bloom_n_hash;
- gint *fds;
- gint num_fds;
+ guint closed : 1;
+ guint inited : 1;
+ guint timeout;
+ guint timed_out : 1;
- gint memfd;
+ guchar bus_id[16];
};
-
+/* GKdbusSource struct */
typedef struct {
GSource source;
GPollFD pollfd;
GIOCondition condition,
gpointer user_data);
-
/* Hash keys for bloom filters*/
const guint8 hash_keys[8][16] =
{
/**
- * _g_kdbus_get_last_msg_sender
- *
- */
-gchar *
-_g_kdbus_get_last_msg_sender (GKdbus *kdbus)
-{
- return kdbus->priv->msg_sender->str;
-}
-
-
-/**
- * _g_kdbus_get_last_msg_destination
- *
- */
-gchar *
-_g_kdbus_get_last_msg_destination (GKdbus *kdbus)
-{
- return kdbus->priv->msg_destination->str;
-}
-
-
-/**
- * _g_kdbus_get_last_msg_items:
- *
- */
-GSList *
-_g_kdbus_get_last_msg_items (GKdbus *kdbus)
-{
- return kdbus->priv->kdbus_msg_items;
-}
-
-
-/**
- * g_kdbus_add_msg_part:
- *
- */
-static void
-g_kdbus_add_msg_part (GKdbus *kdbus,
- gchar *data,
- gsize size)
-{
- msg_part* part = g_new (msg_part, 1);
- part->data = data;
- part->size = size;
- kdbus->priv->kdbus_msg_items = g_slist_append(kdbus->priv->kdbus_msg_items, part);
-}
-
-
-/**
* _g_kdbus_hexdump_all_items:
*
*/
if (kdbus->priv->fd != -1 && !kdbus->priv->closed)
_g_kdbus_close (kdbus, NULL);
- g_string_free (kdbus->priv->msg_sender, TRUE);
- g_string_free (kdbus->priv->msg_destination, TRUE);
-
if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize)
(*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object);
}
kdbus->priv = G_TYPE_INSTANCE_GET_PRIVATE (kdbus, G_TYPE_KDBUS, GKdbusPrivate);
kdbus->priv->fd = -1;
+
kdbus->priv->unique_id = -1;
- kdbus->priv->memfd = -1;
+ kdbus->priv->unique_name = NULL;
- kdbus->priv->path = NULL;
kdbus->priv->kdbus_buffer = NULL;
- kdbus->priv->kdbus_msg_items = NULL;
-
- kdbus->priv->msg_sender = g_string_new (NULL);
- kdbus->priv->msg_destination = g_string_new (NULL);
- kdbus->priv->fds = NULL;
- kdbus->priv->num_fds = 0;
-
- kdbus->priv->hello_flags = KDBUS_HELLO_ACCEPT_FD;
- kdbus->priv->attach_flags = KDBUS_ATTACH_NAMES;
+ kdbus->priv->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
+ kdbus->priv->attach_flags_send = _KDBUS_ATTACH_ALL;
+ kdbus->priv->attach_flags_recv = _KDBUS_ATTACH_ALL;
}
if (kdbus->priv->timeout)
kdbus_source->timeout_time = g_get_monotonic_time ()
+ kdbus->priv->timeout * 1000000;
-
else
kdbus_source->timeout_time = 0;
/**
* _g_kdbus_open:
- * @kdbus: a #GKdbus.
- * @address: path to kdbus bus file.
- * @error: #GError for error reporting, or %NULL to ignore.
*
- * Opens file descriptor to kdbus bus control.
- * It is located in /dev/kdbus/uid-name/bus.
- *
- * Returns: TRUE on success.
*/
gboolean
_g_kdbus_open (GKdbus *kdbus,
g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
kdbus->priv->fd = open(address, O_RDWR|O_NOCTTY|O_CLOEXEC);
-
if (kdbus->priv->fd<0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Can't open kdbus endpoint"));
/**
- * _g_kdbus_close:
- * @kdbus: a #GKdbus.
- * @error: #GError for error reporting, or %NULL to ignore.
+ * g_kdbus_free_data:
*
- * Closes file descriptor to kdbus bus.
- * Disconnect a connection. If the connection's message list is empty,
- * the calls succeeds, closes file descriptor to kdbus bus. Otherwise
- * FALSE is returned without any further side-effects.
+ */
+static gboolean
+g_kdbus_free_data (GKdbus *kdbus,
+ guint64 offset)
+{
+ struct kdbus_cmd_free cmd;
+ int ret;
+
+ cmd.offset = offset;
+ cmd.flags = 0;
+
+ ret = ioctl (kdbus->priv->fd, KDBUS_CMD_FREE, &cmd);
+ if (ret < 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+
+/**
+ * g_kdbus_translate_nameowner_flags:
*
- * Returns: TRUE on success.
+ */
+static void
+g_kdbus_translate_nameowner_flags (GBusNameOwnerFlags flags,
+ guint64 *kdbus_flags)
+{
+ guint64 new_flags;
+
+ new_flags = 0;
+
+ if (flags & G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT)
+ new_flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
+
+ if (flags & G_BUS_NAME_OWNER_FLAGS_REPLACE)
+ new_flags |= KDBUS_NAME_REPLACE_EXISTING;
+
+ if (!(flags & G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE))
+ new_flags |= KDBUS_NAME_QUEUE;
+
+ *kdbus_flags = new_flags;
+}
+
+
+/**
+ * _g_kdbus_close:
*
*/
gboolean
{
gint res;
- if (kdbus->priv->closed)
- return TRUE; /* Multiple close not an error */
-
g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_BYEBYE) < 0)
- return FALSE;
+ if (kdbus->priv->closed)
+ return TRUE;
while (1)
{
/**
* _g_kdbus_is_closed:
- * @kdbus: a #GKdbus.
- *
- * checks whether a kdbus is closed.
*
*/
gboolean
/**
- * g_kdbus_generate_local_reply:
+ * _g_kdbus_Hello:
*
*/
-static GDBusMessage *
-g_kdbus_generate_local_reply (GDBusMessage *message,
- GDBusMessageType message_type,
- GDBusMessageFlags message_flags,
- guint32 message_reply_serial,
- GVariant *message_body,
- const gchar *error_name)
+GVariant *
+_g_kdbus_Hello (GIOStream *stream,
+ GError **error)
{
- GDBusMessage *reply;
+ GKdbus *kdbus;
+ struct kdbus_cmd_hello *hello;
+ struct kdbus_item *item;
- reply = g_dbus_message_new ();
+ gchar *conn_name;
+ size_t size, conn_name_size;
+
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (stream));
+
+ conn_name = "gdbus-kdbus";
+ conn_name_size = strlen (conn_name);
- g_dbus_message_set_sender (reply, "org.freedesktop.DBus");
- g_dbus_message_set_message_type (reply, message_type);
- g_dbus_message_set_flags (reply, message_flags);
- g_dbus_message_set_reply_serial (reply, message_reply_serial);
+ size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_hello, items)) +
+ KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1);
+
+ hello = g_alloca0 (size);
+ hello->flags = kdbus->priv->flags;
+ hello->attach_flags_send = kdbus->priv->attach_flags_send;
+ hello->attach_flags_recv = kdbus->priv->attach_flags_recv;
+ hello->size = size;
+ hello->pool_size = KDBUS_POOL_SIZE;
- g_dbus_message_set_body (reply, message_body);
+ item = hello->items;
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1;
+ item->type = KDBUS_ITEM_CONN_DESCRIPTION;
+ memcpy (item->str, conn_name, conn_name_size+1);
+ item = KDBUS_ITEM_NEXT (item);
- if (message != NULL)
- g_dbus_message_set_destination (reply, g_dbus_message_get_sender (message));
+ if (ioctl(kdbus->priv->fd, KDBUS_CMD_HELLO, hello))
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Failed to send HELLO: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
- if (message_type == G_DBUS_MESSAGE_TYPE_ERROR)
- g_dbus_message_set_error_name (reply, error_name);
+ kdbus->priv->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kdbus->priv->fd, 0);
+ if (kdbus->priv->kdbus_buffer == MAP_FAILED)
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("mmap error: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
- if (G_UNLIKELY (_g_dbus_debug_message ()))
+ if (hello->bus_flags > 0xFFFFFFFFULL)
{
- gchar *s;
- _g_dbus_debug_print_lock ();
- g_print ("========================================================================\n"
- "GDBus-debug:Message:\n"
- " <<<< RECEIVED LOCAL D-Bus message (N/A bytes)\n");
-
- s = g_dbus_message_print (reply, 2);
- g_print ("%s", s);
- g_free (s);
- _g_dbus_debug_print_unlock ();
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Incompatible HELLO flags"));
+ return NULL;
}
- return reply;
+ memcpy (kdbus->priv->bus_id, hello->id128, 16);
+
+ kdbus->priv->unique_id = hello->id;
+ asprintf(&kdbus->priv->unique_name, ":1.%llu", (unsigned long long) hello->id);
+
+ /* read bloom filters parameters */
+ kdbus->priv->bloom_size = (gsize) hello->bloom.size;
+ kdbus->priv->bloom_n_hash = (guint) hello->bloom.n_hash;
+
+ return g_variant_new ("(s)", kdbus->priv->unique_name);
}
/**
- * g_kdbus_generate_local_error:
+ * _g_kdbus_RequestName:
*
*/
-static void
-g_kdbus_generate_local_error (GDBusWorker *worker,
- GDBusMessage *dbus_msg,
- GVariant *message_body,
- gint error_code)
+GVariant *
+_g_kdbus_RequestName (GDBusConnection *connection,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GError **error)
{
- GDBusMessage *reply;
- GError *error = NULL;
- gchar *dbus_error_name;
-
- error = g_error_new_literal (G_DBUS_ERROR, error_code, "");
- dbus_error_name = g_dbus_error_encode_gerror (error);
-
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_ERROR,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- message_body,
- dbus_error_name);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-}
+ GKdbus *kdbus;
+ GVariant *result;
+ struct kdbus_cmd_name *kdbus_name;
+ guint64 kdbus_flags;
+ gssize len, size;
+ gint status, ret;
+ status = G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER;
-/**
- * g_kdbus_check_signature:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_check_signature (GDBusWorker *worker,
- GDBusMessage *dbus_msg,
- const gchar *method_name,
- GVariant *body,
- const GVariantType *type)
-{
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
+ {
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ return NULL;
+ }
- if (!g_variant_is_of_type (body, type))
+ if (!g_dbus_is_name (name))
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Call to %s has wrong args (expected %s)", method_name, g_variant_type_peek_string (type));
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_INVALID_ARGS);
- g_string_free (error_name,TRUE);
- return FALSE;
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return NULL;
}
- else
- return TRUE;
+
+ if (*name == ':')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot acquire a service starting with ':' such as \"%s\"", name);
+ return NULL;
+ }
+
+ g_kdbus_translate_nameowner_flags (flags, &kdbus_flags);
+
+ len = strlen(name) + 1;
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(len);
+ kdbus_name = g_alloca0 (size);
+ kdbus_name->size = size;
+ kdbus_name->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ kdbus_name->items[0].type = KDBUS_ITEM_NAME;
+ kdbus_name->flags = kdbus_flags;
+ memcpy (kdbus_name->items[0].str, name, len);
+
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_ACQUIRE, kdbus_name);
+ if (ret < 0)
+ {
+ if (errno == EEXIST)
+ status = G_BUS_REQUEST_NAME_FLAGS_EXISTS;
+ else if (errno == EALREADY)
+ status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
+ else
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error while acquiring name: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
+ }
+
+ if (kdbus_name->flags & KDBUS_NAME_IN_QUEUE)
+ status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
+
+ result = g_variant_new ("(u)", status);
+
+ return result;
}
/**
- * g_kdbus_check_name:
- * Returns: TRUE on success.
+ * _g_kdbus_ReleaseName:
+ *
*/
-static gboolean
-g_kdbus_check_name (GDBusWorker *worker,
- GDBusMessage *dbus_msg,
- const gchar *name)
+GVariant *
+_g_kdbus_ReleaseName (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
{
+ GKdbus *kdbus;
+ GVariant *result;
+ struct kdbus_cmd_name *kdbus_name;
+ gssize len, size;
+ gint status, ret;
+
+ status = G_BUS_RELEASE_NAME_FLAGS_RELEASED;
+
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
+ {
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ return NULL;
+ }
+
if (!g_dbus_is_name (name))
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Name \"%s\" is not valid", name);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_INVALID_ARGS);
- g_string_free (error_name,TRUE);
- return FALSE;
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return NULL;
}
- else
- return TRUE;
+
+ if (*name == ':')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot release a service starting with ':' such as \"%s\"", name);
+ return NULL;
+ }
+
+ len = strlen(name) + 1;
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_name, items) + KDBUS_ITEM_SIZE(len);
+ kdbus_name = g_alloca0 (size);
+ kdbus_name->size = size;
+ kdbus_name->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ kdbus_name->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (kdbus_name->items[0].str, name, len);
+
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_RELEASE, kdbus_name);
+ if (ret < 0)
+ {
+ if (errno == ESRCH)
+ status = G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT;
+ else if (errno == EADDRINUSE)
+ status = G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER;
+ else
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error while releasing name: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
+ }
+
+ result = g_variant_new ("(u)", status);
+
+ return result;
}
/**
- * g_kdbus_translate_request_name_flags:
+ * _g_kdbus_GetBusId:
*
*/
-static void
-g_kdbus_translate_request_name_flags (GBusNameOwnerFlags flags,
- guint64 *kdbus_flags)
-{
- guint64 new_flags = 0;
+GVariant *
+_g_kdbus_GetBusId (GDBusConnection *connection,
+ GError **error)
+{
+ GKdbus *kdbus;
+ GVariant *result;
+ GString *result_str;
+ guint cnt;
+
+ result_str = g_string_new (NULL);
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
+ {
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ g_string_free (result_str, TRUE);
+ return NULL;
+ }
- if (flags & G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT)
- new_flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
+ for (cnt=0; cnt<16; cnt++)
+ g_string_append_printf (result_str, "%02x", kdbus->priv->bus_id[cnt]);
- if (flags & G_BUS_NAME_OWNER_FLAGS_REPLACE)
- new_flags |= KDBUS_NAME_REPLACE_EXISTING;
+ result = g_variant_new ("(s)", result_str->str);
+ g_string_free (result_str, TRUE);
- *kdbus_flags = new_flags;
+ return result;
}
/**
- * g_kdbus_NameHasOwner:
- * Returns: TRUE on success.
+ * _g_kdbus_GetListNames:
+ *
*/
-static gboolean
-g_kdbus_NameHasOwner (GKdbus *kdbus, const gchar *name)
+GVariant *
+_g_kdbus_GetListNames (GDBusConnection *connection,
+ guint list_name_type,
+ GError **error)
{
- struct kdbus_cmd_conn_info *cmd;
- gssize size;
- gint ret;
-
- if (g_dbus_is_unique_name(name))
- {
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, name);
- cmd = g_alloca0 (size);
- cmd->id = g_ascii_strtoull (name+3,NULL,10);
- }
- else
- {
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
- cmd = g_alloca0 (size);
- strcpy(cmd->name, name);
- }
-
- cmd->flags = KDBUS_ATTACH_NAMES;
- cmd->size = size;
-
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
-
- if (ret<0)
- return FALSE;
- else
- return TRUE;
-}
-
-
-/**
- * g_kdbus_take_fd:
- *
- */
-static void
-g_kdbus_take_fd (GKdbus *kdbus)
-{
- struct kdbus_cmd_hello *hello;
- struct kdbus_item *item;
- gchar *conn_name;
- size_t size, conn_name_size;
-
- conn_name = "gdbus-kdbus";
- conn_name_size = strlen (conn_name);
-
- size = ALIGN8(G_STRUCT_OFFSET(struct kdbus_cmd_hello, items)) +
- ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, str) + conn_name_size + 1);
-
- hello = g_alloca0(size);
- hello->conn_flags = kdbus->priv->hello_flags;
- hello->attach_flags = kdbus->priv->attach_flags;
- hello->size = size;
- hello->pool_size = KDBUS_POOL_SIZE;
-
- /* connection's human-readable name (only for debugging purposes)*/
- item = hello->items;
- item->size = G_STRUCT_OFFSET(struct kdbus_item, str) + conn_name_size + 1;
- item->type = KDBUS_ITEM_CONN_NAME;
- memcpy(item->str, conn_name, conn_name_size+1);
- item = KDBUS_ITEM_NEXT(item);
-
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_HELLO, hello))
- g_error("[KDBUS] fd=%d failed to send hello: %m, %d", kdbus->priv->fd,errno);
-
- kdbus->priv->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kdbus->priv->fd, 0);
-
- if (kdbus->priv->kdbus_buffer == MAP_FAILED)
- g_error("[KDBUS] error when mmap: %m, %d", errno);
-
- if (hello->bus_flags > 0xFFFFFFFFULL || hello->conn_flags > 0xFFFFFFFFULL)
- g_error("[KDBUS] incompatible flags");
-
- /* read bloom filters parameters */
- kdbus->priv->bloom_size = (gsize) hello->bloom.size;
- kdbus->priv->bloom_n_hash = (guint) hello->bloom.n_hash;
-
- /* validate bloom filters parameters here? */
-
- kdbus->priv->unique_id = hello->id;
- memcpy (kdbus->priv->bus_id, hello->id128, 16);
-}
-
-
-/**
- * g_kdbus_Hello_reply:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_Hello_reply (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GString *unique_name;
- GDBusMessage *reply;
-
- unique_name = g_string_new(NULL);
- g_string_printf (unique_name,":1.%" G_GUINT64_FORMAT, kdbus->priv->unique_id);
-
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(s)",unique_name->str),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-
- g_string_free (unique_name,TRUE);
- return TRUE;
-}
+ GKdbus *kdbus;
+ GVariant *result;
+ GVariantBuilder *builder;
+ struct kdbus_cmd_name_list cmd = {};
+ struct kdbus_name_list *name_list;
+ struct kdbus_name_info *name;
-/**
- * g_kdbus_RequestName_handler:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_RequestName_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GDBusMessage *reply;
- GBusNameOwnerFlags flags;
- struct kdbus_cmd_name *kdbus_name;
- const gchar *name;
- guint64 kdbus_flags;
- guint64 size;
+ guint64 prev_id;
gint ret;
- gint status = G_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
-
- /* read and validate message */
- GVariant *body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "RequestName", body, G_VARIANT_TYPE("(su)")))
- return TRUE;
-
- g_variant_get (body, "(&su)", &name, &flags);
- if (!g_kdbus_check_name (worker, dbus_msg, name))
- return TRUE;
-
- if (*name == ':')
+ prev_id = 0;
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Cannot acquire a service starting with ':' such as \"%s\"", name);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_INVALID_ARGS);
- g_string_free (error_name,TRUE);
- return TRUE;
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ return NULL;
}
- g_kdbus_translate_request_name_flags (flags, &kdbus_flags);
-
- /* calculate size */
- size = sizeof(*kdbus_name) + strlen(name) + 1;
- kdbus_name = g_alloca(size);
-
- /* set message header */
- memset(kdbus_name, 0, size);
- strcpy(kdbus_name->name, name);
- kdbus_name->size = size;
- kdbus_name->flags = kdbus_flags;
+ if (list_name_type)
+ cmd.flags = KDBUS_NAME_LIST_ACTIVATORS; /* ListActivatableNames */
+ else
+ cmd.flags = KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES; /* ListNames */
- /* send message */
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_ACQUIRE, kdbus_name);
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_LIST, &cmd);
if (ret < 0)
{
- if (errno == EEXIST)
- status = G_BUS_REQUEST_NAME_REPLY_EXISTS;
- else if (errno == EALREADY)
- status = G_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
- else
- return FALSE;
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Error listing names"));
+ return NULL;
}
- if (kdbus_name->flags & KDBUS_NAME_IN_QUEUE)
- status = G_BUS_REQUEST_NAME_REPLY_IN_QUEUE;
-
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(u)",status),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-
- return TRUE;
-}
-
-
-/**
- * g_kdbus_ReleaseName_handler:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_ReleaseName_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GDBusMessage *reply;
- struct kdbus_cmd_name *kdbus_name;
- const gchar *name;
- guint64 size;
- gint ret;
- gint status = G_BUS_RELEASE_NAME_REPLY_RELEASED;
-
- /* read and validate message */
- GVariant *body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "ReleaseName", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
-
- g_variant_get (body, "(&s)", &name);
-
- if (!g_kdbus_check_name (worker, dbus_msg, name))
- return TRUE;
+ name_list = (struct kdbus_name_list *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd.offset);
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- if (*name == ':')
+ KDBUS_ITEM_FOREACH(name, name_list, names)
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Cannot release a service starting with ':' such as \"%s\"", name);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_INVALID_ARGS);
- g_string_free (error_name,TRUE);
- return TRUE;
- }
+ struct kdbus_item *item;
+ const gchar *item_name = "";
- /* calculate size */
- size = sizeof(*kdbus_name) + strlen(name) + 1;
- kdbus_name = g_alloca(size);
+ if ((cmd.flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != prev_id)
+ {
+ GString *unique_name;
- /* set message header */
- memset(kdbus_name, 0, size);
- strcpy(kdbus_name->name, name);
- kdbus_name->size = size;
+ unique_name = g_string_new (NULL);
+ g_string_printf (unique_name, ":1.%llu", name->owner_id);
+ g_variant_builder_add (builder, "s", unique_name->str);
+ g_string_free (unique_name,TRUE);
+ prev_id = name->owner_id;
+ }
- /* send message */
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_RELEASE, kdbus_name);
- if (ret < 0)
- {
- if (errno == ESRCH)
- status = G_BUS_RELEASE_NAME_REPLY_NON_EXISTENT;
- else if (errno == EADDRINUSE)
- status = G_BUS_RELEASE_NAME_REPLY_NOT_OWNER;
- else
- return FALSE;
+ KDBUS_ITEM_FOREACH(item, name, items)
+ if (item->type == KDBUS_ITEM_OWNED_NAME)
+ item_name = item->name.name;
+
+ if (g_dbus_is_name (item_name))
+ g_variant_builder_add (builder, "s", item_name);
}
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(u)",status),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
+ result = g_variant_new ("(as)", builder);
+ g_variant_builder_unref (builder);
- return TRUE;
+ g_kdbus_free_data (kdbus, cmd.offset);
+ return result;
}
/**
- * g_kdbus_ListNames_handler:
- * Returns: TRUE on success.
+ * _g_kdbus_NameHasOwner_internal:
+ *
*/
static gboolean
-g_kdbus_ListNames_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg,
- guint64 flags)
+g_kdbus_NameHasOwner_internal (GKdbus *kdbus,
+ const gchar *name,
+ GError **error)
{
- GDBusMessage *reply;
- GVariantBuilder *builder;
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_cmd_name *name;
- guint64 prev_id = 0;
+ struct kdbus_cmd_info *cmd;
+ gssize size, len;
gint ret;
- cmd.flags = flags;
-
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_LIST, &cmd);
- if (ret < 0)
- return FALSE;
-
- /* get name list */
- name_list = (struct kdbus_name_list *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd.offset);
-
- builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- KDBUS_ITEM_FOREACH(name, name_list, names)
+ if (g_dbus_is_unique_name(name))
{
- if ((flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != prev_id)
- {
- GString *unique_name = g_string_new (NULL);
-
- g_string_printf (unique_name, ":1.%llu", name->owner_id);
-
- g_variant_builder_add (builder, "s", unique_name->str);
- g_string_free (unique_name,TRUE);
- prev_id = name->owner_id;
- }
-
- if (g_dbus_is_name (name->name))
- g_variant_builder_add (builder, "s", name->name);
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
+ cmd = g_alloca0 (size);
+ cmd->id = g_ascii_strtoull (name+3, NULL, 10);
}
+ else
+ {
+ len = strlen(name) + 1;
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
+ }
+ cmd->size = size;
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(as)", builder),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
+ g_kdbus_free_data (kdbus, cmd->offset);
- g_variant_builder_unref (builder);
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &cmd.offset);
if (ret < 0)
return FALSE;
-
- return TRUE;
+ else
+ return TRUE;
}
/**
- * g_kdbus_ListQueuedOwners_handler:
- * Returns: TRUE on success.
+ * _g_kdbus_GetListQueuedOwners:
+ *
*/
-static gboolean
-g_kdbus_ListQueuedOwners_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
+GVariant *
+_g_kdbus_GetListQueuedOwners (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
{
- GDBusMessage *reply;
- GString *unique_name;
+ GKdbus *kdbus;
+ GVariant *result;
GVariantBuilder *builder;
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_cmd_name *name;
- const gchar *service;
+ GString *unique_name;
gint ret;
- /* read and validate message */
- GVariant *body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "ListQueuedOwners", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
+ struct kdbus_cmd_name_list cmd = {};
+ struct kdbus_name_list *name_list;
+ struct kdbus_name_info *kname;
- g_variant_get (body, "(&s)", &service);
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
+ {
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ return NULL;
+ }
- if (!g_kdbus_check_name (worker, dbus_msg, service))
- return TRUE;
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return NULL;
+ }
- if (!g_kdbus_NameHasOwner (kdbus, service))
+ if (!g_kdbus_NameHasOwner_internal (kdbus, name, error))
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Could not get owners of name \'%s\': no such name", service);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_NAME_HAS_NO_OWNER);
- g_string_free (error_name,TRUE);
- return TRUE;
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Could not get owner of name '%s': no such name", name);
+ return NULL;
}
- /* get queued name list */
cmd.flags = KDBUS_NAME_LIST_QUEUED;
-
ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_LIST, &cmd);
if (ret < 0)
- return FALSE;
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Error listing names"));
+ return NULL;
+ }
name_list = (struct kdbus_name_list *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd.offset);
unique_name = g_string_new (NULL);
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- KDBUS_ITEM_FOREACH(name, name_list, names)
+ KDBUS_ITEM_FOREACH(kname, name_list, names)
{
- if (name->size <= sizeof(*name))
- continue;
+ struct kdbus_item *item;
+ const char *item_name = "";
- if (strcmp(name->name, service))
- continue;
+ KDBUS_ITEM_FOREACH(item, kname, items)
+ if (item->type == KDBUS_ITEM_NAME)
+ item_name = item->str;
- g_string_printf (unique_name, ":1.%llu", name->owner_id);
- g_variant_builder_add (builder, "s", unique_name);
+ if (strcmp(item_name, name))
+ continue;
+ g_string_printf (unique_name, ":1.%llu", kname->owner_id);
+ g_variant_builder_add (builder, "s", item_name);
}
- /* generate reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(as)", builder),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-
+ result = g_variant_new ("(as)", builder);
g_variant_builder_unref (builder);
g_string_free (unique_name,TRUE);
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &cmd.offset);
- if (ret < 0)
- return FALSE;
-
- return TRUE;
+ g_kdbus_free_data (kdbus, cmd.offset);
+ return result;
}
/**
- * g_kdbus_GetOwner_handler:
- * Returns: TRUE on success.
+ * g_kdbus_GetConnInfo_internal:
+ *
*/
-static gboolean
-g_kdbus_GetOwner_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg,
- guint64 flag)
+static GVariant *
+g_kdbus_GetConnInfo_internal (GDBusConnection *connection,
+ const gchar *name,
+ guint64 flag,
+ GError **error)
{
- GVariant *result = NULL;
- GDBusMessage *reply;
- struct kdbus_cmd_conn_info *cmd;
- struct kdbus_conn_info *conn_info;
+ GKdbus *kdbus;
+ GVariant *result;
+
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_info *conn_info;
struct kdbus_item *item;
- const gchar *name;
- gssize size;
+ gssize size, len;
gint ret;
- /* read and validate message */
- GVariant *body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "GetOwner", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
+ result = NULL;
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ if (kdbus == NULL)
+ {
+ g_set_error_literal (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_IO_ERROR,
+ _("The connection is closed"));
+ return NULL;
+ }
- g_variant_get (body, "(&s)", &name);
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return NULL;
+ }
- if (!g_kdbus_check_name (worker, dbus_msg, name))
- return TRUE;
+ if (!g_kdbus_NameHasOwner_internal (kdbus, name, error))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Could not get owner of name '%s': no such name", name);
+ return NULL;
+ }
- /* setup kmsg for ioctl */
if (g_dbus_is_unique_name(name))
{
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, name);
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
cmd = g_alloca0 (size);
- cmd->id = g_ascii_strtoull (name+3,NULL,10);
+ cmd->id = g_ascii_strtoull (name+3, NULL, 10);
}
else
{
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, name) + strlen(name) + 1;
+ len = strlen(name) + 1;
+ size = G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
cmd = g_alloca0 (size);
- strcpy(cmd->name, name);
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
}
- cmd->flags = KDBUS_ATTACH_NAMES;
+ cmd->flags = _KDBUS_ATTACH_ALL;
cmd->size = size;
- /* get info about connection */
ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
if (ret < 0)
{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Could not get owners of name \'%s\': no such name", name);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_NAME_HAS_NO_OWNER);
- g_string_free (error_name, TRUE);
- return TRUE;
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Could not get connection info"));
+ return NULL;
}
- conn_info = (struct kdbus_conn_info *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd->offset);
+ conn_info = (struct kdbus_info *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd->offset);
+ /*
if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
- return FALSE;
+ {}
+ */
if (flag == G_BUS_CREDS_UNIQUE_NAME)
{
- GString *unique_name = g_string_new (NULL);
+ GString *unique_name;
+ unique_name = g_string_new (NULL);
g_string_printf (unique_name, ":1.%llu", (unsigned long long) conn_info->id);
-
- result = g_variant_new ("(s)", unique_name);
+ result = g_variant_new ("(s)", unique_name->str);
g_string_free (unique_name,TRUE);
- goto send_reply;
+ goto exit;
}
- /* read creds info */
KDBUS_ITEM_FOREACH(item, conn_info, items)
{
-
switch (item->type)
{
-
- case KDBUS_ITEM_CREDS:
+ case KDBUS_ITEM_PIDS:
if (flag == G_BUS_CREDS_PID)
{
- guint pid = item->creds.pid;
+ guint pid = item->pids.pid;
result = g_variant_new ("(u)", pid);
- goto send_reply;
+ goto exit;
}
+ case KDBUS_ITEM_CREDS:
+
if (flag == G_BUS_CREDS_UID)
{
guint uid = item->creds.uid;
result = g_variant_new ("(u)", uid);
- goto send_reply;
+ goto exit;
}
case KDBUS_ITEM_SECLABEL:
- if (flag == G_BUS_CREDS_SELINUX_CONTEXT)
- {
- gint counter;
- gchar *label;
- GVariantBuilder *builder = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
-
- label = g_strdup (item->str);
- if (!label)
- goto exit;
-
- for (counter = 0 ; counter < strlen (label) ; counter++)
- {
- g_variant_builder_add (builder, "y", label);
- label++;
- }
-
- result = g_variant_new ("(ay)", builder);
- g_variant_builder_unref (builder);
- g_free (label);
- goto send_reply;
-
- }
- break;
-
case KDBUS_ITEM_PID_COMM:
case KDBUS_ITEM_TID_COMM:
case KDBUS_ITEM_EXE:
case KDBUS_ITEM_CMDLINE:
case KDBUS_ITEM_CGROUP:
case KDBUS_ITEM_CAPS:
- case KDBUS_ITEM_NAME:
case KDBUS_ITEM_AUDIT:
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ case KDBUS_ITEM_AUXGROUPS:
+ case KDBUS_ITEM_OWNED_NAME:
break;
-
}
}
-send_reply:
- if (result == NULL)
- goto exit;
-
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- result,
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-
exit:
- ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &cmd->offset);
- return TRUE;
-
-}
-
-
-/**
- * g_kdbus_NameHasOwner_handler:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_NameHasOwner_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GDBusMessage *reply;
- GVariant *result = NULL;
- const gchar *name;
-
- /* read and validate message */
- GVariant *body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "NameHasOwner", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
-
- g_variant_get (body, "(&s)", &name);
-
- if (!g_kdbus_check_name (worker, dbus_msg, name))
- return TRUE;
-
- /* check whether name has owner */
- if (!g_kdbus_NameHasOwner (kdbus, name))
- result = g_variant_new ("(b)", FALSE);
- else
- result = g_variant_new ("(b)", TRUE);
-
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- result,
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
- return TRUE;
-}
-
-
-/**
- * g_kdbus_GetId_handler:
- * Returns: TRUE on success.
- */
-static gboolean
-g_kdbus_GetId_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GDBusMessage *reply;
- GString *result = g_string_new (NULL);
- gint i;
-
- for (i=0; i<16; i++)
- g_string_append_printf (result, "%02x", kdbus->priv->bus_id[i]);
-
- /* generate local reply */
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(s)", result->str),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
-
- g_string_free (result,TRUE);
- return TRUE;
-}
-
-
-/**
- * g_kdbus_StartServiceByName_handler:
- * Returns: TRUE on success.
- *
- */
-static gboolean
-g_kdbus_StartServiceByName_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GDBusMessage *reply;
- GVariant *body;
- const gchar *name;
- guint64 flags;
-
- body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "StartServiceByName", body, G_VARIANT_TYPE("(su)")))
- return TRUE;
-
- g_variant_get (body, "(&su)", &name, &flags);
-
- if (!g_kdbus_check_name (worker, dbus_msg, name))
- return TRUE;
-
- if (g_kdbus_NameHasOwner (kdbus, name))
- {
- reply = g_kdbus_generate_local_reply (dbus_msg,
- G_DBUS_MESSAGE_TYPE_METHOD_RETURN,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- g_dbus_message_get_serial (dbus_msg),
- g_variant_new ("(u)", G_BUS_START_REPLY_ALREADY_RUNNING),
- NULL);
- _g_dbus_worker_queue_or_deliver_received_message (worker, reply);
- return TRUE;
- }
-
- /* TODO */
- g_error ("[KDBUS] StartServiceByName method is not implemented yet");
-
- return TRUE;
+ g_kdbus_free_data (kdbus, cmd->offset);
+ return result;
}
/**
- * g_kdbus_AddMatch_handler:
- * Returns: TRUE on success.
+ * _g_kdbus_GetNameOwner:
*
*/
-static gboolean
-g_kdbus_AddMatch_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GVariant *body;
- const gchar *rule;
-
- body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "AddMatch", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
-
- g_variant_get (body, "(&s)", &rule);
-
- /* TODO */
- g_error ("[KDBUS] AddMatch method is not implemented yet");
-
- return TRUE;
+GVariant *
+_g_kdbus_GetNameOwner (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ return g_kdbus_GetConnInfo_internal (connection,
+ name,
+ G_BUS_CREDS_UNIQUE_NAME,
+ error);
}
/**
- * g_kdbus_RemoveMatch_handler:
- * Returns: TRUE on success.
- *
- */
-static gboolean
-g_kdbus_RemoveMatch_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
-{
- GVariant *body;
- const gchar *rule;
-
- body = g_dbus_message_get_body (dbus_msg);
-
- if (!g_kdbus_check_signature (worker, dbus_msg, "RemoveMatch", body, G_VARIANT_TYPE("(s)")))
- return TRUE;
-
- g_variant_get (body, "(&s)", &rule);
-
- /* TODO */
- g_error ("[KDBUS] RemoveMatch method is not implemented yet");
-
- return TRUE;
+ * _g_kdbus_GetConnectionUnixProcessID:
+ *
+ */
+GVariant *
+_g_kdbus_GetConnectionUnixProcessID (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ return g_kdbus_GetConnInfo_internal (connection,
+ name,
+ G_BUS_CREDS_PID,
+ error);
}
/**
- * g_kdbus_UnsupportedMethod_handler:
- * Returns: TRUE on success.
+ * _g_kdbus_GetConnectionUnixUser:
+ *
*/
-static gboolean
-g_kdbus_UnsupportedMethod_handler (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg,
- const gchar *method_name)
-{
- GString *error_name = g_string_new (NULL);
- g_string_printf (error_name, "Method \"%s\" is not supported", method_name);
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_UNKNOWN_METHOD);
- g_string_free (error_name,TRUE);
- return TRUE;
+GVariant *
+_g_kdbus_GetConnectionUnixUser (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ return g_kdbus_GetConnInfo_internal (connection,
+ name,
+ G_BUS_CREDS_UID,
+ error);
}
/**
- * g_kdbus_bus_driver:
+ * _g_kdbus_match_remove:
*
*/
-static gboolean
-g_kdbus_bus_driver (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg)
+static void
+_g_kdbus_match_remove (GDBusConnection *connection,
+ guint cookie)
{
- gboolean ret = FALSE;
-
- /* Hello */
- if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "Hello") == 0)
- {
- g_kdbus_take_fd (kdbus);
- ret = g_kdbus_Hello_reply (worker, kdbus, dbus_msg);
- }
-
- /* RequestName and ReleaseName */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "RequestName") == 0)
- ret = g_kdbus_RequestName_handler (worker, kdbus, dbus_msg);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "ReleaseName") == 0)
- ret = g_kdbus_ReleaseName_handler (worker, kdbus, dbus_msg);
-
- /* All List* Methods */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "ListNames") == 0)
- ret = g_kdbus_ListNames_handler (worker, kdbus, dbus_msg, KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "ListActivatableNames") == 0)
- ret = g_kdbus_ListNames_handler (worker, kdbus, dbus_msg, KDBUS_NAME_LIST_ACTIVATORS);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "ListQueuedOwners") == 0)
- ret = g_kdbus_ListQueuedOwners_handler (worker, kdbus, dbus_msg);
-
- /* All Get* Methods */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "GetNameOwner") == 0)
- ret = g_kdbus_GetOwner_handler (worker, kdbus, dbus_msg, G_BUS_CREDS_UNIQUE_NAME);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "GetConnectionUnixProcessID") == 0)
- ret = g_kdbus_GetOwner_handler (worker, kdbus, dbus_msg, G_BUS_CREDS_PID);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "GetConnectionUnixUser") == 0)
- ret = g_kdbus_GetOwner_handler (worker, kdbus, dbus_msg, G_BUS_CREDS_UID);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "GetConnectionSELinuxSecurityContext") == 0)
- ret = g_kdbus_GetOwner_handler (worker, kdbus, dbus_msg, G_BUS_CREDS_SELINUX_CONTEXT);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "GetId") == 0)
- ret = g_kdbus_GetId_handler (worker, kdbus, dbus_msg);
-
- /* NameHasOwner nad StartServiceByName methods */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "NameHasOwner") == 0)
- ret = g_kdbus_NameHasOwner_handler (worker, kdbus, dbus_msg);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "StartServiceByName") == 0)
- ret = g_kdbus_StartServiceByName_handler (worker, kdbus, dbus_msg);
-
- /* AddMatch and RemoveMatch */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "AddMatch") == 0)
- ret = g_kdbus_AddMatch_handler (worker, kdbus, dbus_msg);
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "RemoveMatch") == 0)
- ret = g_kdbus_RemoveMatch_handler (worker, kdbus, dbus_msg);
-
- /* Unsupported Methods */
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "ReloadConfig") == 0)
- ret = g_kdbus_UnsupportedMethod_handler (worker, kdbus, dbus_msg, "ReloadConfig");
- else if (g_strcmp0(g_dbus_message_get_member(dbus_msg), "UpdateActivationEnvironment") == 0)
- ret = g_kdbus_UnsupportedMethod_handler (worker, kdbus, dbus_msg, "UpdateActivationEnvironment");
-
- else
- {
- GString *error_name;
+ GKdbus *kdbus;
+ struct kdbus_cmd_match cmd_match = {};
+ gint ret;
- error_name = g_string_new (NULL);
- g_string_printf (error_name, "org.freedesktop.DBus does not understand message %s", g_dbus_message_get_member(dbus_msg));
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
- g_kdbus_generate_local_error (worker,
- dbus_msg,
- g_variant_new ("(s)",error_name->str),
- G_DBUS_ERROR_UNKNOWN_METHOD);
- g_string_free (error_name,TRUE);
- }
+ cmd_match.size = sizeof (cmd_match);
+ cmd_match.cookie = cookie;
- return ret;
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_MATCH_REMOVE, &cmd_match);
+ if (ret < 0)
+ g_warning ("ERROR - %d\n", (int) errno);
}
/**
- * g_kdbus_alloc_memfd:
+ * _g_kdbus_subscribe_name_acquired:
*
*/
-static gboolean
-g_kdbus_alloc_memfd (GKdbus *kdbus)
+static void
+_g_kdbus_subscribe_name_owner_changed (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name,
+ guint cookie)
{
- struct kdbus_cmd_memfd_make *memfd;
+ GKdbus *kdbus;
struct kdbus_item *item;
- gssize size;
- gchar *name = "gdbus-memfd";
+ struct kdbus_cmd_match *cmd_match;
+ gssize size, len;
+ gint ret;
+ guint64 old_id = 0; /* XXX why? */
+ guint64 new_id = KDBUS_MATCH_ID_ANY;
- size = ALIGN8(G_STRUCT_OFFSET(struct kdbus_cmd_memfd_make, items)) +
- ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, str)) +
- strlen(name) + 1;
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
- memfd = g_alloca0 (size);
- memfd->size = size;
+ len = strlen(name) + 1;
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
- item = memfd->items;
- item->size = ALIGN8(offsetof(struct kdbus_item, str)) + strlen(name) + 1;
- item->type = KDBUS_ITEM_MEMFD_NAME;
- memcpy(item->str, name, strlen(name) + 1);
+ cmd_match = g_alloca0 (size);
+ cmd_match->size = size;
+ cmd_match->cookie = cookie;
+ item = cmd_match->items;
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_MEMFD_NEW, memfd) < 0)
- return FALSE;
+ if (old_name[0] == 0)
+ {
+ old_id = KDBUS_MATCH_ID_ANY;
+ }
+ else
+ {
+ if (g_dbus_is_unique_name(old_name))
+ old_id = old_id+3;
+ else
+ return;
+ }
- kdbus->priv->memfd = memfd->fd;
+ if (new_name[0] == 0)
+ {
+ new_id = KDBUS_MATCH_ID_ANY;
+ }
+ else
+ {
+ if (g_dbus_is_unique_name(new_name))
+ new_id = new_id+3;
+ else
+ return;
+ }
- return TRUE;
+ cmd_match = g_alloca0 (size);
+ cmd_match->size = size;
+ cmd_match->cookie = cookie;
+ item = cmd_match->items;
+
+ /* KDBUS_ITEM_NAME_CHANGE */
+ item->type = KDBUS_ITEM_NAME_CHANGE;
+ item->name_change.old_id.id = old_id;
+ item->name_change.new_id.id = new_id;
+ memcpy(item->name_change.name, name, len);
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_MATCH_ADD, cmd_match);
+ if (ret < 0)
+ g_warning ("ERROR - %d\n", (int) errno);
}
/**
- * _g_kdbus_release_msg:
- * Release memory occupied by kdbus_msg.
- * Use after DBUS message is extracted.
+ * _g_kdbus_subscribe_name_acquired:
+ *
*/
void
-_g_kdbus_release_kmsg (GKdbus *kdbus)
+_g_kdbus_subscribe_name_acquired (GDBusConnection *connection,
+ const gchar *name)
{
- struct kdbus_item *item = NULL;
- GSList *iterator = NULL;
- guint64 offset;
-
- offset = (guint8 *)kdbus->priv->kmsg - (guint8 *)kdbus->priv->kdbus_buffer;
- ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &offset);
-
- for (iterator = kdbus->priv->kdbus_msg_items; iterator; iterator = iterator->next)
- g_free ((msg_part*)iterator->data);
+ GKdbus *kdbus;
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd_match;
+ gssize size, len;
+ guint64 cookie;
+ gint ret;
- g_slist_free (kdbus->priv->kdbus_msg_items);
- kdbus->priv->kdbus_msg_items = NULL;
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+
+ len = strlen(name) + 1;
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cookie = 0xbeefbeefbeefbeef;
+ cmd_match = g_alloca0 (size);
+ cmd_match->size = size;
+ cmd_match->cookie = cookie;
+ item = cmd_match->items;
+
+ /* KDBUS_ITEM_NAME_ADD */
+ item->type = KDBUS_ITEM_NAME_ADD;
+ item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+ item->name_change.new_id.id = kdbus->priv->unique_id;
+ memcpy(item->name_change.name, name, len);
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
- KDBUS_ITEM_FOREACH (item, kdbus->priv->kmsg, items)
- {
- if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD)
- close(item->memfd.fd);
- else if (item->type == KDBUS_ITEM_FDS)
- {
- gint i;
- gint num_fds = (item->size - G_STRUCT_OFFSET(struct kdbus_item, fds)) / sizeof(int);
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_MATCH_ADD, cmd_match);
+ if (ret < 0)
+ g_warning ("ERROR - %d\n", (int) errno);
- for (i = 0; i < num_fds; i++)
- close(item->fds[i]);
- }
- }
+ _g_kdbus_subscribe_name_owner_changed (connection, name, "", kdbus->priv->unique_name, cookie);
}
/**
- * g_kdbus_append_payload_vec:
+ * _g_kdbus_subscribe_name_lost:
*
*/
-static void
-g_kdbus_append_payload_vec (struct kdbus_item **item,
- const void *data_ptr,
- gssize size)
+void
+_g_kdbus_subscribe_name_lost (GDBusConnection *connection,
+ const gchar *name)
{
- *item = ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, vec) + sizeof(struct kdbus_vec);
- (*item)->type = KDBUS_ITEM_PAYLOAD_VEC;
- (*item)->vec.address = (guint64)((guintptr)data_ptr);
- (*item)->vec.size = size;
- *item = KDBUS_ITEM_NEXT(*item);
+ GKdbus *kdbus;
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd_match;
+ gssize size, len;
+ guint64 cookie;
+ gint ret;
+
+ kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+
+ len = strlen(name) + 1;
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cookie = 0xdeafdeafdeafdeaf;
+ cmd_match = g_alloca0 (size);
+ cmd_match->size = size;
+ cmd_match->cookie = cookie;
+ item = cmd_match->items;
+
+ /* KDBUS_ITEM_NAME_REMOVE */
+ item->type = KDBUS_ITEM_NAME_REMOVE;
+ item->name_change.old_id.id = kdbus->priv->unique_id;
+ item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
+ memcpy(item->name_change.name, name, len);
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(kdbus->priv->fd, KDBUS_CMD_MATCH_ADD, cmd_match);
+ if (ret < 0)
+ g_warning ("ERROR - %d\n", (int) errno);
+
+ _g_kdbus_subscribe_name_owner_changed (connection, name, kdbus->priv->unique_name, "", cookie);
}
/**
- * g_kdbus_append_payload_memfd:
+ * _g_kdbus_unsubscribe_name_acquired:
*
*/
-static void
-g_kdbus_append_payload_memfd (struct kdbus_item **item,
- int fd,
- gssize size)
+void
+_g_kdbus_unsubscribe_name_acquired (GDBusConnection *connection)
{
- *item = ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
- (*item)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
- (*item)->memfd.fd = fd;
- (*item)->memfd.size = size;
- *item = KDBUS_ITEM_NEXT(*item);
+ guint64 cookie;
+
+ cookie = 0xbeefbeefbeefbeef;
+ _g_kdbus_match_remove (connection, cookie);
}
/**
- * g_kdbus_append_payload_destiantion:
+ * _g_kdbus_unsubscribe_name_lost:
*
*/
-static void
-g_kdbus_append_destination (struct kdbus_item **item,
- const gchar *destination,
- gsize size)
+void
+_g_kdbus_unsubscribe_name_lost (GDBusConnection *connection)
{
- *item = ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, str) + size + 1;
- (*item)->type = KDBUS_ITEM_DST_NAME;
- memcpy ((*item)->str, destination, size+1);
- *item = KDBUS_ITEM_NEXT(*item);
+ guint64 cookie;
+
+ cookie = 0xdeafdeafdeafdeaf;
+ _g_kdbus_match_remove (connection, cookie);
}
{
struct kdbus_item *bloom_item;
- bloom_item = ALIGN8_PTR(*item);
+ bloom_item = KDBUS_ALIGN8_PTR(*item);
bloom_item->size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
size;
/**
- * g_kdbus_append_fds:
- *
- */
-static void
-g_kdbus_append_fds (struct kdbus_item **item,
- GUnixFDList *fd_list)
-{
- *item = ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list);
- (*item)->type = KDBUS_ITEM_FDS;
- memcpy ((*item)->fds, g_unix_fd_list_peek_fds(fd_list, NULL), sizeof(int) * g_unix_fd_list_get_length(fd_list));
-
- *item = KDBUS_ITEM_NEXT(*item);
-}
-
-
-/**
- * _g_kdbus_attach_fds_to_msg:
- *
- */
-void
-_g_kdbus_attach_fds_to_msg (GKdbus *kdbus,
- GUnixFDList **fd_list)
-{
- if ((kdbus->priv->fds != NULL) && (kdbus->priv->num_fds > 0))
- {
- gint n;
-
- if (*fd_list == NULL)
- *fd_list = g_unix_fd_list_new();
-
- for (n = 0; n < kdbus->priv->num_fds; n++)
- {
- g_unix_fd_list_append (*fd_list, kdbus->priv->fds[n], NULL);
- (void) g_close (kdbus->priv->fds[n], NULL);
- }
-
- g_free (kdbus->priv->fds);
- kdbus->priv->fds = NULL;
- kdbus->priv->num_fds = 0;
- }
-}
-
-
-/**
* g_kdbus_bloom_add_data:
* Based on bus-bloom.c from systemd
* http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
}
-/**
- * g_kdbus_NameOwnerChanged_generate:
- * TODO: Not tesed yet
- */
-static gssize
-g_kdbus_NameOwnerChanged_generate (GKdbus *kdbus,
- struct kdbus_item *item)
-{
- GVariant *result = NULL;
- GDBusMessage *reply;
- GError *error;
- guchar *blob;
- gssize reply_size = 0;
-
- gchar *owner;
- gchar *old_owner;
- gchar *new_owner;
-
- /* ID change */
- if (item->type == KDBUS_ITEM_ID_ADD || item->type == KDBUS_ITEM_ID_REMOVE)
- {
- owner = "";
-
- if (item->type == KDBUS_ITEM_ID_ADD)
- {
- old_owner = NULL;
- new_owner = owner;
- }
- else
- {
- old_owner = owner;
- new_owner = NULL;
- }
- }
-
- /* name change */
- if (item->type == KDBUS_ITEM_NAME_ADD ||
- item->type == KDBUS_ITEM_NAME_REMOVE ||
- item->type == KDBUS_ITEM_NAME_CHANGE )
- {
- g_error ("[KDBUS] 'NameChange' is not implemented yet");
- }
-
- result = g_variant_new ("(sss)", owner, old_owner, new_owner);
- reply = g_kdbus_generate_local_reply (NULL,
- G_DBUS_MESSAGE_TYPE_SIGNAL,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- -1,
- result,
- NULL);
-
- //_g_dbus_message_set_protocol_ver (reply,2);
- blob = g_dbus_message_to_blob (reply, (gsize*) &reply_size, 0, &error);
- if (blob == NULL)
-
- g_error ("[KDBUS] NameOwnerChanged: %s\n",error->message);
-
- ((guint32 *) blob)[2] = GUINT32_TO_LE (-1);
- g_kdbus_add_msg_part (kdbus, (gchar*)blob, reply_size);
-
- return reply_size;
-
-}
-
-
-/**
- * g_kdbus_KernelMethodError_generate:
- *
+/*
+ * TODO: g_kdbus_NameOwnerChanged_generate, g_kdbus_KernelMethodError_generate
*/
-static gssize
-g_kdbus_KernelMethodError_generate (GKdbus *kdbus,
- struct kdbus_item *item)
-{
- GVariant *error_name;
- GDBusMessage *reply;
- GError *error;
- guchar *blob;
- gssize reply_size = 0;
-
- if (item->type == KDBUS_ITEM_REPLY_TIMEOUT)
- error_name = g_variant_new ("(s)", "Method call timed out");
- else
- error_name = g_variant_new ("(s)", "Method call peer died");
-
- error = NULL;
- reply = g_kdbus_generate_local_reply (NULL,
- G_DBUS_MESSAGE_TYPE_ERROR,
- G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED,
- -1,
- error_name,
- "org.freedesktop.DBus.Error.NoReply");
-
- //_g_dbus_message_set_protocol_ver (reply,2);
- blob = g_dbus_message_to_blob (reply, (gsize*) &reply_size, 0, &error);
-
- if (blob == NULL)
- g_error ("[KDBUS] KernelMethodError: %s\n",error->message);
-
- ((guint32 *) blob)[2] = GUINT32_TO_LE (-1);
- g_kdbus_add_msg_part (kdbus, (gchar*)blob, reply_size);
-
- return reply_size;
-}
-
/**
* g_kdbus_decode_kernel_msg:
*
*/
-static gssize
-g_kdbus_decode_kernel_msg (GKdbus *kdbus)
+static void
+g_kdbus_decode_kernel_msg (GKdbus *kdbus,
+ struct kdbus_msg *msg)
{
struct kdbus_item *item = NULL;
- gssize size = 0;
- KDBUS_ITEM_FOREACH(item, kdbus->priv->kmsg, items)
+ KDBUS_ITEM_FOREACH(item, msg, items)
{
- switch (item->type)
+ switch (item->type)
{
case KDBUS_ITEM_ID_ADD:
case KDBUS_ITEM_ID_REMOVE:
case KDBUS_ITEM_NAME_ADD:
case KDBUS_ITEM_NAME_REMOVE:
case KDBUS_ITEM_NAME_CHANGE:
- size = g_kdbus_NameOwnerChanged_generate (kdbus, item);
+ //size = g_kdbus_NameOwnerChanged_generate (kdbus, item);
+ g_error ("'NameOwnerChanged'");
break;
case KDBUS_ITEM_REPLY_TIMEOUT:
case KDBUS_ITEM_REPLY_DEAD:
- size = g_kdbus_KernelMethodError_generate (kdbus, item);
+ //size = g_kdbus_KernelMethodError_generate (kdbus, item);
+ g_error ("'KernelMethodError'");
break;
default:
- g_error ("[KDBUS] KERNEL: Unknown filed - %lld", item->type);
- }
+ g_warning ("Unknown field in kernel message - %lld", item->type);
+ }
}
+#if 0
/* Override information from the user header with data from the kernel */
g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_NAME)
g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id);
else
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
-
+ g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
return size;
+#endif
}
* g_kdbus_decode_dbus_msg:
*
*/
-static gssize
-g_kdbus_decode_dbus_msg (GKdbus *kdbus)
+static GDBusMessage *
+g_kdbus_decode_dbus_msg (GKdbus *kdbus,
+ struct kdbus_msg *msg)
{
+ GDBusMessage *message;
struct kdbus_item *item;
- gchar *msg_ptr;
- gssize ret_size = 0;
gssize data_size = 0;
- const gchar *destination = NULL;
+ GArray *body_vectors;
+ gsize body_size;
+ GVariant *body;
+ gchar *tmp;
+ guint i;
+
+ message = g_dbus_message_new ();
+
+ tmp = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
+ g_dbus_message_set_sender (message, tmp);
+ g_free (tmp);
+
+ body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
+ body_size = 0;
- KDBUS_ITEM_FOREACH(item, kdbus->priv->kmsg, items)
+ KDBUS_ITEM_FOREACH(item, msg, items)
{
if (item->size <= KDBUS_ITEM_HEADER_SIZE)
g_error("[KDBUS] %llu bytes - invalid data record\n", item->size);
switch (item->type)
{
-
/* KDBUS_ITEM_DST_NAME */
case KDBUS_ITEM_DST_NAME:
- destination = item->str;
+ /* Classic D-Bus doesn't make this known to the receiver, so
+ * we don't do it here either (for compatibility with the
+ * fallback case).
+ */
break;
/* KDBUS_ITEM_PALOAD_OFF */
case KDBUS_ITEM_PAYLOAD_OFF:
-
- msg_ptr = (gchar*) kdbus->priv->kmsg + item->vec.offset;
- g_kdbus_add_msg_part (kdbus, msg_ptr, item->vec.size);
- ret_size += item->vec.size;
-
+ {
+ GVariantVector vector;
+ gsize flavour;
+
+ /* We want to make sure the bytes are aligned the same as
+ * they would be if they appeared in a contiguously
+ * allocated chunk of aligned memory.
+ *
+ * We decide what the alignment 'should' be by consulting
+ * body_size, which has been tracking the total size of the
+ * message up to this point.
+ *
+ * We then play around with the pointer by removing as many
+ * bytes as required to get it to the proper alignment (and
+ * copy extra bytes accordingly). This means that we will
+ * grab some extra data in the 'bytes', but it won't be
+ * shared with GVariant (which means there is no chance of
+ * it being accidentally retransmitted).
+ *
+ * The kernel does the same thing, so make sure we get the
+ * expected result. Because of the kernel doing the same,
+ * the result is that we will always be rounding-down to a
+ * multiple of 8 for the pointer, which means that the
+ * pointer will always be valid, assuming the original
+ * address was.
+ *
+ * We could fix this with a new GBytes constructor that took
+ * 'flavour' as a parameter, but it's not worth it...
+ */
+ flavour = body_size & 7;
+ //g_assert ((item->vec.offset & 7) == flavour); FIXME: kdbus bug doesn't count memfd in flavouring
+
+ vector.gbytes = g_bytes_new (((guchar *) msg) + item->vec.offset - flavour, item->vec.size + flavour);
+ vector.data.pointer = g_bytes_get_data (vector.gbytes, NULL);
+ vector.data.pointer += flavour;
+ vector.size = item->vec.size;
+
+ g_array_append_val (body_vectors, vector);
+ body_size += vector.size;
+ }
break;
/* KDBUS_ITEM_PAYLOAD_MEMFD */
case KDBUS_ITEM_PAYLOAD_MEMFD:
+ {
+ GVariantVector vector;
- msg_ptr = mmap(NULL, item->memfd.size, PROT_READ, MAP_SHARED, item->memfd.fd, 0);
-
- if (msg_ptr == MAP_FAILED)
- {
- g_print ("mmap() fd=%i failed:%m", item->memfd.fd);
- break;
- }
-
- g_kdbus_add_msg_part (kdbus, msg_ptr, item->memfd.size);
- ret_size += item->memfd.size;
+ vector.gbytes = g_bytes_new_take_zero_copy_fd (item->memfd.fd);
+ vector.data.pointer = g_bytes_get_data (vector.gbytes, &vector.size);
+ g_print ("GB was %p/%d\n", vector.data.pointer, (guint) vector.size);
+ g_array_append_val (body_vectors, vector);
+ body_size += vector.size;
+ }
break;
/* KDBUS_ITEM_FDS */
case KDBUS_ITEM_FDS:
+ {
+ GUnixFDList *fd_list;
- kdbus->priv->num_fds = data_size / sizeof(int);
- kdbus->priv->fds = g_malloc0 (sizeof(int) * kdbus->priv->num_fds);
- memcpy(kdbus->priv->fds, item->fds, sizeof(int) * kdbus->priv->num_fds);
-
+ fd_list = g_unix_fd_list_new_from_array (item->fds, data_size / sizeof (int));
+ g_dbus_message_set_unix_fd_list (message, fd_list);
+ g_object_unref (fd_list);
+ }
break;
/* All of the following items, like CMDLINE,
CGROUP, etc. need some GDBUS API extensions and
should be implemented in the future */
- case KDBUS_ITEM_CREDS:
case KDBUS_ITEM_TIMESTAMP:
+ {
+ g_print ("time: seq %llu mon %llu real %llu\n",
+ item->timestamp.seqnum, item->timestamp.monotonic_ns, item->timestamp.realtime_ns);
+ //g_dbus_message_set_timestamp (message, item->timestamp.monotonic_ns / 1000);
+ //g_dbus_message_set_serial (message, item->timestamp.seqnum);
+ break;
+ }
+
+ case KDBUS_ITEM_CREDS:
+ {
+ g_print ("creds: u%u eu %u su%u fsu%u g%u eg%u sg%u fsg%u\n",
+ item->creds.uid, item->creds.euid, item->creds.suid, item->creds.fsuid,
+ item->creds.gid, item->creds.egid, item->creds.sgid, item->creds.fsgid);
+ break;
+ }
+
+ case KDBUS_ITEM_PIDS:
case KDBUS_ITEM_PID_COMM:
case KDBUS_ITEM_TID_COMM:
case KDBUS_ITEM_EXE:
case KDBUS_ITEM_AUDIT:
case KDBUS_ITEM_CAPS:
case KDBUS_ITEM_SECLABEL:
- case KDBUS_ITEM_CONN_NAME:
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ case KDBUS_ITEM_AUXGROUPS:
+ case KDBUS_ITEM_OWNED_NAME:
case KDBUS_ITEM_NAME:
+ g_print ("unhandled %04x\n", (int) item->type);
break;
default:
}
}
- /* Override information from the user header with data from the kernel */
+ body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("(ssa{sv})"),
+ (GVariantVector *) body_vectors->data,
+ body_vectors->len, body_size, FALSE);
+ g_assert (body);
- if (kdbus->priv->kmsg->src_id == KDBUS_SRC_ID_KERNEL)
- g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
- else
- g_string_printf (kdbus->priv->msg_sender, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->src_id);
+ for (i = 0; i < body_vectors->len; i++)
+ g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes);
- if (destination)
- g_string_printf (kdbus->priv->msg_destination, "%s", destination);
- else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_BROADCAST)
- /* for broadcast messages we don't have to set destination */
- ;
- else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_NAME)
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id);
- else
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
+ g_array_free (body_vectors, TRUE);
+
+ g_dbus_message_set_body (message, body);
+ g_variant_unref (body);
- return ret_size;
+ return message;
}
GError **error)
{
struct kdbus_cmd_recv recv = {};
- gssize size = 0;
+ struct kdbus_msg *msg;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1;
- again:
+again:
if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RECV, &recv) < 0)
{
if (errno == EINTR || errno == EAGAIN)
goto again;
- g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno),_("Error receiving message - KDBUS_CMD_MSG_RECV error"));
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error while receiving message: %s"),
+ g_strerror (errno));
return -1;
}
- kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
+ msg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
- if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS)
- size = g_kdbus_decode_dbus_msg (kdbus);
- else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL)
- size = g_kdbus_decode_kernel_msg (kdbus);
- else
- g_error ("[KDBUS] Unknown payload type: %llu", kdbus->priv->kmsg->payload_type);
+ if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
+ g_kdbus_decode_dbus_msg (kdbus, msg);
+ else if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
+ g_kdbus_decode_kernel_msg (kdbus, msg);
+ else
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Received unknown payload type"));
+ return -1;
+ }
+
+ ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &recv.offset);
+
+ return 0;
+}
+
+struct dbus_fixed_header {
+ guint8 endian;
+ guint8 type;
+ guint8 flags;
+ guint8 version;
+ guint32 reserved;
+ guint64 serial;
+};
+
+#define DBUS_FIXED_HEADER_TYPE ((const GVariantType *) "(yyyyut)")
+#define DBUS_EXTENDED_HEADER_TYPE ((const GVariantType *) "a{tv}")
+#define DBUS_MESSAGE_TYPE ((const GVariantType *) "((yyyyut)a{tv}v)")
+
+#define KDBUS_MSG_MAX_SIZE 8192
+
+static gboolean
+g_kdbus_msg_append_item (struct kdbus_msg *msg,
+ gsize type,
+ gconstpointer data,
+ gsize size)
+{
+ struct kdbus_item *item;
+ gsize item_size;
+
+ item_size = size + sizeof (struct kdbus_item);
- return size;
+ if (msg->size + item_size > KDBUS_MSG_MAX_SIZE)
+ return FALSE;
+
+ item = (struct kdbus_item *) ((guchar *) msg) + msg->size;
+ item->type = type;
+ item->size = item_size;
+ memcpy (item->data, data, size);
+
+ msg->size += (item_size + 7) & ~7ull;
+
+ return TRUE;
+}
+
+static gboolean
+g_kdbus_msg_append_payload_vec (struct kdbus_msg *msg,
+ gconstpointer data,
+ gsize size)
+{
+ struct kdbus_vec vec = {
+ .size = size,
+ .address = (gsize) data
+ };
+
+ return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_VEC, &vec, sizeof vec);
}
+static gboolean
+g_kdbus_msg_append_payload_memfd (struct kdbus_msg *msg,
+ gint fd,
+ gsize offset,
+ gsize size)
+{
+ struct kdbus_memfd mfd = {
+ .start = offset,
+ .size = size,
+ .fd = fd,
+ };
+
+ return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_MEMFD, &mfd, sizeof mfd);
+}
/**
* _g_kdbus_send:
* Returns: size of data sent or -1 when error
*/
-gsize
-_g_kdbus_send (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg,
- gchar *blob,
- gsize blob_size,
- GUnixFDList *fd_list,
+gboolean
+_g_kdbus_send (GKdbus *kdbus,
+ GDBusMessage *message,
GCancellable *cancellable,
GError **error)
{
- struct kdbus_msg* kmsg;
- struct kdbus_item *item;
- guint64 kmsg_size = 0;
- const gchar *name;
- gboolean use_memfd = FALSE;
- guint64 dst_id = KDBUS_DST_ID_BROADCAST;
+ struct kdbus_msg *msg = alloca (KDBUS_MSG_MAX_SIZE);
+ GVariantVectors body_vectors;
g_return_val_if_fail (G_IS_KDBUS (kdbus), -1);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
- return -1;
+ return FALSE;
+ /* fill in as we go... */
+ memset (msg, 0, sizeof (struct kdbus_msg));
+ msg->size = sizeof (struct kdbus_msg);
+ msg->payload_type = KDBUS_PAYLOAD_DBUS;
+ msg->src_id = kdbus->priv->unique_id;
+ msg->cookie = g_dbus_message_get_serial(message);
- /*
- * If systemd-bus-driverd from systemd isn't available
- * try to process the bus driver messages locally
- */
-#ifndef SYSTEMD_BUS_DRIVERD
- if (g_strcmp0(g_dbus_message_get_destination(dbus_msg), "org.freedesktop.DBus") == 0)
- {
- if (g_kdbus_bus_driver (worker, kdbus, dbus_msg))
- return blob_size;
- else
- return -1;
- }
-#else
- if ((g_strcmp0(g_dbus_message_get_destination(dbus_msg), "org.freedesktop.DBus") == 0) &&
- (g_strcmp0(g_dbus_message_get_member(dbus_msg), "Hello") == 0))
+ /* Message destination */
+ {
+ const gchar *dst_name;
+
+ dst_name = g_dbus_message_get_destination (message);
+
+ if (dst_name != NULL)
{
- g_kdbus_take_fd (kdbus);
+ if (g_dbus_is_unique_name (dst_name))
+ {
+ if (dst_name[1] != '1' || dst_name[2] != '.')
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Invalid unique D-Bus name '%s'", dst_name);
+ return FALSE;
+ }
+
+ /* We already know that it passes the checks for unique
+ * names, so no need to perform error checking on strtoull.
+ */
+ msg->dst_id = strtoull (dst_name + 3, NULL, 10);
+ dst_name = NULL;
+ }
+ else
+ {
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_DST_NAME, dst_name, strlen (dst_name) + 1);
+ msg->dst_id = KDBUS_DST_ID_NAME;
+ }
}
-#endif
+ else
+ msg->dst_id = KDBUS_DST_ID_BROADCAST;
+ }
+ /* File descriptors */
+ {
+ GUnixFDList *fd_list;
- /*
- * check destination
- */
- if ((name = g_dbus_message_get_destination(dbus_msg)))
- {
- dst_id = KDBUS_DST_ID_NAME;
- if ((name[0] == ':') && (name[1] == '1') && (name[2] == '.'))
- {
- dst_id = strtoull(&name[3], NULL, 10);
- name=NULL;
- }
- }
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list != NULL)
+ {
+ const gint *fds;
+ gint n_fds;
- /*
- * check whether we should use memfd transport (for messages > 512K)
- */
- if (name && (blob_size > 524288))
- use_memfd = TRUE;
+ fds = g_unix_fd_list_peek_fds (fd_list, &n_fds);
+ if (n_fds)
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_FDS, fds, sizeof (gint) * n_fds);
+ }
+ }
+
+ /* Message body */
+ {
+ struct dbus_fixed_header fh;
+ GHashTableIter header_iter;
+ GVariantBuilder builder;
+ gpointer key, value;
+ GVariant *parts[3];
+ GVariant *body;
+
+ fh.endian = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 'l': 'B';
+ fh.type = g_dbus_message_get_message_type (message);
+ fh.flags = g_dbus_message_get_flags (message);
+ fh.version = 2;
+ fh.reserved = 0;
+ fh.serial = g_dbus_message_get_serial (message);
+ parts[0] = g_variant_new_from_data (DBUS_FIXED_HEADER_TYPE, &fh, sizeof fh, TRUE, NULL, NULL);
+
+ g_dbus_message_init_header_iter (message, &header_iter);
+ g_variant_builder_init (&builder, DBUS_EXTENDED_HEADER_TYPE);
+ while (g_hash_table_iter_next (&header_iter, &key, &value))
+ {
+ guint64 key_int = (gsize) key;
- /*
- * check and set message size
- */
- kmsg_size = sizeof(struct kdbus_msg);
- if (use_memfd)
- {
- kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); /* header */
- kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_memfd)); /* body */
- }
- else
- kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); /* header + body */
+ /* We don't send these in GVariant format */
+ if (key_int == G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE ||
+ key_int == G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS)
+ continue;
- if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
- kmsg_size += ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list));
+ g_variant_builder_add (&builder, "{tv}", key_int, value);
+ }
+ parts[1] = g_variant_builder_end (&builder);
- if (name)
- kmsg_size += KDBUS_ITEM_SIZE(strlen(name) + 1);
- else if (dst_id == KDBUS_DST_ID_BROADCAST)
- kmsg_size += ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, bloom_filter) +
- G_STRUCT_OFFSET(struct kdbus_bloom_filter, data) +
- kdbus->priv->bloom_size);
+ body = g_dbus_message_get_body (message);
+ if (!body)
+ body = g_variant_new ("()");
+ parts[2] = g_variant_new_variant (body);
- kmsg = malloc(kmsg_size);
- if (!kmsg)
- g_error ("[KDBUS] kmsg malloc error");
+ body = g_variant_ref_sink (g_variant_new_tuple (parts, G_N_ELEMENTS (parts)));
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
+ g_variant_unref (body);
+ }
+ {
+ guint i;
- /*
- * set message header
- */
- memset(kmsg, 0, kmsg_size);
- kmsg->size = kmsg_size;
- kmsg->payload_type = KDBUS_PAYLOAD_DBUS;
- kmsg->dst_id = name ? 0 : dst_id;
- kmsg->src_id = kdbus->priv->unique_id;
- kmsg->cookie = g_dbus_message_get_serial(dbus_msg);
- kmsg->priority = 0;
+ for (i = 0; i < body_vectors.vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
+ if (vector.gbytes)
+ {
+ gint fd;
- /*
- * set message flags
- */
- kmsg->flags = ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
- ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+ fd = g_bytes_get_zero_copy_fd (vector.gbytes);
- if ((kmsg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY)
- kmsg->timeout_ns = 2000000000;
- else
- kmsg->cookie_reply = g_dbus_message_get_reply_serial(dbus_msg);
+ if (fd >= 0)
+ {
+ const guchar *bytes_data;
+ gsize bytes_size;
+ bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
+
+ if (bytes_data <= vector.data.pointer && vector.data.pointer + vector.size <= bytes_data + bytes_size)
+ {
+ if (!g_kdbus_msg_append_payload_memfd (msg, fd, vector.data.pointer - bytes_data, vector.size))
+ goto need_compact;
+ }
+ else
+ {
+ if (!g_kdbus_msg_append_payload_vec (msg, vector.data.pointer, vector.size))
+ goto need_compact;
+ }
+ }
+ else
+ {
+ if (!g_kdbus_msg_append_payload_vec (msg, vector.data.pointer, vector.size))
+ goto need_compact;
+ }
+ }
+ else
+ if (!g_kdbus_msg_append_payload_vec (msg, body_vectors.extra_bytes->data + vector.data.offset, vector.size))
+ goto need_compact;
+ }
+ }
/*
- * append payload
+ * set message flags
*/
- item = kmsg->items;
- if (use_memfd)
- {
- gint32 body_size;
-
- if (!g_kdbus_alloc_memfd (kdbus))
- g_error ("Can't alloc memfd");
-
- /* split blob to header and body */
- memcpy (&body_size, blob+4, 4);
- body_size = GINT32_FROM_LE (body_size);
-
- /*
- * write blob and seal
- * We should build up whole messsage directly in memfd object without
- * making copy but memfd will be completly reworked soon [1],
- * so we're still waiting for this:
- *
- * [1] https://code.google.com/p/d-bus/source/browse/TODO
- */
-
- if (write(kdbus->priv->memfd, blob + (blob_size-body_size), body_size) <= 0)
- g_error ("Can't write data to memfd object");
-
- if (ioctl(kdbus->priv->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) < 0)
- g_error ("Can't seal memfd object");
-
- /* message header in its entirety must be contained in a single PAYLOAD_VEC item */
- g_kdbus_append_payload_vec (&item, blob, blob_size - body_size);
- /* send body as as PAYLOAD_MEMFD item */
- g_kdbus_append_payload_memfd (&item, kdbus->priv->memfd, body_size);
- }
+ msg->flags = ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
+ ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+
+ if ((msg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY)
+ msg->timeout_ns = 2000000000;
else
- {
- /* if we don't use memfd, send whole message as a PAYLOAD_VEC item */
- g_kdbus_append_payload_vec (&item, blob, blob_size);
- }
+ msg->cookie_reply = g_dbus_message_get_reply_serial(message);
/*
- * append destination or bloom filters
- */
- if (name)
- g_kdbus_append_destination (&item, name, strlen(name));
- else if (dst_id == KDBUS_DST_ID_BROADCAST)
+ if (dst_id == KDBUS_DST_ID_BROADCAST)
{
struct kdbus_bloom_filter *bloom_filter;
bloom_filter = g_kdbus_append_bloom (&item, kdbus->priv->bloom_size);
- g_kdbus_setup_bloom (kdbus, dbus_msg, bloom_filter);
+ g_kdbus_setup_bloom (kdbus, message, bloom_filter);
}
-
-
- /*
- * append fds if any
- */
- if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
- g_kdbus_append_fds (&item, fd_list);
-
+ */
/*
* send message
*/
-again:
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg))
+//again:
+ if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, msg))
{
+/*
GString *error_name;
error_name = g_string_new (NULL);
g_print ("[KDBUS] ioctl error sending kdbus message:%d (%m)\n",errno);
g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno), _("Error sending message - KDBUS_CMD_MSG_SEND error"));
- return -1;
+*/
+ perror("ioctl send");
+ g_error ("IOCTL SEND: %d\n",errno);
+ return FALSE;
}
- if (kdbus->priv->memfd >= 0)
- close(kdbus->priv->memfd);
-
- free(kmsg);
+ return TRUE;
- return blob_size;
+need_compact:
+ /* We end up here if:
+ * - too many kdbus_items
+ * - too large kdbus_msg size
+ * - too much vector data
+ *
+ * We need to compact the message before sending it.
+ */
+ g_assert_not_reached ();
}