#include "glib-unix.h"
#include "glibintl.h"
#include "kdbus.h"
-#include "gkdbusconnection.h"
#include <gio/gio.h>
#include <errno.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <stdio.h>
+#include <stdint.h>
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#include <sys/uio.h>
#endif
-#define KDBUS_POOL_SIZE (16 * 1024LU * 1024LU)
-#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
-#define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p))
+#include <glib/gstdio.h>
+#include <glib/glib-private.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+
+#include "glibintl.h"
+#include "gunixfdmessage.h"
+
+#define KDBUS_MSG_MAX_SIZE 8192
+#define KDBUS_TIMEOUT_NS 2000000000LU
+#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) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
for (item = (head)->first; \
(guint8 *)(item) < (guint8 *)(head) + (head)->size; \
item = KDBUS_ITEM_NEXT(item))
+#define KDBUS_FOREACH(iter, first, _size) \
+ for (iter = (first); \
+ ((guint8 *)(iter) < (guint8 *)(first) + (_size)) && \
+ ((guint8 *)(iter) >= (guint8 *)(first)); \
+ iter = (void*)(((guint8 *)iter) + KDBUS_ALIGN8((iter)->size)))
#define g_alloca0(x) memset(g_alloca(x), '\0', (x))
-static void g_kdbus_initable_iface_init (GInitableIface *iface);
-static gboolean g_kdbus_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error);
+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)")
+
+/*
+ * Macros for SipHash algorithm
+ */
-#define g_kdbus_get_type _g_kdbus_get_type
-G_DEFINE_TYPE_WITH_CODE (GKdbus, g_kdbus, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
- g_kdbus_initable_iface_init));
+#define ROTL(x,b) (guint64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
+
+#define U32TO8_LE(p, v) \
+ (p)[0] = (guint8)((v) ); (p)[1] = (guint8)((v) >> 8); \
+ (p)[2] = (guint8)((v) >> 16); (p)[3] = (guint8)((v) >> 24);
+
+#define U64TO8_LE(p, v) \
+ U32TO8_LE((p), (guint32)((v) )); \
+ U32TO8_LE((p) + 4, (guint32)((v) >> 32));
+
+#define U8TO64_LE(p) \
+ (((guint64)((p)[0]) ) | \
+ ((guint64)((p)[1]) << 8) | \
+ ((guint64)((p)[2]) << 16) | \
+ ((guint64)((p)[3]) << 24) | \
+ ((guint64)((p)[4]) << 32) | \
+ ((guint64)((p)[5]) << 40) | \
+ ((guint64)((p)[6]) << 48) | \
+ ((guint64)((p)[7]) << 56))
+
+#define SIPROUND \
+ do { \
+ v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
+ v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
+ v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
+ v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
+ } while(0)
-/* GBusCredentialsFlags */
typedef enum
{
G_BUS_CREDS_PID = 1,
G_BUS_CREDS_SELINUX_CONTEXT = 4
} GBusCredentialsFlags;
-/* 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;
+typedef GObjectClass GKDBusWorkerClass;
-/* GBusReleaseNameReturnFlags */
-typedef enum
+struct _GKDBusWorker
{
- 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;
+ GObject parent_instance;
-/* GKdbusPrivate struct */
-struct _GKdbusPrivate
-{
gint fd;
+ GMainContext *context;
+ GSource *source;
+
gchar *kdbus_buffer;
- struct kdbus_msg *kmsg;
gchar *unique_name;
guint64 unique_id;
- guint64 hello_flags;
- guint64 attach_flags;
+ guint64 flags;
+ guint64 attach_flags_send;
+ guint64 attach_flags_recv;
+
+ gsize bloom_size;
+ guint bloom_n_hash;
guint closed : 1;
guint inited : 1;
guint timed_out : 1;
guchar bus_id[16];
-};
-/* GKdbusSource struct */
-typedef struct {
- GSource source;
- GPollFD pollfd;
- GKdbus *kdbus;
- GIOCondition condition;
- GCancellable *cancellable;
- GPollFD cancel_pollfd;
- gint64 timeout_time;
-} GKdbusSource;
+ GDBusCapabilityFlags capabilities;
+ GDBusWorkerMessageReceivedCallback message_received_callback;
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback;
+ GDBusWorkerDisconnectedCallback disconnected_callback;
+ gpointer user_data;
+};
+static gssize _g_kdbus_receive (GKDBusWorker *kdbus,
+ GCancellable *cancellable,
+ GError **error);
-typedef gboolean (*GKdbusSourceFunc) (GKdbus *kdbus,
- GIOCondition condition,
- gpointer user_data);
+G_DEFINE_TYPE (GKDBusWorker, g_kdbus_worker, G_TYPE_OBJECT)
-/**
- * g_kdbus_finalize:
- *
- */
-static void
-g_kdbus_finalize (GObject *object)
+/* Hash keys for bloom filters*/
+const guint8 hash_keys[8][16] =
{
- GKdbus *kdbus = G_KDBUS (object);
-
- if (kdbus->priv->kdbus_buffer != NULL)
- munmap (kdbus->priv->kdbus_buffer, KDBUS_POOL_SIZE);
+ {0xb9,0x66,0x0b,0xf0,0x46,0x70,0x47,0xc1,0x88,0x75,0xc4,0x9c,0x54,0xb9,0xbd,0x15},
+ {0xaa,0xa1,0x54,0xa2,0xe0,0x71,0x4b,0x39,0xbf,0xe1,0xdd,0x2e,0x9f,0xc5,0x4a,0x3b},
+ {0x63,0xfd,0xae,0xbe,0xcd,0x82,0x48,0x12,0xa1,0x6e,0x41,0x26,0xcb,0xfa,0xa0,0xc8},
+ {0x23,0xbe,0x45,0x29,0x32,0xd2,0x46,0x2d,0x82,0x03,0x52,0x28,0xfe,0x37,0x17,0xf5},
+ {0x56,0x3b,0xbf,0xee,0x5a,0x4f,0x43,0x39,0xaf,0xaa,0x94,0x08,0xdf,0xf0,0xfc,0x10},
+ {0x31,0x80,0xc8,0x73,0xc7,0xea,0x46,0xd3,0xaa,0x25,0x75,0x0f,0x9e,0x4c,0x09,0x29},
+ {0x7d,0xf7,0x18,0x4b,0x7b,0xa4,0x44,0xd5,0x85,0x3c,0x06,0xe0,0x65,0x53,0x96,0x6d},
+ {0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35}
+};
- kdbus->priv->kdbus_buffer = NULL;
+enum {
+ MATCH_ELEMENT_TYPE,
+ MATCH_ELEMENT_SENDER,
+ MATCH_ELEMENT_INTERFACE,
+ MATCH_ELEMENT_MEMBER,
+ MATCH_ELEMENT_PATH,
+ MATCH_ELEMENT_PATH_NAMESPACE,
+ MATCH_ELEMENT_DESTINATION,
+ MATCH_ELEMENT_ARG0NAMESPACE,
+ MATCH_ELEMENT_EAVESDROP,
+ MATCH_ELEMENT_ARGN,
+ MATCH_ELEMENT_ARGNPATH,
+};
- if (kdbus->priv->fd != -1 && !kdbus->priv->closed)
- _g_kdbus_close (kdbus, NULL);
+/* MatchElement struct */
+typedef struct {
+ guint16 type;
+ guint16 arg;
+ char *value;
+} MatchElement;
- if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object);
-}
+/* Match struct */
+typedef struct {
+ int n_elements;
+ MatchElement *elements;
+} Match;
/**
- * g_kdbus_class_init:
+ * SipHash algorithm
*
*/
static void
-g_kdbus_class_init (GKdbusClass *klass)
+_g_siphash24 (guint8 out[8],
+ const void *_in,
+ gsize inlen,
+ const guint8 k[16])
{
- GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
+ /* "somepseudorandomlygeneratedbytes" */
+ guint64 v0 = 0x736f6d6570736575ULL;
+ guint64 v1 = 0x646f72616e646f6dULL;
+ guint64 v2 = 0x6c7967656e657261ULL;
+ guint64 v3 = 0x7465646279746573ULL;
+ guint64 b;
+ guint64 k0 = U8TO64_LE (k);
+ guint64 k1 = U8TO64_LE (k + 8);
+ guint64 m;
+ const guint8 *in = _in;
+ const guint8 *end = in + inlen - (inlen % sizeof(guint64));
+ const int left = inlen & 7;
+ b = ((guint64) inlen) << 56;
+ v3 ^= k1;
+ v2 ^= k0;
+ v1 ^= k1;
+ v0 ^= k0;
+
+ for (; in != end; in += 8)
+ {
+ m = U8TO64_LE (in);
+ v3 ^= m;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= m;
+ }
+
+ switch (left)
+ {
+ case 7: b |= ((guint64) in[6]) << 48;
+ case 6: b |= ((guint64) in[5]) << 40;
+ case 5: b |= ((guint64) in[4]) << 32;
+ case 4: b |= ((guint64) in[3]) << 24;
+ case 3: b |= ((guint64) in[2]) << 16;
+ case 2: b |= ((guint64) in[1]) << 8;
+ case 1: b |= ((guint64) in[0]); break;
+ case 0: break;
+ }
- g_type_class_add_private (klass, sizeof (GKdbusPrivate));
- gobject_class->finalize = g_kdbus_finalize;
+ v3 ^= b;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= b;
+
+ v2 ^= 0xff;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ b = v0 ^ v1 ^ v2 ^ v3;
+ U64TO8_LE (out, b);
}
/**
- * g_kdbus_initable_iface_init:
+ * is_key()
*
*/
-static void
-g_kdbus_initable_iface_init (GInitableIface *iface)
+static gboolean
+is_key (const char *key_start, const char *key_end, char *value)
{
- iface->init = g_kdbus_initable_init;
+ gsize len = strlen (value);
+
+ if (len != key_end - key_start)
+ return FALSE;
+
+ return strncmp (key_start, value, len) == 0;
}
/**
- * g_kdbus_init:
+ * parse_key()
*
*/
-static void
-g_kdbus_init (GKdbus *kdbus)
+static gboolean
+parse_key (MatchElement *element, const char *key_start, const char *key_end)
{
- kdbus->priv = G_TYPE_INSTANCE_GET_PRIVATE (kdbus, G_TYPE_KDBUS, GKdbusPrivate);
+ gboolean res = TRUE;
- kdbus->priv->fd = -1;
+ if (is_key (key_start, key_end, "type"))
+ {
+ element->type = MATCH_ELEMENT_TYPE;
+ }
+ else if (is_key (key_start, key_end, "sender"))
+ {
+ element->type = MATCH_ELEMENT_SENDER;
+ }
+ else if (is_key (key_start, key_end, "interface"))
+ {
+ element->type = MATCH_ELEMENT_INTERFACE;
+ }
+ else if (is_key (key_start, key_end, "member"))
+ {
+ element->type = MATCH_ELEMENT_MEMBER;
+ }
+ else if (is_key (key_start, key_end, "path"))
+ {
+ element->type = MATCH_ELEMENT_PATH;
+ }
+ else if (is_key (key_start, key_end, "path_namespace"))
+ {
+ element->type = MATCH_ELEMENT_PATH_NAMESPACE;
+ }
+ else if (is_key (key_start, key_end, "destination"))
+ {
+ element->type = MATCH_ELEMENT_DESTINATION;
+ }
+ else if (is_key (key_start, key_end, "arg0namespace"))
+ {
+ element->type = MATCH_ELEMENT_ARG0NAMESPACE;
+ }
+ else if (is_key (key_start, key_end, "eavesdrop"))
+ {
+ element->type = MATCH_ELEMENT_EAVESDROP;
+ }
+ else if (key_end - key_start > 3 && is_key (key_start, key_start + 3, "arg"))
+ {
+ const char *digits = key_start + 3;
+ const char *end_digits = digits;
- kdbus->priv->unique_id = -1;
- kdbus->priv->unique_name = NULL;
+ while (end_digits < key_end && g_ascii_isdigit (*end_digits))
+ end_digits++;
- kdbus->priv->kdbus_buffer = NULL;
+ if (end_digits == key_end) /* argN */
+ {
+ element->type = MATCH_ELEMENT_ARGN;
+ element->arg = atoi (digits);
+ }
+ else if (is_key (end_digits, key_end, "path")) /* argNpath */
+ {
+ element->type = MATCH_ELEMENT_ARGNPATH;
+ element->arg = atoi (digits);
+ }
+ else
+ res = FALSE;
+ }
+ else
+ res = FALSE;
- kdbus->priv->hello_flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
- kdbus->priv->attach_flags = KDBUS_ATTACH_NAMES;
+ return res;
}
/**
- * g_kdbus_initable_init:
+ * parse_value()
*
*/
-static gboolean
-g_kdbus_initable_init (GInitable *initable,
- GCancellable *cancellable,
- GError **error)
+static const char *
+parse_value (MatchElement *element, const char *s)
{
- GKdbus *kdbus;
+ char quote_char;
+ GString *value;
- g_return_val_if_fail (G_IS_KDBUS (initable), FALSE);
+ value = g_string_new ("");
- kdbus = G_KDBUS (initable);
+ quote_char = 0;
- if (cancellable != NULL)
+ for (;*s; s++)
{
- g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
- _("Cancellable initialization not supported"));
- return FALSE;
+ if (quote_char == 0)
+ {
+ switch (*s)
+ {
+ case '\'':
+ quote_char = '\'';
+ break;
+
+ case ',':
+ s++;
+ goto out;
+
+ case '\\':
+ quote_char = '\\';
+ break;
+
+ default:
+ g_string_append_c (value, *s);
+ break;
+ }
+ }
+ else if (quote_char == '\\')
+ {
+ /* \ only counts as an escape if escaping a quote mark */
+ if (*s != '\'')
+ g_string_append_c (value, '\\');
+
+ g_string_append_c (value, *s);
+ quote_char = 0;
+ }
+ else /* quote_char == ' */
+ {
+ if (*s == '\'')
+ quote_char = 0;
+ else
+ g_string_append_c (value, *s);
+ }
}
- kdbus->priv->inited = TRUE;
+ out:
+ if (quote_char == '\\')
+ g_string_append_c (value, '\\');
+ else if (quote_char == '\'')
+ {
+ g_string_free (value, TRUE);
+ return NULL;
+ }
- return TRUE;
+ element->value = g_string_free (value, FALSE);
+ return s;
}
/**
- * kdbus_source_prepare:
+ * match_new()
*
*/
-static gboolean
-kdbus_source_prepare (GSource *source,
- gint *timeout)
+static Match *
+match_new (const char *str)
{
- GKdbusSource *kdbus_source = (GKdbusSource *)source;
+ Match *match;
+ GArray *elements;
+ const char *p;
+ const char *key_start;
+ const char *key_end;
+ MatchElement element;
+ int i;
- if (g_cancellable_is_cancelled (kdbus_source->cancellable))
- return TRUE;
+ elements = g_array_new (TRUE, TRUE, sizeof (MatchElement));
- if (kdbus_source->timeout_time)
- {
- gint64 now;
+ p = str;
- now = g_source_get_time (source);
+ while (*p != 0)
+ {
+ memset (&element, 0, sizeof (element));
- *timeout = (kdbus_source->timeout_time - now + 999) / 1000;
- if (*timeout < 0)
- {
- kdbus_source->kdbus->priv->timed_out = TRUE;
- *timeout = 0;
- return TRUE;
- }
- }
- else
- *timeout = -1;
+ /* Skip initial whitespace */
+ while (*p && g_ascii_isspace (*p))
+ p++;
- if ((kdbus_source->condition & kdbus_source->pollfd.revents) != 0)
- return TRUE;
+ key_start = p;
- return FALSE;
-}
+ /* Read non-whitespace non-equals chars */
+ while (*p && *p != '=' && !g_ascii_isspace (*p))
+ p++;
+ key_end = p;
-/**
- * kdbus_source_check:
- *
- */
-static gboolean
-kdbus_source_check (GSource *source)
-{
- gint timeout;
+ /* Skip any whitespace after key */
+ while (*p && g_ascii_isspace (*p))
+ p++;
- return kdbus_source_prepare (source, &timeout);
-}
+ if (key_start == key_end)
+ continue; /* Allow trailing whitespace */
+ if (*p != '=')
+ goto error;
+ ++p;
-/**
- * kdbus_source_dispatch
- *
- */
-static gboolean
-kdbus_source_dispatch (GSource *source,
- GSourceFunc callback,
- gpointer user_data)
-{
- GKdbusSourceFunc func = (GKdbusSourceFunc)callback;
- GKdbusSource *kdbus_source = (GKdbusSource *)source;
- GKdbus *kdbus = kdbus_source->kdbus;
- gboolean ret;
+ if (!parse_key (&element, key_start, key_end))
+ goto error;
- if (kdbus_source->kdbus->priv->timed_out)
- kdbus_source->pollfd.revents |= kdbus_source->condition & (G_IO_IN | G_IO_OUT);
+ p = parse_value (&element, p);
+ if (p == NULL)
+ goto error;
- ret = (*func) (kdbus,
- kdbus_source->pollfd.revents & kdbus_source->condition,
- user_data);
+ g_array_append_val (elements, element);
+ }
- if (kdbus->priv->timeout)
- kdbus_source->timeout_time = g_get_monotonic_time ()
- + kdbus->priv->timeout * 1000000;
+ match = g_new0 (Match, 1);
+ match->n_elements = elements->len;
+ match->elements = (MatchElement *)g_array_free (elements, FALSE);
- else
- kdbus_source->timeout_time = 0;
+ return match;
- return ret;
+ error:
+ for (i = 0; i < elements->len; i++)
+ g_free (g_array_index (elements, MatchElement, i).value);
+ g_array_free (elements, TRUE);
+ return NULL;
}
/**
- * kdbus_source_finalize
+ * match_free()
*
*/
static void
-kdbus_source_finalize (GSource *source)
+match_free (Match *match)
{
- GKdbusSource *kdbus_source = (GKdbusSource *)source;
- GKdbus *kdbus;
-
- kdbus = kdbus_source->kdbus;
-
- g_object_unref (kdbus);
-
- if (kdbus_source->cancellable)
- {
- g_cancellable_release_fd (kdbus_source->cancellable);
- g_object_unref (kdbus_source->cancellable);
- }
+ int i;
+ for (i = 0; i < match->n_elements; i++)
+ g_free (match->elements[i].value);
+ g_free (match->elements);
+ g_free (match);
}
/**
- * kdbus_source_closure_callback:
+ * g_kdbus_finalize:
*
*/
-static gboolean
-kdbus_source_closure_callback (GKdbus *kdbus,
- GIOCondition condition,
- gpointer data)
+static void
+g_kdbus_worker_finalize (GObject *object)
{
- GClosure *closure = data;
- GValue params[2] = { G_VALUE_INIT, G_VALUE_INIT };
- GValue result_value = G_VALUE_INIT;
- gboolean result;
-
- g_value_init (&result_value, G_TYPE_BOOLEAN);
+ GKDBusWorker *kdbus = G_KDBUS_WORKER (object);
- g_value_init (¶ms[0], G_TYPE_KDBUS);
- g_value_set_object (¶ms[0], kdbus);
- g_value_init (¶ms[1], G_TYPE_IO_CONDITION);
- g_value_set_flags (¶ms[1], condition);
+ if (kdbus->kdbus_buffer != NULL)
+ munmap (kdbus->kdbus_buffer, KDBUS_POOL_SIZE);
- g_closure_invoke (closure, &result_value, 2, params, NULL);
+ kdbus->kdbus_buffer = NULL;
- result = g_value_get_boolean (&result_value);
- g_value_unset (&result_value);
- g_value_unset (¶ms[0]);
- g_value_unset (¶ms[1]);
+ if (kdbus->fd != -1 && !kdbus->closed)
+ _g_kdbus_close (kdbus);
- return result;
+ G_OBJECT_CLASS (g_kdbus_worker_parent_class)->finalize (object);
}
-
-static GSourceFuncs kdbus_source_funcs =
+static void
+g_kdbus_worker_class_init (GKDBusWorkerClass *class)
{
- kdbus_source_prepare,
- kdbus_source_check,
- kdbus_source_dispatch,
- kdbus_source_finalize,
- (GSourceFunc)kdbus_source_closure_callback,
-};
-
+ class->finalize = g_kdbus_worker_finalize;
+}
-/**
- * kdbus_source_new:
- *
- */
-static GSource *
-kdbus_source_new (GKdbus *kdbus,
- GIOCondition condition,
- GCancellable *cancellable)
+static void
+g_kdbus_worker_init (GKDBusWorker *kdbus)
{
- GSource *source;
- GKdbusSource *kdbus_source;
-
- source = g_source_new (&kdbus_source_funcs, sizeof (GKdbusSource));
- g_source_set_name (source, "GKdbus");
- kdbus_source = (GKdbusSource *)source;
-
- kdbus_source->kdbus = g_object_ref (kdbus);
- kdbus_source->condition = condition;
+ kdbus->fd = -1;
- if (g_cancellable_make_pollfd (cancellable,
- &kdbus_source->cancel_pollfd))
- {
- kdbus_source->cancellable = g_object_ref (cancellable);
- g_source_add_poll (source, &kdbus_source->cancel_pollfd);
- }
+ kdbus->unique_id = -1;
+ kdbus->unique_name = NULL;
- kdbus_source->pollfd.fd = kdbus->priv->fd;
- kdbus_source->pollfd.events = condition;
- kdbus_source->pollfd.revents = 0;
- g_source_add_poll (source, &kdbus_source->pollfd);
-
- if (kdbus->priv->timeout)
- kdbus_source->timeout_time = g_get_monotonic_time ()
- + kdbus->priv->timeout * 1000000;
- else
- kdbus_source->timeout_time = 0;
+ kdbus->kdbus_buffer = NULL;
- return source;
+ kdbus->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
+ kdbus->attach_flags_send = _KDBUS_ATTACH_ALL;
+ kdbus->attach_flags_recv = _KDBUS_ATTACH_ALL;
}
-
-/**
- * _g_kdbus_create_source:
- *
- */
-GSource *
-_g_kdbus_create_source (GKdbus *kdbus,
- GIOCondition condition,
- GCancellable *cancellable)
+static gboolean
+kdbus_ready (gint fd,
+ GIOCondition condition,
+ gpointer user_data)
{
- g_return_val_if_fail (G_IS_KDBUS (kdbus) && (cancellable == NULL || G_IS_CANCELLABLE (cancellable)), NULL);
+ GKDBusWorker *kdbus = user_data;
+ GError *error = NULL;
- return kdbus_source_new (kdbus, condition, cancellable);
-}
+ _g_kdbus_receive (kdbus, NULL, &error);
+ g_assert_no_error (error);
+ return G_SOURCE_CONTINUE;
+}
-/**
- * _g_kdbus_open:
- *
- */
gboolean
-_g_kdbus_open (GKdbus *kdbus,
- const gchar *address,
- GError **error)
+_g_kdbus_open (GKDBusWorker *worker,
+ const gchar *address,
+ GError **error)
{
- g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
- kdbus->priv->fd = open(address, O_RDWR|O_NOCTTY|O_CLOEXEC);
- if (kdbus->priv->fd<0)
+ worker->fd = open(address, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (worker->fd<0)
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Can't open kdbus endpoint"));
return FALSE;
}
- kdbus->priv->closed = FALSE;
+ worker->closed = FALSE;
return TRUE;
}
*
*/
static gboolean
-g_kdbus_free_data (GKdbus *kdbus,
+g_kdbus_free_data (GKDBusWorker *kdbus,
guint64 offset)
{
- struct kdbus_cmd_free cmd;
+ struct kdbus_cmd_free cmd = {
+ .size = sizeof(cmd),
+ .offset = offset,
+ .flags = 0
+ };
int ret;
- cmd.offset = offset;
- cmd.flags = 0;
-
- ret = ioctl (kdbus->priv->fd, KDBUS_CMD_FREE, &cmd);
+ ret = ioctl (kdbus->fd, KDBUS_CMD_FREE, &cmd);
if (ret < 0)
return FALSE;
* _g_kdbus_close:
*
*/
-gboolean
-_g_kdbus_close (GKdbus *kdbus,
- GError **error)
+void
+_g_kdbus_close (GKDBusWorker *kdbus)
{
- gint res;
-
- g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
-
- if (kdbus->priv->closed)
- return TRUE;
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (kdbus), FALSE);
- while (1)
- {
- res = close (kdbus->priv->fd);
+ if (kdbus->closed)
+ return;
- if (res == -1)
- {
- if (errno == EINTR)
- continue;
+ g_source_destroy (kdbus->source);
+ kdbus->source = 0;
- g_set_error (error, G_IO_ERROR,
- g_io_error_from_errno (errno),
- _("Error closing kdbus fd: %s"),
- g_strerror (errno));
- return FALSE;
- }
- break;
- }
+ g_main_context_unref (kdbus->context);
+ kdbus->context = NULL;
- kdbus->priv->closed = TRUE;
- kdbus->priv->fd = -1;
+ close (kdbus->fd);
+ kdbus->fd = -1;
- return TRUE;
+ kdbus->closed = TRUE;
}
-
/**
* _g_kdbus_is_closed:
*
*/
gboolean
-_g_kdbus_is_closed (GKdbus *kdbus)
+_g_kdbus_is_closed (GKDBusWorker *kdbus)
{
- g_return_val_if_fail (G_IS_KDBUS (kdbus), FALSE);
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (kdbus), FALSE);
- return kdbus->priv->closed;
+ return kdbus->closed;
}
*
*/
GVariant *
-_g_kdbus_Hello (GIOStream *stream,
+_g_kdbus_Hello (GKDBusWorker *worker,
GError **error)
{
- GKdbus *kdbus;
- struct kdbus_cmd_hello *hello;
+ struct kdbus_cmd_hello *cmd;
struct kdbus_item *item;
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);
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->conn_flags = kdbus->priv->hello_flags;
- hello->attach_flags = kdbus->priv->attach_flags;
- hello->size = size;
- hello->pool_size = KDBUS_POOL_SIZE;
+ cmd = g_alloca0 (size);
+ cmd->flags = worker->flags;
+ cmd->attach_flags_send = worker->attach_flags_send;
+ cmd->attach_flags_recv = worker->attach_flags_recv;
+ cmd->size = size;
+ cmd->pool_size = KDBUS_POOL_SIZE;
- item = hello->items;
+ item = cmd->items;
item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1;
- item->type = KDBUS_ITEM_CONN_NAME;
+ item->type = KDBUS_ITEM_CONN_DESCRIPTION;
memcpy (item->str, conn_name, conn_name_size+1);
item = KDBUS_ITEM_NEXT (item);
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_HELLO, hello))
+ if (ioctl(worker->fd, KDBUS_CMD_HELLO, cmd))
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
return NULL;
}
- kdbus->priv->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, kdbus->priv->fd, 0);
- if (kdbus->priv->kdbus_buffer == MAP_FAILED)
+ worker->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, worker->fd, 0);
+ if (worker->kdbus_buffer == MAP_FAILED)
{
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
return NULL;
}
- if (hello->bus_flags > 0xFFFFFFFFULL)
+ if (cmd->bus_flags > 0xFFFFFFFFULL)
{
g_set_error_literal (error,
G_IO_ERROR,
return NULL;
}
- memcpy (kdbus->priv->bus_id, hello->id128, 16);
+ memcpy (worker->bus_id, cmd->id128, 16);
- kdbus->priv->unique_id = hello->id;
- asprintf(&kdbus->priv->unique_name, ":1.%llu", (unsigned long long) hello->id);
+ worker->unique_id = cmd->id;
+ asprintf(&worker->unique_name, ":1.%llu", (unsigned long long) cmd->id);
- return g_variant_new ("(s)", kdbus->priv->unique_name);
+ /* read bloom filters parameters */
+ //worker->bloom_size = (gsize) cmd->bloom.size;
+ //worker->bloom_n_hash = (guint) cmd->bloom.n_hash;
+
+ return g_variant_new ("(s)", worker->unique_name);
}
-/*
+/**
* _g_kdbus_RequestName:
*
*/
GVariant *
-_g_kdbus_RequestName (GDBusConnection *connection,
+_g_kdbus_RequestName (GKDBusWorker *worker,
const gchar *name,
GBusNameOwnerFlags flags,
GError **error)
{
- GKdbus *kdbus;
GVariant *result;
- struct kdbus_cmd_name *kdbus_name;
+ struct kdbus_cmd *cmd;
guint64 kdbus_flags;
gssize len, size;
gint status, ret;
- status = G_BUS_REQUEST_NAME_REPLY_PRIMARY_OWNER;
-
- 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;
- }
+ status = G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER;
if (!g_dbus_is_name (name))
{
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);
+ size = G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ cmd->flags = kdbus_flags;
+ memcpy (cmd->items[0].str, name, len);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_NAME_ACQUIRE, cmd);
if (ret < 0)
{
if (errno == EEXIST)
- status = G_BUS_REQUEST_NAME_REPLY_EXISTS;
+ status = G_BUS_REQUEST_NAME_FLAGS_EXISTS;
else if (errno == EALREADY)
- status = G_BUS_REQUEST_NAME_REPLY_ALREADY_OWNER;
+ status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
else
{
g_set_error (error, G_IO_ERROR,
}
}
- if (kdbus_name->flags & KDBUS_NAME_IN_QUEUE)
- status = G_BUS_REQUEST_NAME_REPLY_IN_QUEUE;
+ if (cmd->flags & KDBUS_NAME_IN_QUEUE)
+ status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
result = g_variant_new ("(u)", status);
}
-/*
+/**
* _g_kdbus_ReleaseName:
*
*/
GVariant *
-_g_kdbus_ReleaseName (GDBusConnection *connection,
+_g_kdbus_ReleaseName (GKDBusWorker *worker,
const gchar *name,
GError **error)
{
- GKdbus *kdbus;
GVariant *result;
- struct kdbus_cmd_name *kdbus_name;
+ struct kdbus_cmd *cmd;
gssize len, size;
gint status, ret;
- status = G_BUS_RELEASE_NAME_REPLY_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;
- }
+ status = G_BUS_RELEASE_NAME_FLAGS_RELEASED;
if (!g_dbus_is_name (name))
{
}
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);
+ size = G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_NAME_RELEASE, cmd);
if (ret < 0)
{
if (errno == ESRCH)
- status = G_BUS_RELEASE_NAME_REPLY_NON_EXISTENT;
+ status = G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT;
else if (errno == EADDRINUSE)
- status = G_BUS_RELEASE_NAME_REPLY_NOT_OWNER;
+ status = G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER;
else
{
g_set_error (error, G_IO_ERROR,
*
*/
GVariant *
-_g_kdbus_GetBusId (GDBusConnection *connection,
+_g_kdbus_GetBusId (GKDBusWorker *worker,
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;
- }
for (cnt=0; cnt<16; cnt++)
- g_string_append_printf (result_str, "%02x", kdbus->priv->bus_id[cnt]);
+ g_string_append_printf (result_str, "%02x", worker->bus_id[cnt]);
result = g_variant_new ("(s)", result_str->str);
g_string_free (result_str, TRUE);
*
*/
GVariant *
-_g_kdbus_GetListNames (GDBusConnection *connection,
+_g_kdbus_GetListNames (GKDBusWorker *worker,
guint list_name_type,
GError **error)
{
- GKdbus *kdbus;
GVariant *result;
GVariantBuilder *builder;
-
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_cmd_name *name;
+ struct kdbus_info *name_list, *name;
+ struct kdbus_cmd_list cmd = {
+ .size = sizeof(cmd)
+ };
guint64 prev_id;
gint ret;
prev_id = 0;
- 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 (list_name_type)
- cmd.flags = KDBUS_NAME_LIST_ACTIVATORS; /* ListActivatableNames */
+ cmd.flags = KDBUS_LIST_ACTIVATORS; /* ListActivatableNames */
else
- cmd.flags = KDBUS_NAME_LIST_UNIQUE | KDBUS_NAME_LIST_NAMES; /* ListNames */
+ cmd.flags = KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES; /* ListNames */
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_LIST, &cmd);
+ ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
if (ret < 0)
{
g_set_error (error,
return NULL;
}
- name_list = (struct kdbus_name_list *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd.offset);
+ name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- KDBUS_ITEM_FOREACH(name, name_list, names)
+ KDBUS_FOREACH(name, name_list, cmd.list_size)
{
struct kdbus_item *item;
const gchar *item_name = "";
- if ((cmd.flags & KDBUS_NAME_LIST_UNIQUE) && name->owner_id != prev_id)
+ if ((cmd.flags & KDBUS_LIST_UNIQUE) && name->id != prev_id)
{
GString *unique_name;
unique_name = g_string_new (NULL);
- g_string_printf (unique_name, ":1.%llu", name->owner_id);
+ g_string_printf (unique_name, ":1.%llu", name->id);
g_variant_builder_add (builder, "s", unique_name->str);
g_string_free (unique_name,TRUE);
- prev_id = name->owner_id;
+ prev_id = name->id;
}
KDBUS_ITEM_FOREACH(item, name, items)
- if (item->type == KDBUS_ITEM_NAME)
- item_name = item->str;
+ 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);
result = g_variant_new ("(as)", builder);
g_variant_builder_unref (builder);
- g_kdbus_free_data (kdbus, cmd.offset);
+ g_kdbus_free_data (worker, cmd.offset);
return result;
}
*
*/
static gboolean
-g_kdbus_NameHasOwner_internal (GKdbus *kdbus,
+g_kdbus_NameHasOwner_internal (GKDBusWorker *worker,
const gchar *name,
GError **error)
{
- struct kdbus_cmd_conn_info *cmd;
+ struct kdbus_cmd_info *cmd;
gssize size, len;
gint ret;
if (g_dbus_is_unique_name(name))
{
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items);
+ 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_conn_info, items) + KDBUS_ITEM_SIZE(len);
+ 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;
}
cmd->size = size;
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
- g_kdbus_free_data (kdbus, cmd->offset);
+ ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
+ g_kdbus_free_data (worker, cmd->offset);
if (ret < 0)
return FALSE;
*
*/
GVariant *
-_g_kdbus_GetListQueuedOwners (GDBusConnection *connection,
- const gchar *name,
- GError **error)
+_g_kdbus_GetListQueuedOwners (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
{
- GKdbus *kdbus;
GVariant *result;
GVariantBuilder *builder;
GString *unique_name;
gint ret;
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_cmd_name *kname;
-
- 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;
- }
+ struct kdbus_info *name_list, *kname;
+ struct kdbus_cmd_list cmd = {
+ .size = sizeof(cmd),
+ .flags = KDBUS_LIST_QUEUED
+ };
if (!g_dbus_is_name (name))
{
return NULL;
}
- if (!g_kdbus_NameHasOwner_internal (kdbus, name, error))
+ if (!g_kdbus_NameHasOwner_internal (worker, name, error))
{
g_set_error (error,
G_DBUS_ERROR,
return NULL;
}
- cmd.flags = KDBUS_NAME_LIST_QUEUED;
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_NAME_LIST, &cmd);
+ ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
if (ret < 0)
{
g_set_error (error,
return NULL;
}
- name_list = (struct kdbus_name_list *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd.offset);
+ name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
unique_name = g_string_new (NULL);
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
- KDBUS_ITEM_FOREACH(kname, name_list, names)
+ KDBUS_FOREACH(kname, name_list, cmd.list_size)
{
struct kdbus_item *item;
const char *item_name = "";
if (strcmp(item_name, name))
continue;
- g_string_printf (unique_name, ":1.%llu", kname->owner_id);
+ g_string_printf (unique_name, ":1.%llu", kname->id);
g_variant_builder_add (builder, "s", item_name);
}
g_variant_builder_unref (builder);
g_string_free (unique_name,TRUE);
- g_kdbus_free_data (kdbus, cmd.offset);
- return result;
-}
-
-
-/**
- * _g_kdbus_NameHasOwner:
- *
- */
-GVariant *
-_g_kdbus_NameHasOwner (GDBusConnection *connection,
- const gchar *name,
- GError **error)
-{
- GKdbus *kdbus;
- GVariant *result;
-
- 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))
- {
- 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_internal (kdbus, name, error))
- result = g_variant_new ("(b)", FALSE);
- else
- result = g_variant_new ("(b)", TRUE);
-
+ g_kdbus_free_data (worker, cmd.offset);
return result;
}
*
*/
static GVariant *
-g_kdbus_GetConnInfo_internal (GDBusConnection *connection,
+g_kdbus_GetConnInfo_internal (GKDBusWorker *worker,
const gchar *name,
guint64 flag,
GError **error)
{
- GKdbus *kdbus;
GVariant *result;
- struct kdbus_cmd_conn_info *cmd;
- struct kdbus_conn_info *conn_info;
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_info *conn_info;
struct kdbus_item *item;
gssize size, len;
gint ret;
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;
- }
if (!g_dbus_is_name (name))
{
return NULL;
}
- if (!g_kdbus_NameHasOwner_internal (kdbus, name, error))
+ if (!g_kdbus_NameHasOwner_internal (worker, name, error))
{
g_set_error (error,
G_DBUS_ERROR,
if (g_dbus_is_unique_name(name))
{
- size = G_STRUCT_OFFSET (struct kdbus_cmd_conn_info, items);
+ 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_conn_info, items) + KDBUS_ITEM_SIZE(len);
+ 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->flags = KDBUS_ATTACH_NAMES;
+ cmd->attach_flags = _KDBUS_ATTACH_ALL;
cmd->size = size;
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_CONN_INFO, cmd);
+ ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
if (ret < 0)
{
g_set_error (error,
return NULL;
}
- conn_info = (struct kdbus_conn_info *) ((guint8 *) kdbus->priv->kdbus_buffer + cmd->offset);
+ conn_info = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd->offset);
/*
if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
{
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 exit;
- }
+ }
+
+ case KDBUS_ITEM_CREDS:
if (flag == G_BUS_CREDS_UID)
{
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;
}
}
exit:
- g_kdbus_free_data (kdbus, cmd->offset);
+ g_kdbus_free_data (worker, cmd->offset);
return result;
}
*
*/
GVariant *
-_g_kdbus_GetNameOwner (GDBusConnection *connection,
+_g_kdbus_GetNameOwner (GKDBusWorker *worker,
const gchar *name,
GError **error)
{
- return g_kdbus_GetConnInfo_internal (connection,
+ return g_kdbus_GetConnInfo_internal (worker,
name,
G_BUS_CREDS_UNIQUE_NAME,
error);
*
*/
GVariant *
-_g_kdbus_GetConnectionUnixProcessID (GDBusConnection *connection,
+_g_kdbus_GetConnectionUnixProcessID (GKDBusWorker *worker,
const gchar *name,
GError **error)
{
- return g_kdbus_GetConnInfo_internal (connection,
+ return g_kdbus_GetConnInfo_internal (worker,
name,
G_BUS_CREDS_PID,
error);
*
*/
GVariant *
-_g_kdbus_GetConnectionUnixUser (GDBusConnection *connection,
+_g_kdbus_GetConnectionUnixUser (GKDBusWorker *worker,
const gchar *name,
GError **error)
{
- return g_kdbus_GetConnInfo_internal (connection,
+ return g_kdbus_GetConnInfo_internal (worker,
name,
G_BUS_CREDS_UID,
error);
}
-/*
- * _g_kdbus_subscribe_name_acquired:
- *
+/**
+ * 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
*/
static void
-_g_kdbus_subscribe_name_owner_changed (GDBusConnection *connection,
- const gchar *name,
- const gchar *old_name,
- const gchar *new_name,
- guint cookie)
+g_kdbus_bloom_add_data (GKDBusWorker *worker,
+ guint64 bloom_data [],
+ const void *data,
+ gsize n)
{
- GKdbus *kdbus;
- struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
- gssize size, len;
- gint ret;
- guint64 old_id;
- guint64 new_id = KDBUS_MATCH_ID_ANY;
+ guint8 hash[8];
+ guint64 bit_num;
+ guint bytes_num = 0;
+ guint cnt_1, cnt_2;
- kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
+ guint c = 0;
+ guint64 p = 0;
- 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);
+ bit_num = worker->bloom_size * 8;
- cmd_match = g_alloca0 (size);
- cmd_match->size = size;
- cmd_match->cookie = cookie;
- item = cmd_match->items;
+ if (bit_num > 1)
+ bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
- if (old_name[0] == 0)
- {
- old_id = KDBUS_MATCH_ID_ANY;
- }
- else
+ for (cnt_1 = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
{
- if (g_dbus_is_unique_name(old_name))
- old_id = old_id+3;
- else
- return;
- }
+ for (cnt_2 = 0; cnt_2 < bytes_num; cnt_2++)
+ {
+ if (c <= 0)
+ {
+ _g_siphash24(hash, data, n, hash_keys[cnt_1++]);
+ c += 8;
+ }
+
+ p = (p << 8ULL) | (guint64) hash[8 - c];
+ c--;
+ }
+
+ p &= bit_num - 1;
+ bloom_data[p >> 6] |= 1ULL << (p & 63);
+ }
+}
+
+
+/**
+ * g_kdbus_bloom_add_pair:
+ *
+ */
+static void
+g_kdbus_bloom_add_pair (GKDBusWorker *worker,
+ guint64 bloom_data [],
+ const gchar *parameter,
+ const gchar *value)
+{
+ gchar buf[1024];
+ gsize size;
+
+ size = strlen(parameter) + strlen(value) + 1;
+ if (size > 1024)
+ return;
+
+ strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
+ g_kdbus_bloom_add_data(worker, bloom_data, buf, size);
+}
+
+
+/**
+ * g_kdbus_bloom_add_prefixes:
+ *
+ */
+static void
+g_kdbus_bloom_add_prefixes (GKDBusWorker *worker,
+ guint64 bloom_data [],
+ const gchar *parameter,
+ const gchar *value,
+ gchar separator)
+{
+ gchar buf[1024];
+ gsize size;
+
+ size = strlen(parameter) + strlen(value) + 1;
+ if (size > 1024)
+ return;
+
+ strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
+
+ for (;;)
+ {
+ gchar *last_sep;
+ last_sep = strrchr(buf, separator);
+ if (!last_sep || last_sep == buf)
+ break;
+
+ *last_sep = 0;
+ g_kdbus_bloom_add_data(worker, bloom_data, buf, last_sep-buf);
+ }
+}
+
+
+/**
+ * _g_kdbus_AddMatch:
+ *
+ */
+void
+_g_kdbus_AddMatch (GKDBusWorker *worker,
+ const gchar *match_rule,
+ guint cookie)
+{
+ Match *match;
+ MatchElement *element;
+ const gchar *sender_name;
+ gsize sender_len, size;
+ struct kdbus_cmd_match *cmd;
+ struct kdbus_item *item;
+ guint64 *bloom;
+ guint64 src_id;
+ gchar *type;
+ gint cnt, ret;
+
+ if (match_rule[0] == '-')
+ return;
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ match_free (match);
+ return;
+ }
+
+ sender_name = NULL;
+ src_id = KDBUS_MATCH_ID_ANY;
+
+ bloom = g_alloca0 (worker->bloom_size);
+ size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_match, items));
+ match = match_new (match_rule);
+
+ for (cnt = 0; cnt < match->n_elements; cnt++)
+ {
+ element = &match->elements[cnt];
+ switch (element->type)
+ {
+ case MATCH_ELEMENT_SENDER:
+ if (g_dbus_is_unique_name(element->value))
+ {
+ src_id = g_ascii_strtoull ((element->value)+3, NULL, 10);
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id));
+ }
+ else if (g_dbus_is_name (element->value))
+ {
+ sender_name = element->value;
+ sender_len = strlen(element->value) + 1;
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len);
+ }
+ else
+ {
+ g_critical ("Error while adding a match: %d", cookie);
+ match_free (match);
+ return;
+ }
+ break;
+
+ case MATCH_ELEMENT_TYPE:
+ g_kdbus_bloom_add_pair (worker, bloom, "message-type", element->value);
+ break;
+
+ case MATCH_ELEMENT_INTERFACE:
+ g_kdbus_bloom_add_pair (worker, bloom, "interface", element->value);
+ break;
+
+ case MATCH_ELEMENT_MEMBER:
+ g_kdbus_bloom_add_pair (worker, bloom, "member", element->value);
+ break;
+
+ case MATCH_ELEMENT_PATH:
+ g_kdbus_bloom_add_pair (worker, bloom, "path", element->value);
+ break;
+
+ case MATCH_ELEMENT_PATH_NAMESPACE:
+ if (g_strcmp0 (element->value, "/"))
+ g_kdbus_bloom_add_pair (worker, bloom, "path-slash-prefix", element->value);
+ break;
+
+ case MATCH_ELEMENT_ARGN:
+ asprintf (&type, "arg%u", element->arg);
+ g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
+ free (type);
+ break;
+
+ case MATCH_ELEMENT_ARGNPATH:
+ asprintf (&type, "arg%u-slash-prefix", element->arg);
+ g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
+ free (type);
+ break;
+
+ case MATCH_ELEMENT_ARG0NAMESPACE:
+ g_kdbus_bloom_add_pair (worker, bloom, "arg0-dot-prefix", element->value);
+ break;
+
+ case MATCH_ELEMENT_DESTINATION:
+ case MATCH_ELEMENT_EAVESDROP:
+ break;
+ }
+ }
+
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, data64) + worker->bloom_size);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+
+ item = cmd->items;
+ item->size = G_STRUCT_OFFSET(struct kdbus_item, data64) + worker->bloom_size;
+ item->type = KDBUS_ITEM_BLOOM_MASK;
+ memcpy(item->data64, bloom, worker->bloom_size);
+ item = KDBUS_ITEM_NEXT(item);
+
+ if (src_id != KDBUS_MATCH_ID_ANY)
+ {
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id);
+ item->type = KDBUS_ITEM_ID;
+ item->id = src_id;
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
+ if (sender_name)
+ {
+ item->size = G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len;
+ item->type = KDBUS_ITEM_NAME;
+ memcpy (item->str, sender_name, sender_len);
+ }
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ g_critical ("Error while adding a match: %d", cookie);
+
+ match_free (match);
+}
+
+
+/**
+ * _g_kdbus_RemoveMatch:
+ *
+ */
+void
+_g_kdbus_RemoveMatch (GKDBusWorker *worker,
+ guint cookie)
+{
+ struct kdbus_cmd_match cmd = {
+ .size = sizeof(cmd),
+ .cookie = cookie
+ };
+ gint ret;
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_REMOVE, &cmd);
+ if (ret < 0)
+ g_warning ("Error while removing a match: %d\n", (int) errno);
+}
+
+
+/**
+ * _g_kdbus_subscribe_name_acquired:
+ *
+ */
+static void
+_g_kdbus_subscribe_name_owner_changed (GKDBusWorker *worker,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name,
+ guint cookie)
+{
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd;
+ gssize size, len;
+ gint ret;
+ guint64 old_id = 0; /* XXX why? */
+ guint64 new_id = KDBUS_MATCH_ID_ANY;
+
+ 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);
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->items;
+
+ 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;
+ }
if (new_name[0] == 0)
{
return;
}
- cmd_match = g_alloca0 (size);
- cmd_match->size = size;
- cmd_match->cookie = cookie;
- item = cmd_match->items;
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->items;
/* KDBUS_ITEM_NAME_CHANGE */
item->type = 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);
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
if (ret < 0)
g_warning ("ERROR - %d\n", (int) errno);
}
-/*
+/**
* _g_kdbus_subscribe_name_acquired:
*
*/
void
-_g_kdbus_subscribe_name_acquired (GDBusConnection *connection,
+_g_kdbus_subscribe_name_acquired (GKDBusWorker *worker,
const gchar *name)
{
- GKdbus *kdbus;
struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
+ struct kdbus_cmd_match *cmd;
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 = 0xbeefbeefbeefbeef;
- cmd_match = g_alloca0 (size);
- cmd_match->size = size;
- cmd_match->cookie = cookie;
- item = cmd_match->items;
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->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;
+ item->name_change.new_id.id = worker->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);
- ret = ioctl(kdbus->priv->fd, KDBUS_CMD_MATCH_ADD, cmd_match);
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
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_subscribe_name_owner_changed (worker, name, "", worker->unique_name, cookie);
}
-/*
+/**
* _g_kdbus_subscribe_name_lost:
*
*/
void
-_g_kdbus_subscribe_name_lost (GDBusConnection *connection,
+_g_kdbus_subscribe_name_lost (GKDBusWorker *worker,
const gchar *name)
{
- GKdbus *kdbus;
struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
+ struct kdbus_cmd_match *cmd;
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;
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->items;
/* KDBUS_ITEM_NAME_REMOVE */
item->type = KDBUS_ITEM_NAME_REMOVE;
- item->name_change.old_id.id = kdbus->priv->unique_id;
+ item->name_change.old_id.id = worker->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);
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
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_subscribe_name_owner_changed (worker, name, worker->unique_name, "", cookie);
}
/**
-* g_kdbus_decode_kernel_msg:
-*
-*/
-static gssize
-g_kdbus_decode_kernel_msg (GKdbus *kdbus)
+ * _g_kdbus_unsubscribe_name_acquired:
+ *
+ */
+void
+_g_kdbus_unsubscribe_name_acquired (GKDBusWorker *worker)
+{
+ guint64 cookie;
+
+ cookie = 0xbeefbeefbeefbeef;
+ _g_kdbus_RemoveMatch (worker, cookie);
+}
+
+
+/**
+ * _g_kdbus_unsubscribe_name_lost:
+ *
+ */
+void
+_g_kdbus_unsubscribe_name_lost (GKDBusWorker *worker)
+{
+ guint64 cookie;
+
+ cookie = 0xdeafdeafdeafdeaf;
+ _g_kdbus_RemoveMatch (worker, cookie);
+}
+
+
+/**
+ * g_kdbus_append_payload_bloom:
+ *
+ */
+static struct kdbus_bloom_filter *
+g_kdbus_append_bloom (struct kdbus_item **item,
+ gsize size)
+{
+ struct kdbus_item *bloom_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;
+
+ bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
+
+ *item = KDBUS_ITEM_NEXT(bloom_item);
+ return &bloom_item->bloom_filter;
+}
+
+
+/**
+ * g_kdbus_setup_bloom:
+ * Based on bus-bloom.c from systemd
+ * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
+ */
+static void
+g_kdbus_setup_bloom (GKDBusWorker *worker,
+ GDBusMessage *dbus_msg,
+ struct kdbus_bloom_filter *bloom_filter)
+{
+ GVariant *body;
+
+ const gchar *message_type;
+ const gchar *interface;
+ const gchar *member;
+ const gchar *path;
+
+ void *bloom_data;
+
+ body = g_dbus_message_get_body (dbus_msg);
+ message_type = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, g_dbus_message_get_message_type (dbus_msg));
+ interface = g_dbus_message_get_interface (dbus_msg);
+ member = g_dbus_message_get_member (dbus_msg);
+ path = g_dbus_message_get_path (dbus_msg);
+
+ bloom_data = bloom_filter->data;
+ memset (bloom_data, 0, worker->bloom_size);
+ bloom_filter->generation = 0;
+
+ g_kdbus_bloom_add_pair(worker, bloom_data, "message-type", message_type);
+
+ if (interface)
+ g_kdbus_bloom_add_pair(worker, bloom_data, "interface", interface);
+
+ if (member)
+ g_kdbus_bloom_add_pair(worker, bloom_data, "member", member);
+
+ if (path)
+ {
+ g_kdbus_bloom_add_pair(worker, bloom_data, "path", path);
+ g_kdbus_bloom_add_pair(worker, bloom_data, "path-slash-prefix", path);
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, "path-slash-prefix", path, '/');
+ }
+
+ if (body != NULL)
+ {
+ const GVariantType *body_type;
+ const GVariantType *arg_type;
+ guint cnt;
+
+ body_type = g_variant_get_type (body);
+
+ for (arg_type = g_variant_type_first (body_type), cnt = 0;
+ arg_type;
+ arg_type = g_variant_type_next (arg_type), cnt++)
+ {
+ gchar type_char = g_variant_type_peek_string (arg_type)[0];
+ gchar buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+ const gchar *str;
+ GVariant *child;
+ gchar *e;
+
+ if (type_char != 's' && type_char != 'o')
+ /* XXX: kdbus docs say "stop after first non-string" but I
+ * think they're wrong (vs. dbus-1 compat)...
+ */
+ continue;
+
+ child = g_variant_get_child_value (body, cnt);
+ str = g_variant_get_string (child, NULL);
+
+ e = stpcpy(buf, "arg");
+ if (cnt < 10)
+ *(e++) = '0' + (char) cnt;
+ else
+ {
+ *(e++) = '0' + (char) (cnt / 10);
+ *(e++) = '0' + (char) (cnt % 10);
+ }
+
+ /* We add this one for both strings and object paths */
+ strcpy(e, "-slash-prefix");
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '/');
+
+ /* But the others are only for strings */
+ if (type_char == 's')
+ {
+ strcpy(e, "-dot-prefix");
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '.');
+
+ *e = 0;
+ g_kdbus_bloom_add_pair(worker, bloom_data, buf, str);
+ }
+
+ g_variant_unref (child);
+ }
+ }
+}
+
+
+/*
+ * TODO: g_kdbus_NameOwnerChanged_generate, g_kdbus_KernelMethodError_generate
+ */
+
+/**
+ * g_kdbus_decode_kernel_msg:
+ *
+ */
+static void
+g_kdbus_decode_kernel_msg (GKDBusWorker *worker,
+ 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)
{
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 (worker, 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 (worker, item);
g_error ("'KernelMethodError'");
break;
#if 0
/* Override information from the user header with data from the kernel */
- g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
+ g_string_printf (worker->msg_sender, "org.freedesktop.DBus");
/* for destination */
- if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_BROADCAST)
+ if (worker->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 if (worker->kmsg->dst_id == KDBUS_DST_ID_NAME)
+ g_string_printf (worker->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) worker->unique_id);
else
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
-#endif
+ g_string_printf (worker->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) worker->kmsg->dst_id);
return size;
+#endif
+}
+
+
+/**
+ * g_kdbus_decode_dbus_msg:
+ *
+ */
+static GDBusMessage *
+g_kdbus_decode_dbus_msg (GKDBusWorker *worker,
+ struct kdbus_msg *msg)
+{
+ GDBusMessage *message;
+ struct kdbus_item *item;
+ gssize data_size = 0;
+ GArray *body_vectors;
+ gsize body_size;
+ GVariant *body;
+ gchar *tmp;
+ guint i;
+ GVariant *parts[2];
+ GVariantIter *fields_iter;
+ guint8 endianness, type, flags, version;
+ guint64 key;
+ GVariant *value;
+ guint64 serial;
+
+
+ message = g_dbus_message_new ();
+
+ body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
+
+ tmp = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
+ g_dbus_message_set_sender (message, tmp);
+ g_free (tmp);
+
+ item = msg->items;
+ body_size = 0;
+
+ KDBUS_ITEM_FOREACH(item, msg, items)
+ {
+ if (item->size <= KDBUS_ITEM_HEADER_SIZE)
+ g_error("[KDBUS] %llu bytes - invalid data record\n", item->size);
+
+ data_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+
+ switch (item->type)
+ {
+ /* KDBUS_ITEM_DST_NAME */
+ case KDBUS_ITEM_DST_NAME:
+ /* 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:
+ {
+ 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);
+
+ 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;
+ const guchar *data;
+ gsize size;
+
+ vector.gbytes = g_bytes_new_take_zero_copy_fd (item->memfd.fd);
+ data = g_bytes_get_data (vector.gbytes, &size);
+
+ g_assert (item->memfd.start + item->memfd.size <= size);
+
+ vector.data.pointer = data + item->memfd.start;
+ vector.size = item->memfd.size;
+
+ g_array_append_val (body_vectors, vector);
+ body_size += vector.size;
+ }
+ break;
+
+ /* KDBUS_ITEM_FDS */
+ case KDBUS_ITEM_FDS:
+ {
+ GUnixFDList *fd_list;
+
+ 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_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_CMDLINE:
+ case KDBUS_ITEM_CGROUP:
+ case KDBUS_ITEM_AUDIT:
+ case KDBUS_ITEM_CAPS:
+ case KDBUS_ITEM_SECLABEL:
+ 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:
+ g_error ("[KDBUS] DBUS_PAYLOAD: Unknown filed - %lld", item->type);
+ break;
+ }
+ }
+
+ body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("((yyyyuta{tv})v)"),
+ (GVariantVector *) body_vectors->data,
+ body_vectors->len, body_size, FALSE);
+ g_assert (body);
+
+ for (i = 0; i < body_vectors->len; i++)
+ g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes);
+
+ g_array_free (body_vectors, TRUE);
+
+ parts[0] = g_variant_get_child_value (body, 0);
+ parts[1] = g_variant_get_child_value (body, 1);
+ g_variant_unref (body);
+
+ body = g_variant_get_variant (parts[1]);
+ g_variant_unref (parts[1]);
+ g_dbus_message_set_body (message, body);
+ g_variant_unref (body);
+
+ g_variant_get (parts[0], "(yyyyuta{tv})", &endianness, &type, &flags, &version, NULL, &serial, &fields_iter);
+ g_variant_unref (parts[0]);
+
+ while (g_variant_iter_loop (fields_iter, "{tv}", &key, &value))
+ g_dbus_message_set_header (message, key, value);
+
+ g_dbus_message_set_flags (message, flags);
+ g_dbus_message_set_serial (message, serial);
+ g_dbus_message_set_message_type (message, type);
+
+ g_print ("Received:\n%s\n", g_dbus_message_print (message, 2));
+
+ (* worker->message_received_callback) (message, worker->user_data);
+
+ g_object_unref (message);
+
+ return 0;
}
* _g_kdbus_receive:
*
*/
-gssize
-_g_kdbus_receive (GKdbus *kdbus,
+static gssize
+_g_kdbus_receive (GKDBusWorker *kdbus,
GCancellable *cancellable,
GError **error)
{
- struct kdbus_cmd_recv recv = {};
- gssize size = 0;
+ struct kdbus_cmd_recv recv;
+ struct kdbus_msg *msg;
+
+ memset (&recv, 0, sizeof recv);
+ recv.size = sizeof (recv);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1;
again:
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_RECV, &recv) < 0)
+ if (ioctl(kdbus->fd, KDBUS_CMD_RECV, &recv) < 0)
{
- if (errno == EINTR || errno == EAGAIN)
+ if (errno == EINTR)
goto again;
+ if (errno == EAGAIN)
+ return 0;
+
+ g_warning ("in holding pattern over %d %d\n", kdbus->fd, errno);
+ while (1)
+ sleep(1);
+
g_set_error (error, G_IO_ERROR,
g_io_error_from_errno (errno),
_("Error while receiving message: %s"),
return -1;
}
- kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
+ g_print ("but sometimes that's okay\n");
+
+ msg = (struct kdbus_msg *)((guint8 *)kdbus->kdbus_buffer + recv.msg.offset);
- if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS)
- g_error ("Received standard dbus message - not supported yet");
- else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL)
- size = g_kdbus_decode_kernel_msg (kdbus);
+ 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,
return -1;
}
- return size;
+ ioctl(kdbus->fd, KDBUS_CMD_FREE, &recv.msg.offset);
+
+ return 0;
+}
+
+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 + G_STRUCT_OFFSET(struct kdbus_item, data);
+
+ if (msg->size + item_size > KDBUS_MSG_MAX_SIZE)
+ return FALSE;
+
+ /* align */
+ msg->size += (-msg->size) & 7;
+ item = (struct kdbus_item *) ((guchar *) msg + msg->size);
+ item->type = type;
+ item->size = item_size;
+ memcpy (item->data, data, size);
+
+ msg->size += item_size;
+
+ 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);
+}
+
+#if 0
+#include "dbusheader.h"
+
+void dump_header (gconstpointer data, gsize size) ;
+void
+dump_header (gconstpointer data,
+ gsize size)
+{
+ GDBusMessageHeaderFieldsIterator iter;
+ GDBusMessageHeader header;
+
+ header = g_dbus_message_header_new (data, size);
+ g_print ("header e/%c t/%u f/x%x v/%u s/%"G_GUINT64_FORMAT"\n",
+ g_dbus_message_header_get_endian (header),
+ g_dbus_message_header_get_type (header),
+ g_dbus_message_header_get_flags (header),
+ g_dbus_message_header_get_version (header),
+ g_dbus_message_header_get_serial (header));
+
+ iter = g_dbus_message_header_iterate_fields (header);
+
+ while (g_dbus_message_header_fields_iterator_next (&iter))
+ {
+ const gchar *string;
+ guint64 reply_to;
+ guint64 key;
+
+ key = g_dbus_message_header_fields_iterator_get_key (iter);
+
+ switch (key)
+ {
+ case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
+ if (g_dbus_message_header_fields_iterator_get_value_as_object_path (iter, &string))
+ g_print (" path: %s\n", string);
+ else
+ g_print (" path: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" interface: %s\n", string);
+ else
+ g_print (" interface: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" member: %s\n", string);
+ else
+ g_print (" member: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" error: %s\n", string);
+ else
+ g_print (" error: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" serial: %s\n", string);
+ else
+ g_print (" serial: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" destination: %s\n", string);
+ else
+ g_print (" destination: <<invalid string>>\n");
+ break;
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
+ if (g_dbus_message_header_fields_iterator_get_value_as_string (iter, &string))
+ g_print (" sender: %s\n", string);
+ else
+ g_print (" sender: <<invalid string>>\n");
+ break;
+
+ default:
+ g_print ("unknown field code %"G_GUINT64_FORMAT"\n", key);
+ g_assert_not_reached ();
+ }
+ }
+
+ g_print ("\n");
+
+}
+#endif
+
+/**
+ * _g_kdbus_send:
+ * Returns: size of data sent or -1 when error
+ */
+static gboolean
+_g_kdbus_send (GKDBusWorker *kdbus,
+ GDBusMessage *message,
+ GError **error)
+{
+ struct kdbus_msg *msg = alloca (KDBUS_MSG_MAX_SIZE);
+ GVariantVectors body_vectors;
+ struct kdbus_cmd_send send;
+
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (kdbus), -1);
+
+ /* 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->unique_id;
+ msg->cookie = g_dbus_message_get_serial(message);
+
+ /* Message destination */
+ {
+ const gchar *dst_name;
+
+ dst_name = g_dbus_message_get_destination (message);
+
+ if (dst_name != NULL)
+ {
+ 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;
+ }
+ }
+ else
+ msg->dst_id = KDBUS_DST_ID_BROADCAST;
+ }
+
+ /* File descriptors */
+ {
+ GUnixFDList *fd_list;
+
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+
+ if (fd_list != NULL)
+ {
+ const gint *fds;
+ gint n_fds;
+
+ 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);
+
+ /* We set the sender field to the correct value for ourselves */
+ g_variant_builder_add (&builder, "{tv}",
+ (guint64) G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
+ g_variant_new_printf (":1.%"G_GUINT64_FORMAT, kdbus->unique_id));
+
+ while (g_hash_table_iter_next (&header_iter, &key, &value))
+ {
+ guint64 key_int = (gsize) key;
+
+ switch (key_int)
+ {
+ /* These are the normal header fields that get passed
+ * straight through.
+ */
+ case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
+ case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
+ case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
+ case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
+ case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
+ case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
+ g_variant_builder_add (&builder, "{tv}", key_int, value);
+ /* This is a little bit gross.
+ *
+ * We must send the header part of the message in a single
+ * vector as per kdbus rules, but the GVariant serialiser
+ * code will split any item >= 128 bytes into its own
+ * vector to save the copy.
+ *
+ * No header field should be that big anyway... right?
+ */
+ g_assert_cmpint (g_variant_get_size (value), <, 128);
+ continue;
+
+ /* We send this one unconditionally, but set it ourselves */
+ case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
+ continue;
+
+ /* We don't send these at all in GVariant format */
+ case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
+ case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
+ continue;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ parts[1] = g_variant_builder_end (&builder);
+
+ body = g_dbus_message_get_body (message);
+ if (!body)
+ body = g_variant_new ("()");
+ parts[2] = g_variant_new_variant (body);
+
+ body = g_variant_ref_sink (g_variant_new_tuple (parts, G_N_ELEMENTS (parts)));
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
+
+ /* Sanity check to make sure the header is really contiguous:
+ *
+ * - we must have at least one vector in the output
+ * - the first vector must completely contain at least the header
+ */
+ g_assert_cmpint (body_vectors.vectors->len, >, 0);
+ g_assert_cmpint (g_array_index (body_vectors.vectors, GVariantVector, 0).size, >=,
+ g_variant_get_size (parts[0]) + g_variant_get_size (parts[1]));
+
+ g_variant_unref (body);
+ }
+
+ {
+ guint i;
+
+ for (i = 0; i < body_vectors.vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
+
+ if (vector.gbytes)
+ {
+ gint fd;
+
+ fd = g_bytes_get_zero_copy_fd (vector.gbytes);
+
+ 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;
+ }
+ }
+
+ /*
+ * set message flags
+ */
+ msg->flags = ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_EXPECT_REPLY) |
+ ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0);
+
+ if ((msg->flags) & KDBUS_MSG_EXPECT_REPLY)
+ msg->timeout_ns = 1000LU * g_get_monotonic_time() + KDBUS_TIMEOUT_NS;
+ else
+ msg->cookie_reply = g_dbus_message_get_reply_serial(message);
+
+
+ /*
+ if (dst_id == KDBUS_DST_ID_BROADCAST)
+ {
+ struct kdbus_bloom_filter *bloom_filter;
+
+ bloom_filter = g_kdbus_append_bloom (&item, kdbus->bloom_size);
+ g_kdbus_setup_bloom (kdbus, message, bloom_filter);
+ }
+ */
+
+ send.size = sizeof (send);
+ send.flags = 0;
+ send.msg_address = (gsize) msg;
+
+ /*
+ * send message
+ */
+//again:
+ if (ioctl(kdbus->fd, KDBUS_CMD_SEND, &send))
+ {
+/*
+ GString *error_name;
+ error_name = g_string_new (NULL);
+
+ if(errno == EINTR)
+ {
+ g_string_free (error_name,TRUE);
+ goto again;
+ }
+ else if (errno == ENXIO)
+ {
+ g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
+ g_kdbus_generate_local_error (worker,
+ dbus_msg,
+ g_variant_new ("(s)",error_name->str),
+ G_DBUS_ERROR_SERVICE_UNKNOWN);
+ g_string_free (error_name,TRUE);
+ return 0;
+ }
+ else if ((errno == ESRCH) || (errno == EADDRNOTAVAIL))
+ {
+ if (kmsg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START)
+ {
+ g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg));
+ g_kdbus_generate_local_error (worker,
+ dbus_msg,
+ g_variant_new ("(s)",error_name->str),
+ G_DBUS_ERROR_SERVICE_UNKNOWN);
+ g_string_free (error_name,TRUE);
+ return 0;
+ }
+ else
+ {
+ g_string_printf (error_name, "The name %s was not provided by any .service files", g_dbus_message_get_destination(dbus_msg));
+ g_kdbus_generate_local_error (worker,
+ dbus_msg,
+ g_variant_new ("(s)",error_name->str),
+ G_DBUS_ERROR_SERVICE_UNKNOWN);
+ g_string_free (error_name,TRUE);
+ return 0;
+ }
+ }
+
+ 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"));
+*/
+ perror("ioctl send");
+ g_error ("IOCTL SEND: %d\n",errno);
+ return FALSE;
+ }
+
+ return TRUE;
+
+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 ();
+}
+
+GKDBusWorker *
+g_kdbus_worker_new (const gchar *address,
+ GError **error)
+{
+ GKDBusWorker *worker;
+
+ worker = g_object_new (G_TYPE_KDBUS_WORKER, NULL);
+ if (!_g_kdbus_open (worker, address, error))
+ {
+ g_object_unref (worker);
+ return NULL;
+ }
+
+ return worker;
+}
+
+void
+g_kdbus_worker_associate (GKDBusWorker *worker,
+ GDBusCapabilityFlags capabilities,
+ GDBusWorkerMessageReceivedCallback message_received_callback,
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
+ GDBusWorkerDisconnectedCallback disconnected_callback,
+ gpointer user_data)
+{
+ worker->capabilities = capabilities;
+ worker->message_received_callback = message_received_callback;
+ worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
+ worker->disconnected_callback = disconnected_callback;
+ worker->user_data = user_data;
+}
+
+void
+g_kdbus_worker_unfreeze (GKDBusWorker *worker)
+{
+ gchar *name;
+
+ if (worker->source != NULL)
+ return;
+
+ worker->context = g_main_context_ref_thread_default ();
+ worker->source = g_unix_fd_source_new (worker->fd, G_IO_IN);
+
+ g_source_set_callback (worker->source, (GSourceFunc) kdbus_ready, worker, NULL);
+ name = g_strdup_printf ("kdbus worker");
+ g_source_set_name (worker->source, name);
+ g_free (name);
+
+ g_source_attach (worker->source, worker->context);
+}
+
+gboolean
+g_kdbus_worker_send_message (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GError **error)
+{
+ return _g_kdbus_send (worker, message, error);
+}
+
+void
+g_kdbus_worker_stop (GKDBusWorker *worker)
+{
+}
+
+void
+g_kdbus_worker_flush_sync (GKDBusWorker *worker)
+{
+}
+
+void
+g_kdbus_worker_close (GKDBusWorker *worker,
+ GCancellable *cancellable,
+ GSimpleAsyncResult *result)
+{
}