#include "glibintl.h"
#include "gunixfdmessage.h"
-#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_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))
#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
+/*
+ * Macros for SipHash algorithm
+ */
+
+#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)
typedef enum
{
guint timed_out : 1;
guchar bus_id[16];
+
+ 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,
{0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35}
};
+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,
+};
+
+/* MatchElement struct */
+typedef struct {
+ guint16 type;
+ guint16 arg;
+ char *value;
+} MatchElement;
+
+/* Match struct */
+typedef struct {
+ int n_elements;
+ MatchElement *elements;
+} Match;
+
+
+/**
+ * SipHash algorithm
+ *
+ */
+static void
+_g_siphash24 (guint8 out[8],
+ const void *_in,
+ gsize inlen,
+ const guint8 k[16])
+{
+ /* "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;
+ }
+
+ v3 ^= b;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= b;
+
+ v2 ^= 0xff;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ b = v0 ^ v1 ^ v2 ^ v3;
+ U64TO8_LE (out, b);
+}
+
+
+/**
+ * is_key()
+ *
+ */
+static gboolean
+is_key (const char *key_start, const char *key_end, char *value)
+{
+ gsize len = strlen (value);
+
+ if (len != key_end - key_start)
+ return FALSE;
+
+ return strncmp (key_start, value, len) == 0;
+}
+
+
+/**
+ * parse_key()
+ *
+ */
+static gboolean
+parse_key (MatchElement *element, const char *key_start, const char *key_end)
+{
+ gboolean res = TRUE;
+
+ 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;
+
+ while (end_digits < key_end && g_ascii_isdigit (*end_digits))
+ end_digits++;
+
+ 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;
+
+ return res;
+}
+
+
+/**
+ * parse_value()
+ *
+ */
+static const char *
+parse_value (MatchElement *element, const char *s)
+{
+ char quote_char;
+ GString *value;
+
+ value = g_string_new ("");
+
+ quote_char = 0;
+
+ for (;*s; s++)
+ {
+ 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);
+ }
+ }
+
+ out:
+ if (quote_char == '\\')
+ g_string_append_c (value, '\\');
+ else if (quote_char == '\'')
+ {
+ g_string_free (value, TRUE);
+ return NULL;
+ }
+
+ element->value = g_string_free (value, FALSE);
+ return s;
+}
+
+
+/**
+ * match_new()
+ *
+ */
+static Match *
+match_new (const char *str)
+{
+ Match *match;
+ GArray *elements;
+ const char *p;
+ const char *key_start;
+ const char *key_end;
+ MatchElement element;
+ int i;
+
+ elements = g_array_new (TRUE, TRUE, sizeof (MatchElement));
+
+ p = str;
+
+ while (*p != 0)
+ {
+ memset (&element, 0, sizeof (element));
+
+ /* Skip initial whitespace */
+ while (*p && g_ascii_isspace (*p))
+ p++;
+
+ key_start = p;
+
+ /* Read non-whitespace non-equals chars */
+ while (*p && *p != '=' && !g_ascii_isspace (*p))
+ p++;
+
+ key_end = p;
+
+ /* Skip any whitespace after key */
+ while (*p && g_ascii_isspace (*p))
+ p++;
+
+ if (key_start == key_end)
+ continue; /* Allow trailing whitespace */
+ if (*p != '=')
+ goto error;
+
+ ++p;
+
+ if (!parse_key (&element, key_start, key_end))
+ goto error;
+
+ p = parse_value (&element, p);
+ if (p == NULL)
+ goto error;
+
+ g_array_append_val (elements, element);
+ }
+
+ match = g_new0 (Match, 1);
+ match->n_elements = elements->len;
+ match->elements = (MatchElement *)g_array_free (elements, FALSE);
+
+ return match;
+
+ error:
+ for (i = 0; i < elements->len; i++)
+ g_free (g_array_index (elements, MatchElement, i).value);
+ g_array_free (elements, TRUE);
+ return NULL;
+}
+
+
+/**
+ * match_free()
+ *
+ */
+static void
+match_free (Match *match)
+{
+ int i;
+ for (i = 0; i < match->n_elements; i++)
+ g_free (match->elements[i].value);
+ g_free (match->elements);
+ g_free (match);
+}
+
+
/**
* g_kdbus_finalize:
*
}
gboolean
-_g_kdbus_open (GKDBusWorker *worker,
- const gchar *address,
- GError **error)
+_g_kdbus_open (GKDBusWorker *worker,
+ const gchar *address,
+ GError **error)
{
g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
worker->closed = FALSE;
- 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);
- g_source_attach (worker->source, worker->context);
-
return TRUE;
}
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->fd, KDBUS_CMD_FREE, &cmd);
if (ret < 0)
return FALSE;
_g_kdbus_Hello (GKDBusWorker *worker,
GError **error)
{
- struct kdbus_cmd_hello *hello;
+ struct kdbus_cmd_hello *cmd;
struct kdbus_item *item;
gchar *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->flags = worker->flags;
- hello->attach_flags_send = worker->attach_flags_send;
- hello->attach_flags_recv = worker->attach_flags_recv;
- 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_DESCRIPTION;
memcpy (item->str, conn_name, conn_name_size+1);
item = KDBUS_ITEM_NEXT (item);
- if (ioctl(worker->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;
}
- if (hello->bus_flags > 0xFFFFFFFFULL)
+ if (cmd->bus_flags > 0xFFFFFFFFULL)
{
g_set_error_literal (error,
G_IO_ERROR,
return NULL;
}
- memcpy (worker->bus_id, hello->id128, 16);
+ memcpy (worker->bus_id, cmd->id128, 16);
- worker->unique_id = hello->id;
- asprintf(&worker->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);
/* read bloom filters parameters */
- worker->bloom_size = (gsize) hello->bloom.size;
- worker->bloom_n_hash = (guint) hello->bloom.n_hash;
+ //worker->bloom_size = (gsize) cmd->bloom.size;
+ //worker->bloom_n_hash = (guint) cmd->bloom.n_hash;
return g_variant_new ("(s)", worker->unique_name);
}
GError **error)
{
GVariant *result;
- struct kdbus_cmd_name *kdbus_name;
+ struct kdbus_cmd *cmd;
guint64 kdbus_flags;
gssize len, size;
gint status, ret;
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(worker->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)
}
}
- if (kdbus_name->flags & KDBUS_NAME_IN_QUEUE)
+ if (cmd->return_flags & KDBUS_NAME_IN_QUEUE)
status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
result = g_variant_new ("(u)", status);
GError **error)
{
GVariant *result;
- struct kdbus_cmd_name *kdbus_name;
+ struct kdbus_cmd *cmd;
gssize len, size;
gint status, ret;
}
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(worker->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)
{
GVariant *result;
GVariantBuilder *builder;
-
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_name_info *name;
+ struct kdbus_info *name_list, *name;
+ struct kdbus_cmd_list cmd = {
+ .size = sizeof(cmd)
+ };
guint64 prev_id;
gint ret;
prev_id = 0;
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(worker->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 *) worker->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)
*/
GVariant *
_g_kdbus_GetListQueuedOwners (GKDBusWorker *worker,
- const gchar *name,
- GError **error)
+ const gchar *name,
+ GError **error)
{
GVariant *result;
GVariantBuilder *builder;
GString *unique_name;
gint ret;
- struct kdbus_cmd_name_list cmd = {};
- struct kdbus_name_list *name_list;
- struct kdbus_name_info *kname;
+ 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;
}
- cmd.flags = KDBUS_NAME_LIST_QUEUED;
- ret = ioctl(worker->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 *) worker->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);
}
memcpy (cmd->items[0].str, name, len);
}
- cmd->flags = _KDBUS_ATTACH_ALL;
+ cmd->attach_flags = _KDBUS_ATTACH_ALL;
cmd->size = size;
ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
/**
- * _g_kdbus_match_remove:
+ * 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_bloom_add_data (GKDBusWorker *worker,
+ guint64 bloom_data [],
+ const void *data,
+ gsize n)
+{
+ guint8 hash[8];
+ guint64 bit_num;
+ guint bytes_num = 0;
+ guint cnt_1, cnt_2;
+
+ guint c = 0;
+ guint64 p = 0;
+
+ bit_num = worker->bloom_size * 8;
+
+ if (bit_num > 1)
+ bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
+
+ for (cnt_1 = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
+ {
+ 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_match_remove (GKDBusWorker *worker,
- guint cookie)
+g_kdbus_bloom_add_pair (GKDBusWorker *worker,
+ guint64 bloom_data [],
+ const gchar *parameter,
+ const gchar *value)
{
- struct kdbus_cmd_match cmd_match = {};
- gint ret;
+ 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);
+}
+
- cmd_match.size = sizeof (cmd_match);
- cmd_match.cookie = cookie;
+/**
+ * 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);
+ }
+}
- ret = ioctl(worker->fd, KDBUS_CMD_MATCH_REMOVE, &cmd_match);
+
+/**
+ * _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_warning ("ERROR - %d\n", (int) errno);
+ 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);
}
guint cookie)
{
struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
+ struct kdbus_cmd_match *cmd;
gssize size, len;
gint ret;
guint64 old_id = 0; /* XXX why? */
G_STRUCT_OFFSET (struct kdbus_item, name_change) +
G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
- 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;
if (old_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(worker->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);
}
const gchar *name)
{
struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
+ struct kdbus_cmd_match *cmd;
gssize size, len;
guint64 cookie;
gint ret;
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;
G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
item = KDBUS_ITEM_NEXT(item);
- ret = ioctl(worker->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);
const gchar *name)
{
struct kdbus_item *item;
- struct kdbus_cmd_match *cmd_match;
+ struct kdbus_cmd_match *cmd;
gssize size, len;
guint64 cookie;
gint ret;
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;
G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
item = KDBUS_ITEM_NEXT(item);
- ret = ioctl(worker->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);
guint64 cookie;
cookie = 0xbeefbeefbeefbeef;
- _g_kdbus_match_remove (worker, cookie);
+ _g_kdbus_RemoveMatch (worker, cookie);
}
guint64 cookie;
cookie = 0xdeafdeafdeafdeaf;
- _g_kdbus_match_remove (worker, cookie);
+ _g_kdbus_RemoveMatch (worker, cookie);
}
/**
- * 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_bloom_add_data (GKDBusWorker *worker,
- guint64 bloom_data [],
- const void *data,
- gsize n)
-{
- guint8 hash[8];
- guint64 bit_num;
- guint bytes_num = 0;
- guint cnt_1, cnt_2;
-
- guint c = 0;
- guint64 p = 0;
-
- bit_num = worker->bloom_size * 8;
-
- if (bit_num > 1)
- bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
-
- for (cnt_1 = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
- {
- 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)
-{
- GString *data = g_string_new (NULL);
-
- g_string_printf (data,"%s:%s",parameter,value);
- g_kdbus_bloom_add_data(worker, bloom_data, data->str, data->len);
- g_string_free (data, TRUE);
-}
-
-
-/**
- * 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)
-{
- GString *data = g_string_new (NULL);
-
- g_string_printf (data,"%s:%s",parameter,value);
-
- for (;;)
- {
- gchar *last_sep;
- last_sep = strrchr(data->str, separator);
- if (!last_sep || last_sep == data->str)
- break;
-
- *last_sep = 0;
- g_kdbus_bloom_add_data(worker, bloom_data, data->str, last_sep-(data->str));
- }
- g_string_free (data, TRUE);
-}
-
-
-/**
* 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
struct kdbus_bloom_filter *bloom_filter)
{
GVariant *body;
- GVariantIter iter;
- GVariant *child;
const gchar *message_type;
const gchar *interface;
const gchar *path;
void *bloom_data;
- gint cnt = 0;
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));
if (body != NULL)
{
- g_variant_iter_init (&iter, body);
- while ((child = g_variant_iter_next_value (&iter)))
+ 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")];
- gchar *child_string;
+ const gchar *str;
+ GVariant *child;
gchar *e;
- /* Is it necessary? */
- //if (g_variant_is_container (child))
- // iterate_container_recursive (child);
-
- if (!(g_variant_is_of_type (child, G_VARIANT_TYPE_STRING)) &&
- !(g_variant_is_of_type (child, G_VARIANT_TYPE_OBJECT_PATH)) &&
- !(g_variant_is_of_type (child, G_VARIANT_TYPE_SIGNATURE)))
- break;
+ 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_string = g_variant_dup_string (child, NULL);
+ 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 % 10);
}
- *e = 0;
- g_kdbus_bloom_add_pair(worker, bloom_data, buf, child_string);
+ /* We add this one for both strings and object paths */
+ strcpy(e, "-slash-prefix");
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '/');
- strcpy(e, "-dot-prefix");
- g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, child_string, '.');
+ /* 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, '.');
- strcpy(e, "-slash-prefix");
- g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, child_string, '/');
+ *e = 0;
+ g_kdbus_bloom_add_pair(worker, bloom_data, buf, str);
+ }
- g_free (child_string);
g_variant_unref (child);
- cnt++;
}
}
}
flavour = body_size & 7;
g_assert ((item->vec.offset & 7) == flavour);
- vector.gbytes = g_bytes_new (((guchar *) worker->kdbus_buffer) + item->vec.offset - flavour, item->vec.size + 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;
case KDBUS_ITEM_CREDS:
{
- g_print ("creds: u%u eu %u su%u fsu%u g%u eg%u sg%u fsg%u\n",
+ g_print ("creds: u%llu eu %llu su%llu fsu%llu g%llu eg%llu sg%llu fsg%llu\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;
g_print ("Received:\n%s\n", g_dbus_message_print (message, 2));
- return message;
+ (* worker->message_received_callback) (message, worker->user_data);
+
+ g_object_unref (message);
+
+ return 0;
}
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;
}
- msg = (struct kdbus_msg *)((guint8 *)kdbus->kdbus_buffer + recv.reply.offset);
+ g_print ("but sometimes that's okay\n");
+
+ msg = (struct kdbus_msg *)((guint8 *)kdbus->kdbus_buffer + recv.msg.offset);
if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
g_kdbus_decode_dbus_msg (kdbus, msg);
return -1;
}
- ioctl(kdbus->fd, KDBUS_CMD_FREE, &recv.reply.offset);
+ ioctl(kdbus->fd, KDBUS_CMD_FREE, &recv.msg.offset);
return 0;
}
((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 = 2000000000;
+ msg->timeout_ns = 1000LU * g_get_monotonic_time() + KDBUS_TIMEOUT_NS;
else
msg->cookie_reply = g_dbus_message_get_reply_serial(message);
GKDBusWorker *
g_kdbus_worker_new (const gchar *address,
GError **error)
-#if 0
- GDBusCapabilityFlags capabilities,
- gboolean initially_frozen,
- GDBusWorkerMessageReceivedCallback message_received_callback,
- GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
- GDBusWorkerDisconnectedCallback disconnected_callback,
- gpointer user_data)
-#endif
{
GKDBusWorker *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