#include "gdbusprivate.h"
#ifdef G_OS_UNIX
-#include "gkdbus.h"
#include "gunixfdlist.h"
#endif
/* ---------------------------------------------------------------------------------------------------- */
-/**
- * _g_dbus_message_get_protocol_ver:
- * To remove - more info [1]
- * [1] https://bugzilla.gnome.org/show_bug.cgi?id=721861
- */
-guint32
-_g_dbus_message_get_protocol_ver (GDBusMessage *message)
-{
- g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), 0);
- return message->major_protocol_version;
-}
-
-/**
- * _g_dbus_message_set_protocol_ver:
- * To remove - more info [1]
- * [1] https://bugzilla.gnome.org/show_bug.cgi?id=721861
- */
-void
-_g_dbus_message_set_protocol_ver (GDBusMessage *message,
- guint32 protocol_ver)
-{
- g_return_if_fail (G_IS_DBUS_MESSAGE (message));
-
- if (message->locked)
- {
- g_warning ("%s: Attempted to modify a locked message", G_STRFUNC);
- return;
- }
-
- message->major_protocol_version = protocol_ver;
-}
-
/* TODO: need GI annotations to specify that any guchar value goes for header_field */
/**
/* ---------------------------------------------------------------------------------------------------- */
-/*
- * _g_dbus_message_new_from_kdbus_items:
- *
- * Single kdbus message may contain zero, one or more items
- * (PAYLOAD_VEC or PAYLOAD_MEMFD), so we need this function
- * (only for kdbus transport purposes) to parse them to GDBusMessage.
- * kdbus_msg_items list contain list of pointer + data pair for each received item.
- *
- * TODO: Add support for two and more items
- */
-
-GDBusMessage *
-_g_dbus_message_new_from_kdbus_items (GSList *kdbus_msg_items,
- GError **error)
-{
- gboolean ret;
- GMemoryBuffer mbuf;
- GDBusMessage *message;
- guchar endianness;
- guchar major_protocol_version;
- guint32 message_body_len;
- guint32 message_headers_len;
- GVariant *headers;
- GVariant *item;
- GVariantIter iter;
- GVariant *signature;
-
- ret = FALSE;
-
- g_return_val_if_fail (kdbus_msg_items != NULL, NULL);
- g_return_val_if_fail (error == NULL || *error == NULL, NULL);
-
- message = g_dbus_message_new ();
- memset (&mbuf, 0, sizeof (mbuf));
-
- /*
- * MESSAGE HEADER
- * message header in its entirety must be contained in a first single item
- */
- mbuf.data = ((msg_part*)kdbus_msg_items->data)->data;
- mbuf.len = mbuf.valid_len = ((msg_part*)kdbus_msg_items->data)->size;
-
- endianness = g_memory_buffer_read_byte (&mbuf);
- switch (endianness)
- {
- case 'l':
- mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN;
- message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN;
- break;
- case 'B':
- mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN;
- message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN;
- break;
- default:
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Invalid endianness value. Expected 0x6c ('l') or 0x42 ('B') but found value 0x%02x"),
- endianness);
- goto out;
- }
-
- message->type = g_memory_buffer_read_byte (&mbuf);
- message->flags = g_memory_buffer_read_byte (&mbuf);
- major_protocol_version = g_memory_buffer_read_byte (&mbuf);
-
- if (major_protocol_version != 2)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Invalid major protocol version. Expected 2 but found %d"),
- major_protocol_version);
- goto out;
- }
-
- message_body_len = g_memory_buffer_read_uint32 (&mbuf);
- message->serial = g_memory_buffer_read_uint32 (&mbuf);
-
- message_headers_len = g_memory_buffer_read_uint32 (&mbuf);
- headers = g_variant_new_from_data (G_VARIANT_TYPE ("a{yv}"),
- mbuf.data + mbuf.pos,
- message_headers_len,
- TRUE,
- NULL,
- NULL);
- mbuf.pos += message_headers_len;
-
- if (headers == NULL)
- goto out;
- g_variant_iter_init (&iter, headers);
- while ((item = g_variant_iter_next_value (&iter)) != NULL)
- {
- guchar header_field;
- GVariant *value;
- g_variant_get (item,
- "{yv}",
- &header_field,
- &value);
- g_dbus_message_set_header (message, header_field, value);
- g_variant_unref (value);
- g_variant_unref (item);
- }
- g_variant_unref (headers);
-
- signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE);
- if (signature != NULL)
- {
- const gchar *signature_str;
- gsize signature_str_len;
-
- signature_str = g_variant_get_string (signature, &signature_str_len);
-
- if (signature_str_len > 0)
- {
- GVariantType *variant_type;
- gchar *tupled_signature_str;
-
- gchar *data = NULL;
- gsize size = NULL;
-
- if (!g_variant_is_signature (signature_str))
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Parsed value '%s' is not a valid D-Bus signature (for body)"),
- signature_str);
- goto out;
- }
- tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
- variant_type = g_variant_type_new (tupled_signature_str);
- g_free (tupled_signature_str);
-
- /*
- * MESSAGE BODY
- */
-
- if (g_slist_length(kdbus_msg_items) == 1)
- {
- /* if kdbus_msg_items has only one element, head and body are
- contained in a single PAYLOAD_VEC item */
- ensure_input_padding (&mbuf,8);
- data = mbuf.data + mbuf.pos;
- size = message_body_len;
- }
- else if (g_slist_length(kdbus_msg_items) > 1)
- {
- /* message consists two or more items
- TODO: Add support for three and more items */
- data = ((msg_part*)g_slist_next(kdbus_msg_items)->data)->data;
- size = ((msg_part*)g_slist_next(kdbus_msg_items)->data)->size;
- }
- else
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("[KDBUS] Received message is not valid"));
- goto out;
- }
-
- message->body = g_variant_new_from_data (variant_type,
- data,
- size,
- TRUE,
- NULL,
- NULL);
-
- g_variant_type_free (variant_type);
- if (message->body == NULL)
- goto out;
- }
- }
- else
- {
- /* no signature, this is only OK if the body is empty */
- if (message_body_len != 0)
- {
- /* G_GUINT32_FORMAT doesn't work with gettext, just use %u */
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- g_dngettext (GETTEXT_PACKAGE,
- "No signature header in message but the message body is %u byte",
- "No signature header in message but the message body is %u bytes",
- message_body_len),
- message_body_len);
- goto out;
- }
- }
-
- if (!validate_headers (message, error))
- {
- g_prefix_error (error, _("Cannot deserialize message: "));
- goto out;
- }
-
- ret = TRUE;
-
- out:
- if (ret)
- {
- return message;
- }
- else
- {
- if (message != NULL)
- g_object_unref (message);
- return NULL;
- }
-}
-
static gsize
ensure_output_padding (GMemoryBuffer *mbuf,
gsize padding_size)
/* ---------------------------------------------------------------------------------------------------- */
-/* [KDBUS]
- * g_dbus_message_to_blob() will be replaced by new function only for kdbus transport
- * purposes (this function will be able to create blob directly/unconditionally in memfd
- * object, without making copy)
- */
-
/**
* g_dbus_message_to_blob:
* @message: A #GDBusMessage.
goffset body_len_offset;
goffset body_start_offset;
gsize body_size;
- gconstpointer message_body_data;
- gsize message_body_size;
GVariant *header_fields;
- gsize header_fields_size;
- gconstpointer header_fields_data;
GVariantBuilder builder;
GHashTableIter hash_iter;
gpointer key;
g_return_val_if_fail (out_size != NULL, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- /* temporary solution */
- if (!message->major_protocol_version)
- g_error ("message->major_protocol_version is not set");
-
- if (message->major_protocol_version != 1 && message->major_protocol_version != 2)
- {
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_INVALID_ARGUMENT,
- _("Invalid major protocol version. Expected 1 or 2 but found %d"),
- message->major_protocol_version);
- goto out;
- }
-
memset (&mbuf, 0, sizeof (mbuf));
mbuf.len = MIN_ARRAY_SIZE;
mbuf.data = g_malloc (mbuf.len);
g_memory_buffer_put_byte (&mbuf, (guchar) message->byte_order);
g_memory_buffer_put_byte (&mbuf, message->type);
g_memory_buffer_put_byte (&mbuf, message->flags);
-
- /* major protocol version */
- g_memory_buffer_put_byte (&mbuf, message->major_protocol_version);
-
+ g_memory_buffer_put_byte (&mbuf, 1); /* major protocol version */
body_len_offset = mbuf.valid_len;
/* body length - will be filled in later */
g_memory_buffer_put_uint32 (&mbuf, 0xF00DFACE);
}
header_fields = g_variant_builder_end (&builder);
- /* header - dbus1 marshaliling */
- if (message->major_protocol_version == 1)
- {
- if (!append_value_to_blob (header_fields,
- g_variant_get_type (header_fields),
- &mbuf,
- NULL,
- error))
- {
- g_variant_unref (header_fields);
- goto out;
- }
-
- }
- /* header - GVariant marshalling */
- else if (message->major_protocol_version == 2)
+ if (!append_value_to_blob (header_fields,
+ g_variant_get_type (header_fields),
+ &mbuf,
+ NULL,
+ error))
{
- header_fields_data = g_variant_get_data (header_fields);
- header_fields_size = g_variant_get_size (header_fields);
-
- g_memory_buffer_put_uint32 (&mbuf, header_fields_size);
- g_memory_buffer_write (&mbuf, header_fields_data, header_fields_size);
+ g_variant_unref (header_fields);
+ goto out;
}
-
g_variant_unref (header_fields);
/* header size must be a multiple of 8 */
goto out;
}
g_free (tupled_signature_str);
-
- /* body - dbus1 marshaliling */
- if (message->major_protocol_version == 1)
- {
- if (!append_body_to_blob (message->body, &mbuf, error))
- goto out;
- }
-#if 0
- /* body - GVariant marshalling */
- else if (message->major_protocol_version == 2)
- {
- message_body_data = g_variant_get_data (message->body);
- message_body_size = g_variant_get_size (message->body);
-
- g_memory_buffer_write (&mbuf, message_body_data, message_body_size);
- }
-#endif
+ if (!append_body_to_blob (message->body, &mbuf, error))
+ goto out;
}
else
{
#endif
return ret;
}
+
+void
+g_dbus_message_init_header_iter (GDBusMessage *message,
+ GHashTableIter *iter)
+{
+ g_hash_table_iter_init (iter, message->headers);
+}
gint fd;
gchar *kdbus_buffer;
- struct kdbus_msg *kmsg;
gchar *unique_name;
guint64 unique_id;
guint64 attach_flags_send;
guint64 attach_flags_recv;
- GString *msg_sender;
- GString *msg_destination;
- GSList *kdbus_msg_items;
-
- gint *fds;
- gint num_fds;
-
gsize bloom_size;
guint bloom_n_hash;
/**
- * _g_kdbus_get_last_msg_sender
- *
- */
-gchar *
-_g_kdbus_get_last_msg_sender (GKdbus *kdbus)
-{
- return kdbus->priv->msg_sender->str;
-}
-
-
-/**
- * _g_kdbus_get_last_msg_destination
- *
- */
-gchar *
-_g_kdbus_get_last_msg_destination (GKdbus *kdbus)
-{
- return kdbus->priv->msg_destination->str;
-}
-
-
-/**
- * _g_kdbus_get_last_msg_items:
- *
- */
-GSList *
-_g_kdbus_get_last_msg_items (GKdbus *kdbus)
-{
- return kdbus->priv->kdbus_msg_items;
-}
-
-
-/**
- * g_kdbus_add_msg_part:
- *
- */
-static void
-g_kdbus_add_msg_part (GKdbus *kdbus,
- gchar *data,
- gsize size)
-{
- msg_part* part = g_new (msg_part, 1);
- part->data = data;
- part->size = size;
- kdbus->priv->kdbus_msg_items = g_slist_append (kdbus->priv->kdbus_msg_items, part);
-}
-
-
-/**
* _g_kdbus_hexdump_all_items:
*
*/
if (kdbus->priv->fd != -1 && !kdbus->priv->closed)
_g_kdbus_close (kdbus, NULL);
- g_string_free (kdbus->priv->msg_sender, TRUE);
- g_string_free (kdbus->priv->msg_destination, TRUE);
-
if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize)
(*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object);
}
kdbus->priv->unique_name = NULL;
kdbus->priv->kdbus_buffer = NULL;
- kdbus->priv->kdbus_msg_items = NULL;
-
- kdbus->priv->msg_sender = g_string_new (NULL);
- kdbus->priv->msg_destination = g_string_new (NULL);
kdbus->priv->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */
kdbus->priv->attach_flags_send = _KDBUS_ATTACH_ALL;
kdbus->priv->attach_flags_recv = _KDBUS_ATTACH_ALL;
-
- kdbus->priv->fds = NULL;
- kdbus->priv->num_fds = 0;
}
struct kdbus_cmd_match *cmd_match;
gssize size, len;
gint ret;
- guint64 old_id;
+ guint64 old_id = 0; /* XXX why? */
guint64 new_id = KDBUS_MATCH_ID_ANY;
kdbus = _g_kdbus_connection_get_kdbus (G_KDBUS_CONNECTION (g_dbus_connection_get_stream (connection)));
/**
- * _g_kdbus_release_msg:
- *
- */
-void
-_g_kdbus_release_kmsg (GKdbus *kdbus)
-{
- struct kdbus_item *item = NULL;
- GSList *iterator = NULL;
- guint64 offset;
-
- offset = (guint8 *)kdbus->priv->kmsg - (guint8 *)kdbus->priv->kdbus_buffer;
- ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &offset);
-
- for (iterator = kdbus->priv->kdbus_msg_items; iterator; iterator = iterator->next)
- g_free ((msg_part*)iterator->data);
-
- g_slist_free (kdbus->priv->kdbus_msg_items);
- kdbus->priv->kdbus_msg_items = NULL;
-
- KDBUS_ITEM_FOREACH (item, kdbus->priv->kmsg, items)
- {
- if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD)
- close(item->memfd.fd);
- else if (item->type == KDBUS_ITEM_FDS)
- {
- gint i;
- gint num_fds = (item->size - G_STRUCT_OFFSET(struct kdbus_item, fds)) / sizeof(int);
-
- for (i = 0; i < num_fds; i++)
- close(item->fds[i]);
- }
- }
-}
-
-
-/**
- * g_kdbus_append_payload_vec:
- *
- */
-static void
-g_kdbus_append_payload_vec (struct kdbus_item **item,
- const void *data_ptr,
- gssize size)
-{
- *item = KDBUS_ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, vec) + sizeof(struct kdbus_vec);
- (*item)->type = KDBUS_ITEM_PAYLOAD_VEC;
- (*item)->vec.address = (guint64)((guintptr)data_ptr);
- (*item)->vec.size = size;
- *item = KDBUS_ITEM_NEXT(*item);
-}
-
-/**
- * g_kdbus_append_payload_memfd:
- *
- */
-static void
-g_kdbus_append_payload_memfd (struct kdbus_item **item,
- gint fd,
- gssize size)
-{
- *item = KDBUS_ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
- (*item)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
- (*item)->memfd.fd = fd;
- (*item)->memfd.size = size;
- *item = KDBUS_ITEM_NEXT(*item);
-}
-
-
-/**
- * g_kdbus_append_payload_destiantion:
- *
- */
-static void
-g_kdbus_append_destination (struct kdbus_item **item,
- const gchar *destination,
- gsize size)
-{
- *item = KDBUS_ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, str) + size + 1;
- (*item)->type = KDBUS_ITEM_DST_NAME;
- memcpy ((*item)->str, destination, size+1);
- *item = KDBUS_ITEM_NEXT(*item);
-}
-
-
-/**
* g_kdbus_append_payload_bloom:
*
*/
/**
- * g_kdbus_append_fds:
- *
- */
-static void
-g_kdbus_append_fds (struct kdbus_item **item,
- GUnixFDList *fd_list)
-{
- *item = KDBUS_ALIGN8_PTR(*item);
- (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list);
- (*item)->type = KDBUS_ITEM_FDS;
- memcpy ((*item)->fds, g_unix_fd_list_peek_fds(fd_list, NULL), sizeof(int) * g_unix_fd_list_get_length(fd_list));
-
- *item = KDBUS_ITEM_NEXT(*item);
-}
-
-
-/**
- * _g_kdbus_attach_fds_to_msg:
- *
- */
-void
-_g_kdbus_attach_fds_to_msg (GKdbus *kdbus,
- GUnixFDList **fd_list)
-{
- if ((kdbus->priv->fds != NULL) && (kdbus->priv->num_fds > 0))
- {
- gint n;
-
- if (*fd_list == NULL)
- *fd_list = g_unix_fd_list_new();
-
- for (n = 0; n < kdbus->priv->num_fds; n++)
- {
- g_unix_fd_list_append (*fd_list, kdbus->priv->fds[n], NULL);
- (void) g_close (kdbus->priv->fds[n], NULL);
- }
-
- g_free (kdbus->priv->fds);
- kdbus->priv->fds = NULL;
- kdbus->priv->num_fds = 0;
- }
-}
-
-/**
* g_kdbus_bloom_add_data:
* Based on bus-bloom.c from systemd
* http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
* g_kdbus_decode_kernel_msg:
*
*/
-static gssize
-g_kdbus_decode_kernel_msg (GKdbus *kdbus)
+static void
+g_kdbus_decode_kernel_msg (GKdbus *kdbus,
+ struct kdbus_msg *msg)
{
struct kdbus_item *item = NULL;
- gssize size = 0;
- KDBUS_ITEM_FOREACH(item, kdbus->priv->kmsg, items)
+ KDBUS_ITEM_FOREACH(item, msg, items)
{
switch (item->type)
{
}
}
-
+#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 (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
return size;
+#endif
}
*
*/
static GDBusMessage *
-g_kdbus_decode_dbus_msg (GKdbus *kdbus,
- struct kdbus_cmd_recv *recv)
+g_kdbus_decode_dbus_msg (GKdbus *kdbus,
+ struct kdbus_msg *msg)
{
+ GDBusMessage *message;
struct kdbus_item *item;
gssize data_size = 0;
- const gchar *destination = NULL;
GArray *body_vectors;
gsize body_size;
GVariant *body;
+ gchar *tmp;
guint i;
+ message = g_dbus_message_new ();
+
+ tmp = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
+ g_dbus_message_set_sender (message, tmp);
+ g_free (tmp);
+
body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
body_size = 0;
- KDBUS_ITEM_FOREACH(item, (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv->offset), items)
+ KDBUS_ITEM_FOREACH(item, msg, items)
{
if (item->size <= KDBUS_ITEM_HEADER_SIZE)
g_error("[KDBUS] %llu bytes - invalid data record\n", item->size);
{
/* KDBUS_ITEM_DST_NAME */
case KDBUS_ITEM_DST_NAME:
- destination = item->str;
+ /* Classic D-Bus doesn't make this known to the receiver, so
+ * we don't do it here either (for compatibility with the
+ * fallback case).
+ */
break;
/* KDBUS_ITEM_PALOAD_OFF */
flavour = body_size & 7;
//g_assert ((item->vec.offset & 7) == flavour); FIXME: kdbus bug doesn't count memfd in flavouring
- vector.gbytes = g_bytes_new (((guchar *) kdbus->priv->kmsg) + 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;
/* KDBUS_ITEM_FDS */
case KDBUS_ITEM_FDS:
+ {
+ GUnixFDList *fd_list;
- kdbus->priv->num_fds = data_size / sizeof(int);
- kdbus->priv->fds = g_malloc0 (sizeof(int) * kdbus->priv->num_fds);
- memcpy(kdbus->priv->fds, item->fds, sizeof(int) * kdbus->priv->num_fds);
-
+ fd_list = g_unix_fd_list_new_from_array (item->fds, data_size / sizeof (int));
+ g_dbus_message_set_unix_fd_list (message, fd_list);
+ g_object_unref (fd_list);
+ }
break;
/* All of the following items, like CMDLINE,
}
case KDBUS_ITEM_PIDS:
- {
- }
-
case KDBUS_ITEM_PID_COMM:
case KDBUS_ITEM_TID_COMM:
case KDBUS_ITEM_EXE:
g_array_free (body_vectors, TRUE);
- g_print ("body is %s\n", g_variant_print (body, TRUE));
-
- /* Override information from the user header with data from the kernel */
-
- if (kdbus->priv->kmsg->src_id == KDBUS_SRC_ID_KERNEL)
- g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus");
- else
- g_string_printf (kdbus->priv->msg_sender, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->src_id);
-
- if (destination)
- g_string_printf (kdbus->priv->msg_destination, "%s", destination);
- else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_BROADCAST)
- /* for broadcast messages we don't have to set destination */
- ;
- else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_NAME)
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id);
- else
- g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id);
+ g_dbus_message_set_body (message, body);
+ g_variant_unref (body);
- return NULL;
+ return message;
}
GError **error)
{
struct kdbus_cmd_recv recv = {};
+ struct kdbus_msg *msg;
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return -1;
return -1;
}
- kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
+ msg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset);
- if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS)
- g_kdbus_decode_dbus_msg (kdbus, &recv);
- else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL)
- 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;
}
+ ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &recv.offset);
+
return 0;
}
+struct dbus_fixed_header {
+ guint8 endian;
+ guint8 type;
+ guint8 flags;
+ guint8 version;
+ guint32 reserved;
+ guint64 serial;
+};
+
+#define DBUS_FIXED_HEADER_TYPE ((const GVariantType *) "(yyyyut)")
+#define DBUS_EXTENDED_HEADER_TYPE ((const GVariantType *) "a{tv}")
+#define DBUS_MESSAGE_TYPE ((const GVariantType *) "((yyyyut)a{tv}v)")
+
+#define KDBUS_MSG_MAX_SIZE 8192
+
+static gboolean
+g_kdbus_msg_append_item (struct kdbus_msg *msg,
+ gsize type,
+ gconstpointer data,
+ gsize size)
+{
+ struct kdbus_item *item;
+ gsize item_size;
+
+ item_size = size + sizeof (struct kdbus_item);
+
+ if (msg->size + item_size > KDBUS_MSG_MAX_SIZE)
+ return FALSE;
+
+ item = (struct kdbus_item *) ((guchar *) msg) + msg->size;
+ item->type = type;
+ item->size = item_size;
+ memcpy (item->data, data, size);
+
+ msg->size += (item_size + 7) & ~7ull;
+
+ return TRUE;
+}
+
+static gboolean
+g_kdbus_msg_append_payload_vec (struct kdbus_msg *msg,
+ gconstpointer data,
+ gsize size)
+{
+ struct kdbus_vec vec = {
+ .size = size,
+ .address = (gsize) data
+ };
+
+ return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_VEC, &vec, sizeof vec);
+}
+
+static gboolean
+g_kdbus_msg_append_payload_memfd (struct kdbus_msg *msg,
+ gint fd,
+ gsize offset,
+ gsize size)
+{
+ struct kdbus_memfd mfd = {
+ .start = offset,
+ .size = size,
+ .fd = fd,
+ };
+
+ return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_MEMFD, &mfd, sizeof mfd);
+}
+
/**
* _g_kdbus_send:
* Returns: size of data sent or -1 when error
*/
gboolean
-_g_kdbus_send (GDBusWorker *worker,
- GKdbus *kdbus,
- GDBusMessage *dbus_msg,
- GUnixFDList *fd_list,
+_g_kdbus_send (GKdbus *kdbus,
+ GDBusMessage *message,
GCancellable *cancellable,
GError **error)
{
+ struct kdbus_msg *msg = alloca (KDBUS_MSG_MAX_SIZE);
GVariantVectors body_vectors;
- GVariant *body;
- struct kdbus_msg* kmsg;
- struct kdbus_item *item;
- guint64 kmsg_size = 0;
- const gchar *name;
- guint64 dst_id = KDBUS_DST_ID_BROADCAST;
- guint i;
g_return_val_if_fail (G_IS_KDBUS (kdbus), -1);
if (g_cancellable_set_error_if_cancelled (cancellable, error))
return FALSE;
- body = g_dbus_message_get_body (dbus_msg);
- if (body == NULL)
- {
- g_warning ("no body!");
- body = g_variant_new ("()");
- g_variant_ref_sink (body);
- }
- else
- g_variant_ref (body);
- GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
+ /* fill in as we go... */
+ memset (msg, 0, sizeof (struct kdbus_msg));
+ msg->size = sizeof (struct kdbus_msg);
+ msg->payload_type = KDBUS_PAYLOAD_DBUS;
+ msg->src_id = kdbus->priv->unique_id;
+ msg->cookie = g_dbus_message_get_serial(message);
- /*
- * check destination
- */
- if ((name = g_dbus_message_get_destination(dbus_msg)))
- {
- dst_id = KDBUS_DST_ID_NAME;
- if ((name[0] == ':') && (name[1] == '1') && (name[2] == '.'))
- {
- dst_id = strtoull(&name[3], NULL, 10);
- name=NULL;
- }
- }
+ /* Message destination */
+ {
+ const gchar *dst_name;
- /*
- * check and set message size
- */
- kmsg_size = sizeof(struct kdbus_msg);
+ dst_name = g_dbus_message_get_destination (message);
- { G_STATIC_ASSERT (sizeof (struct kdbus_vec) == sizeof (struct kdbus_memfd)); }
- kmsg_size += KDBUS_ITEM_SIZE(sizeof (struct kdbus_vec)) * body_vectors.vectors->len;
+ 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;
+ }
- if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
- kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list));
+ /* 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;
+ }
- if (name)
- kmsg_size += KDBUS_ITEM_SIZE(strlen(name) + 1);
- else if (dst_id == KDBUS_DST_ID_BROADCAST)
- kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, bloom_filter) +
- G_STRUCT_OFFSET(struct kdbus_bloom_filter, data) +
- kdbus->priv->bloom_size);
+ /* File descriptors */
+ {
+ GUnixFDList *fd_list;
- kmsg = malloc(kmsg_size);
- if (!kmsg)
- g_error ("[KDBUS] kmsg malloc error");
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list != NULL)
+ {
+ const gint *fds;
+ gint n_fds;
- /*
- * set message header
- */
- memset(kmsg, 0, kmsg_size);
- kmsg->size = kmsg_size;
- kmsg->payload_type = KDBUS_PAYLOAD_DBUS;
- kmsg->dst_id = name ? 0 : dst_id;
- kmsg->src_id = kdbus->priv->unique_id;
- kmsg->cookie = g_dbus_message_get_serial(dbus_msg);
- kmsg->priority = 0;
+ fds = g_unix_fd_list_peek_fds (fd_list, &n_fds);
+ if (n_fds)
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_FDS, fds, sizeof (gint) * n_fds);
+ }
+ }
+
+ /* Message body */
+ {
+ struct dbus_fixed_header fh;
+ GHashTableIter header_iter;
+ GVariantBuilder builder;
+ gpointer key, value;
+ GVariant *parts[3];
+ GVariant *body;
+
+ fh.endian = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 'l': 'B';
+ fh.type = g_dbus_message_get_message_type (message);
+ fh.flags = g_dbus_message_get_flags (message);
+ fh.version = 2;
+ fh.reserved = 0;
+ fh.serial = g_dbus_message_get_serial (message);
+ parts[0] = g_variant_new_from_data (DBUS_FIXED_HEADER_TYPE, &fh, sizeof fh, TRUE, NULL, NULL);
+
+ g_dbus_message_init_header_iter (message, &header_iter);
+ g_variant_builder_init (&builder, DBUS_EXTENDED_HEADER_TYPE);
+ while (g_hash_table_iter_next (&header_iter, &key, &value))
+ {
+ guint64 key_int = (gsize) key;
- /*
- * set message flags
- */
- kmsg->flags = ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
- ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+ /* We don't send these in GVariant format */
+ if (key_int == G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE ||
+ key_int == G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS)
+ continue;
- if ((kmsg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY)
- kmsg->timeout_ns = 2000000000;
- else
- kmsg->cookie_reply = g_dbus_message_get_reply_serial(dbus_msg);
+ g_variant_builder_add (&builder, "{tv}", key_int, value);
+ }
+ 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);
- /*
- * append payload
- */
- item = kmsg->items;
- for (i = 0; i < body_vectors.vectors->len; i++)
- {
- GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
+ body = g_variant_ref_sink (g_variant_new_tuple (parts, G_N_ELEMENTS (parts)));
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, &body_vectors);
+ g_variant_unref (body);
+ }
- if (vector.gbytes)
- {
- gint fd;
+ {
+ guint i;
- fd = g_bytes_get_zero_copy_fd (vector.gbytes);
+ for (i = 0; i < body_vectors.vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
- if (fd >= 0)
- {
- gconstpointer bytes_data;
- gsize bytes_size;
+ if (vector.gbytes)
+ {
+ gint fd;
- bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
+ fd = g_bytes_get_zero_copy_fd (vector.gbytes);
- if (bytes_data == vector.data.pointer && bytes_size == vector.size)
- g_kdbus_append_payload_memfd (&item, fd, vector.size);
- else
- g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size);
- }
- else
- g_kdbus_append_payload_vec (&item, vector.data.pointer, vector.size);
- }
- else
- g_kdbus_append_payload_vec (&item, body_vectors.extra_bytes->data + vector.data.offset, vector.size);
- }
+ 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;
+ }
+ }
- /* if we don't use memfd, send whole message as a PAYLOAD_VEC item */
+ /*
+ * set message flags
+ */
+ msg->flags = ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
+ ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
+
+ if ((msg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY)
+ msg->timeout_ns = 2000000000;
+ else
+ msg->cookie_reply = g_dbus_message_get_reply_serial(message);
/*
- * append destination or bloom filters
- */
- if (name)
- g_kdbus_append_destination (&item, name, strlen(name));
- else if (dst_id == KDBUS_DST_ID_BROADCAST)
+ if (dst_id == KDBUS_DST_ID_BROADCAST)
{
struct kdbus_bloom_filter *bloom_filter;
bloom_filter = g_kdbus_append_bloom (&item, kdbus->priv->bloom_size);
- g_kdbus_setup_bloom (kdbus, dbus_msg, bloom_filter);
+ g_kdbus_setup_bloom (kdbus, message, bloom_filter);
}
-
- /*
- * append fds if any
- */
- if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0)
- g_kdbus_append_fds (&item, fd_list);
-
+ */
/*
* send message
*/
//again:
- if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg))
+ if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, msg))
{
/*
GString *error_name;
return FALSE;
}
- free(kmsg);
-
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 ();
}