#include "glibintl.h"
#include "gunixfdmessage.h"
-#define KDBUS_MSG_MAX_SIZE 8192
+#define KDBUS_MSG_MAX_SIZE 8192
#define KDBUS_INFINITE_TIMEOUT_NS 0x3fffffffffffffffLLU
#define RECEIVE_POOL_SIZE_DEFAULT_SIZE (16 * 1024LU * 1024LU)
item_size = size + G_STRUCT_OFFSET(struct kdbus_item, data);
- if (msg->size + item_size > KDBUS_MSG_MAX_SIZE)
- return FALSE;
-
msg->size += (-msg->size) & 7;
item = (struct kdbus_item *) ((guchar *) msg + msg->size);
item->type = type;
bloom_item_size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
size;
- if (msg->size + bloom_item_size > KDBUS_MSG_MAX_SIZE)
- return NULL;
msg->size += (-msg->size) & 7;
bloom_item = (struct kdbus_item *) ((guchar *) msg + msg->size);
return &bloom_item->bloom_filter;
}
-
/*
- * _g_kdbus_send
+ * Returns header size.
*/
-static gboolean
-_g_kdbus_send (GKDBusWorker *worker,
- GDBusMessage *message,
- GDBusMessage **out_reply,
- gint timeout_msec,
- GCancellable *cancellable,
- GError **error)
+static gsize
+prepare_body_vectors (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GVariantVectors *body_vectors,
+ gboolean *lg_h_field_exist)
{
- struct kdbus_msg *msg;
- GVariantVectors body_vectors;
- struct kdbus_cmd_send *send;
- gsize send_size;
- const gchar *dst_name;
- gboolean result;
- gboolean lg_h_field_exist = FALSE;
+ struct dbus_fixed_header fh;
+ GHashTableIter header_iter;
+ GVariantBuilder builder;
+ gpointer key, value;
+ GVariant *parts[3];
+ GVariant *body;
+ gsize header_size;
- gint memfd_fd;
- gint cancel_fd;
+ *lg_h_field_exist = FALSE;
- gsize header_size;
+ 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_assert_nonnull (parts[0]);
- g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+ g_dbus_message_init_header_iter (message, &header_iter);
+ g_variant_builder_init (&builder, DBUS_EXTENDED_HEADER_TYPE);
- send = NULL;
- send_size = sizeof(*send);
+ /* 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, worker->unique_id));
- msg = alloca (KDBUS_MSG_MAX_SIZE);
- result = TRUE;
+ while (g_hash_table_iter_next (&header_iter, &key, &value))
+ {
+ guint64 key_int = (gsize) key;
- memfd_fd = -1;
- cancel_fd = -1;
+ switch (key_int)
+ {
+ /* These are the normal header fields that get passed
+ * straight through.
+ */
+ case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
+ g_variant_builder_add (&builder, "{tv}", key_int, g_variant_new_uint64 (g_dbus_message_get_reply_serial(message)));
+ continue;
- /* 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->cookie = g_dbus_message_get_serial(message);
- /* Message destination */
+ 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_DESTINATION:
+ case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
+ 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.
+ *
+ * Anyway, kdbus does not check it, and libraries handle it...
+ */
+
+ if (g_variant_get_size (value) >= 128)
+ *lg_h_field_exist = TRUE;
+
+ 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:
+ continue;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ parts[1] = g_variant_builder_end (&builder);
+ g_assert_nonnull (parts[1]);
+
+ body = g_dbus_message_get_body (message);
+ if (!body)
+ body = g_variant_new ("()");
+ parts[2] = g_variant_new_variant (body);
+ g_assert_nonnull (parts[2]);
+
+ header_size = g_variant_get_size (parts[0]) + g_variant_get_size (parts[1]);
+
+ 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; this
+ * condition must be assured later, during composing kdbus vectors.
+ */
+ g_assert_cmpint (body_vectors->vectors->len, >, 0);
+
+ g_variant_unref (body);
+
+ return header_size;
+}
+
+static void
+make_single_header_vector (GVariantVectors *body_vectors,
+ gsize header_size,
+ gboolean lg_h_field_exist)
+{
+ guint i = 0;
+ gsize added_vectors_size = 0;
+ GVariantVector *first_vector;
+
+ /* Merge all header vectors into single vector */
+ first_vector = &g_array_index (body_vectors->vectors, GVariantVector, 0);
+ if (first_vector->size < header_size)
+ {
+ /* There are multiple header vectors, we have to join them together into a single one */
+ GByteArray *header = g_byte_array_sized_new (header_size);
+ gsize dummy_size;
+
+ g_assert_nonnull (header);
+ g_assert_true (lg_h_field_exist);
+
+ while (added_vectors_size < header_size && i < body_vectors->vectors->len)
+ {
+ GVariantVector *vector = &g_array_index (body_vectors->vectors, GVariantVector, i);
+
+ if (vector->gbytes)
+ {
+ g_byte_array_append (header, vector->data.pointer, vector->size);
+ g_bytes_unref (vector->gbytes);
+ }
+ else
+ {
+ g_byte_array_append (header, body_vectors->extra_bytes->data + vector->data.offset, vector->size);
+ }
+
+ added_vectors_size += vector->size;
+ i++;
+ }
+
+ /* Sanity check if the first vector contains at least the complete header */
+ g_assert_cmpint (added_vectors_size, >=, header_size);
+
+ first_vector->gbytes = g_byte_array_free_to_bytes (header);
+ first_vector->data.pointer = g_bytes_get_data (first_vector->gbytes, &dummy_size);
+ first_vector->size = added_vectors_size;
+
+ g_array_remove_range (body_vectors->vectors, 1, i-1);
+ }
+ /* else: If there is only a single header vector, then just go */
+}
+
+static gboolean
+add_message_destination_item (struct kdbus_msg *msg,
+ GDBusMessage *message,
+ GError **error)
+{
+ const gchar *dst_name;
+
dst_name = g_dbus_message_get_destination (message);
if (dst_name != NULL)
{
else
msg->dst_id = KDBUS_DST_ID_BROADCAST;
- /* File descriptors */
- {
- GUnixFDList *fd_list;
+ return TRUE;
+}
- fd_list = g_dbus_message_get_unix_fd_list (message);
+static void
+add_file_descriptors_item (struct kdbus_msg *msg,
+ GDBusMessage *message)
+{
+ GUnixFDList *fd_list;
- if (fd_list != NULL)
- {
- const gint *fds;
- gint n_fds;
+ 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);
+ 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, worker->unique_id));
-
- while (g_hash_table_iter_next (&header_iter, &key, &value))
- {
- guint64 key_int = (gsize) key;
+ if (n_fds)
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_FDS, fds, sizeof (gint) * n_fds);
+ }
+}
- switch (key_int)
- {
- /* These are the normal header fields that get passed
- * straight through.
- */
- case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
- g_variant_builder_add (&builder, "{tv}", key_int, g_variant_new_uint64 (g_dbus_message_get_reply_serial(message)));
- continue;
+static gboolean
+add_body_vectors (struct kdbus_msg *msg,
+ GVariantVectors *body_vectors,
+ gint *memfd_fd)
+{
+ guint i = 0;
+ /* Add all the vectors to the kdbus message */
+ for (; i < body_vectors->vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors->vectors, GVariantVector, i);
- 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_DESTINATION:
- case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
- 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.
- *
- * Anyway, kdbus does not check it, and libraries handle it...
- */
-
- if (g_variant_get_size (value) >= 128)
- lg_h_field_exist = TRUE;
+ if (vector.gbytes)
+ {
+ const guchar *bytes_data;
+ gboolean use_memfd;
+ gsize bytes_size;
- continue;
+ use_memfd = FALSE;
+ bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
- /* We send this one unconditionally, but set it ourselves */
- case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
- continue;
+ /* check whether we can and should use memfd */
+ if ((msg->dst_id != KDBUS_DST_ID_BROADCAST) && (bytes_size > KDBUS_MEMFD_THRESHOLD))
+ use_memfd = TRUE;
+
+ if (use_memfd)
+ {
+ const guchar *bytes_data_wr;
+ gint64 wr;
+
+ /* create memfd object */
+ *memfd_fd = glib_linux_memfd_create ("glib-kdbus-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (*memfd_fd == -1)
+ {
+ g_warning ("kdbus: missing kernel memfd support");
+ use_memfd = FALSE; /* send as PAYLOAD_VEC item */
+ }
+ else
+ {
+ /* write data to memfd */
+ bytes_data_wr = bytes_data;
+ while (bytes_size)
+ {
+ wr = write (*memfd_fd, bytes_data_wr, bytes_size);
+ if (wr < 0)
+ g_warning ("kdbus: writing to memfd failed: (%d) %m", errno);
+
+ bytes_size -= wr;
+ bytes_data_wr += wr;
+ }
+
+ /* seal memfd */
+ if (!g_unix_fd_ensure_zero_copy_safe (*memfd_fd))
+ {
+ g_warning ("kdbus: memfd sealing failed");
+ use_memfd = FALSE; /* send as PAYLOAD_VEC item */
+ }
+ else
+ {
+ /* attach memfd item */
+ if (!g_kdbus_msg_append_payload_memfd (msg, *memfd_fd, vector.data.pointer - bytes_data, vector.size))
+ return FALSE;
+ }
+ } /* *memfd_fd == -1 */
+ } /* use_memfd */
+
+ if (!use_memfd)
+ if (!g_kdbus_msg_append_payload_vec (msg, vector.data.pointer, vector.size))
+ return FALSE;
+ }
+ else
+ if (!g_kdbus_msg_append_payload_vec (msg, body_vectors->extra_bytes->data + vector.data.offset, vector.size))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+add_bloom_item (struct kdbus_msg *msg,
+ GDBusMessage *message,
+ GKDBusWorker *worker)
+{
+ struct kdbus_bloom_filter *bloom_filter;
+
+ if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ msg->flags |= KDBUS_MSG_SIGNAL;
+ bloom_filter = g_kdbus_msg_append_bloom (msg, worker->bloom_size);
+ if (bloom_filter == NULL)
+ return FALSE;
+ g_kdbus_setup_bloom (worker, message, bloom_filter);
+ }
+ return TRUE;
+}
+
+static gsize
+compute_msg_size (GDBusMessage *message,
+ GKDBusWorker *worker,
+ GVariantVectors *body_vectors)
+{
+ gsize items_size = 0;
+ GUnixFDList *fd_list;
+ const gchar *dst_name;
+ guint i;
+ GDBusMessageType msg_type = g_dbus_message_get_message_type (message);
+
+ /* payload - check which vectors will become memfds */
+ for (i = 0; i < body_vectors->vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors->vectors, GVariantVector, i);
+ gsize payload_size;
+ gsize kdbus_num_vectors;
- /* We don't send these at all in GVariant format */
- case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
+ if (vector.gbytes)
+ {
+ payload_size = g_bytes_get_size (vector.gbytes);
+ if (msg_type != G_DBUS_MESSAGE_TYPE_SIGNAL && payload_size > KDBUS_MEMFD_THRESHOLD)
+ {
+ /* We can do this because we know that struct kdbus_memfd is larger or equal than
+ struct kdbus_vec. struct kdbus_vec is fallback option if memfd does not work */
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_memfd));
continue;
+ }
+ }
+ else
+ {
+ payload_size = vector.size;
+ }
- default:
- g_assert_not_reached ();
- }
- }
- parts[1] = g_variant_builder_end (&builder);
- if (parts[1] == NULL)
- g_warning ("failed to make builder");
-
- body = g_dbus_message_get_body (message);
- if (!body)
- body = g_variant_new ("()");
- parts[2] = g_variant_new_variant (body);
-
- header_size = g_variant_get_size (parts[0]) + g_variant_get_size (parts[1]);
-
- 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; this
- * condition is assured below.
- */
- g_assert_cmpint (body_vectors.vectors->len, >, 0);
-
- g_variant_unref (body);
- }
-
- {
- guint i = 0;
- gsize added_vectors_size = 0;
- GVariantVector *first_vector;
-
- /* First: add all header vectors to single kdbus vector item */
- first_vector = &g_array_index (body_vectors.vectors, GVariantVector, 0);
- if (first_vector->size < header_size)
- {
- /* There are multiple header vectors, we have to join them together into a single one */
- GByteArray *header = g_byte_array_sized_new (header_size);
- gsize dummy_size;
+ kdbus_num_vectors = (payload_size + KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE - 1) / KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_vec)) * kdbus_num_vectors;
+ }
- g_assert_nonnull (header);
- g_assert_true (lg_h_field_exist);
+ /* file descriptors */
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list != NULL)
+ items_size += KDBUS_ITEM_SIZE (g_unix_fd_list_get_length (fd_list) * sizeof(gint));
- while (added_vectors_size < header_size && i < body_vectors.vectors->len)
- {
- GVariantVector *vector = &g_array_index (body_vectors.vectors, GVariantVector, i);
+ /* destination */
+ dst_name = g_dbus_message_get_destination (message);
+ if (dst_name != NULL)
+ items_size += KDBUS_ITEM_SIZE (strlen (dst_name) + 1);
- if (vector->gbytes)
- {
- g_byte_array_append (header, vector->data.pointer, vector->size);
- g_bytes_unref (vector->gbytes);
- }
- else
- {
- g_byte_array_append (header, body_vectors.extra_bytes->data + vector->data.offset, vector->size);
- }
+ /* bloom filters */
+ if (msg_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_bloom_filter) + worker->bloom_size);
- added_vectors_size += vector->size;
- i++;
- }
+ return sizeof (struct kdbus_msg) + items_size;
+}
- /* Sanity check if the first vector contains at least the complete header */
- g_assert_cmpint (added_vectors_size, >=, header_size);
+/*
+ * _g_kdbus_send
+ */
+static gboolean
+_g_kdbus_send (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GDBusMessage **out_reply,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct kdbus_msg *msg;
+ GVariantVectors body_vectors;
+ struct kdbus_cmd_send *send;
+ gsize send_size;
+ gboolean result = FALSE;
+ gboolean lg_h_field_exist = FALSE;
- first_vector->gbytes = g_byte_array_free_to_bytes (header);
- first_vector->data.pointer = g_bytes_get_data (first_vector->gbytes, &dummy_size);
- first_vector->size = added_vectors_size;
+ gint memfd_fd;
+ gint cancel_fd;
- g_array_remove_range (body_vectors.vectors, 1, i-1);
+ gsize header_size;
+ gsize msg_size;
- /* Now, the vectors are prepared correctly, add them to the message */
- i = 0;
- }
- /* else: If there is only a single header vector, then just go */
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
- /* Now, add all the remaining body vectors */
- for (; i < body_vectors.vectors->len; i++)
- {
- GVariantVector vector = g_array_index (body_vectors.vectors, GVariantVector, i);
+ send = NULL;
+ send_size = sizeof(*send);
- if (vector.gbytes)
- {
- const guchar *bytes_data;
- gboolean use_memfd;
- gsize bytes_size;
+ /* Prepare message body - it is needed for kdbus msg size computation */
+ header_size = prepare_body_vectors (worker, message, &body_vectors, &lg_h_field_exist);
+ make_single_header_vector (&body_vectors, header_size, lg_h_field_exist);
- use_memfd = FALSE;
- bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
+ /* We precompute needed size for the message to allocate exact space instead
+ of some arbitrary amount */
+ msg_size = compute_msg_size (message, worker, &body_vectors);
+ if (msg_size <= KDBUS_MSG_MAX_SIZE)
+ {
+ msg = g_alloca (msg_size);
+ memset (msg, 0, msg_size);
+ }
+ else
+ {
+ msg = g_malloc0 (msg_size);
+ }
+ g_assert_nonnull (msg);
- /* check whether we can and should use memfd */
- if ((msg->dst_id != KDBUS_DST_ID_BROADCAST) && (bytes_size > KDBUS_MEMFD_THRESHOLD))
- use_memfd = TRUE;
+ memfd_fd = -1;
+ cancel_fd = -1;
- if (use_memfd)
- {
- const guchar *bytes_data_wr;
- gint64 wr;
+ /* fill in as we go... */
+ msg->size = sizeof (struct kdbus_msg);
+ msg->payload_type = KDBUS_PAYLOAD_DBUS;
+ msg->cookie = g_dbus_message_get_serial(message);
- /* create memfd object */
- memfd_fd = glib_linux_memfd_create ("glib-kdbus-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
- if (memfd_fd == -1)
- {
- g_warning ("kdbus: missing kernel memfd support");
- use_memfd = FALSE; /* send as PAYLOAD_VEC item */
- }
- else
- {
- /* write data to memfd */
- bytes_data_wr = bytes_data;
- while (bytes_size)
- {
- wr = write (memfd_fd, bytes_data_wr, bytes_size);
- if (wr < 0)
- g_warning ("kdbus: writing to memfd failed: (%d) %m", errno);
-
- bytes_size -= wr;
- bytes_data_wr += wr;
- }
-
- /* seal memfd */
- if (!g_unix_fd_ensure_zero_copy_safe (memfd_fd))
- {
- g_warning ("kdbus: memfd sealing failed");
- use_memfd = FALSE; /* send as PAYLOAD_VEC item */
- }
- else
- {
- /* attach memfd item */
- if (!g_kdbus_msg_append_payload_memfd (msg, memfd_fd, vector.data.pointer - bytes_data, vector.size))
- goto need_compact;
- }
- } /* memfd_fd == -1 */
- } /* use_memfd */
-
- if (!use_memfd)
- 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;
- }
- }
+ /* Message destination */
+ if (!add_message_destination_item (msg, message, error))
+ goto out;
+
+ /* File descriptors */
+ add_file_descriptors_item (msg, message);
+
+ if (!add_body_vectors (msg, &body_vectors, &memfd_fd))
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "message serialisation error: body vectors");
+ g_warning ("kdbus: message serialisation error: body vectors");
+ goto out;
+ }
/*
* set message flags
/*
* append bloom filter item for broadcast signals
*/
- if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ if (!add_bloom_item (msg, message, worker))
{
- struct kdbus_bloom_filter *bloom_filter;
-
- msg->flags |= KDBUS_MSG_SIGNAL;
- bloom_filter = g_kdbus_msg_append_bloom (msg, worker->bloom_size);
- if (bloom_filter == NULL)
- goto need_compact;
- g_kdbus_setup_bloom (worker, message, bloom_filter);
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "message serialisation error: bloom filters");
+ g_warning ("kdbus: message serialisation error: bloom filters");
+ goto out;
}
if (out_reply != NULL && cancellable)
send_size += KDBUS_ITEM_SIZE (sizeof(cancel_fd));
}
+ g_assert_cmpuint (msg->size, <=, msg_size);
+
send = g_alloca0 (send_size);
send->size = send_size;
send->msg_address = (gsize) msg;
case DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE:
if (g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START)
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
- "Name \"%s\" does not exist", dst_name);
+ "Name \"%s\" does not exist", g_dbus_message_get_destination (message));
else
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
- "Cannot send message - destination '%s' not known", dst_name);
+ "Cannot send message - destination '%s' not known", g_dbus_message_get_destination (message));
break;
case DBUSPOLICY_RESULT_KDBUS_ERROR:
break;
}
- result = FALSE;
goto out;
}
}
{
if (g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START)
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
- "Name \"%s\" does not exist, %s", dst_name, info);
+ "Name \"%s\" does not exist, %s", g_dbus_message_get_destination (message), info);
else
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
- "Destination '%s' not known, %s", dst_name, info);
+ "Destination '%s' not known, %s", g_dbus_message_get_destination (message), info);
}
else if (errno == EADDRNOTAVAIL)
{
g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
- "No support for activation for name: %s, %s", dst_name, info);
+ "No support for activation for name: %s, %s", g_dbus_message_get_destination (message), info);
}
else if (errno == EXFULL)
{
}
free(info);
}
- result = FALSE;
}
- else if (out_reply != NULL)
+ else
{
- GKDBusMessage *kmsg;
- struct kdbus_msg *kdbus_msg;
+ result = TRUE;
+ if (out_reply != NULL)
+ {
+ GKDBusMessage *kmsg;
+ struct kdbus_msg *kdbus_msg;
- kdbus_msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
+ kdbus_msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
- kmsg = g_kdbus_decode_dbus_msg (worker, kdbus_msg);
- g_kdbus_close_msg (worker, kdbus_msg);
+ kmsg = g_kdbus_decode_dbus_msg (worker, kdbus_msg);
+ g_kdbus_close_msg (worker, kdbus_msg);
- *out_reply = kmsg->message;
+ *out_reply = kmsg->message;
- if (kmsg->sender_seclabel != NULL)
- g_free (kmsg->sender_seclabel);
+ if (kmsg->sender_seclabel != NULL)
+ g_free (kmsg->sender_seclabel);
- if (kmsg->sender_names != NULL)
- g_free (kmsg->sender_names);
+ if (kmsg->sender_names != NULL)
+ g_free (kmsg->sender_names);
- g_free (kmsg);
+ g_free (kmsg);
- if (G_UNLIKELY (_g_dbus_debug_message ()))
- {
- gchar *s;
- _g_dbus_debug_print_lock ();
- g_print ("========================================================================\n"
- "GDBus-debug:Message:\n"
- " <<<< RECEIVED D-Bus message\n");
- s = g_dbus_message_print (*out_reply, 2);
- g_print ("%s", s);
- g_free (s);
- _g_dbus_debug_print_unlock ();
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " <<<< RECEIVED D-Bus message\n");
+ s = g_dbus_message_print (*out_reply, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
}
}
-#ifdef LIBDBUSPOLICY
out:
-#endif
+ if (msg_size > KDBUS_MSG_MAX_SIZE)
+ g_free (msg);
+
if (cancel_fd != -1)
g_cancellable_release_fd (cancellable);
GLIB_PRIVATE_CALL(g_variant_vectors_deinit) (&body_vectors);
return result;
-
-need_compact:
- /* We end up here if:
- * - too many kdbus_items
- * - too large kdbus_msg size
- * - too much vector data
- */
- g_warning ("kdbus: message serialisation error");
- g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
- "message serialisation error");
-
- if (memfd_fd != -1)
- close (memfd_fd);
-
- GLIB_PRIVATE_CALL(g_variant_vectors_deinit) (&body_vectors);
- return FALSE;
}
/* ---------------------------------------------------------------------------------------------------- */