X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgdbusmessage.c;h=4d4cb6963ce6d4505ac53346d6200e3409f3ea1f;hb=d4c39ffb96567b7182e8f4df1aea35320285bc72;hp=ade5e7be70b1621af3bbd27a2971a8ccd9a64302;hpb=30132c44c18d9a08e4c6a9b4834366bd8628ecfa;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index ade5e7b..4d4cb69 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -13,9 +13,7 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General - * Public License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Author: David Zeuthen */ @@ -29,8 +27,11 @@ #include #include #include -#ifdef HAVE_UNISTD_H -#include + +#if MAJOR_IN_MKDEV +#include +#elif MAJOR_IN_SYSMACROS +#include #endif #include "gdbusutils.h" @@ -48,11 +49,376 @@ #include "gdbusprivate.h" #ifdef G_OS_UNIX +#include "gkdbus.h" #include "gunixfdlist.h" #endif #include "glibintl.h" +typedef struct _GMemoryBuffer GMemoryBuffer; +struct _GMemoryBuffer +{ + gsize len; + gsize valid_len; + gsize pos; + gchar *data; + GDataStreamByteOrder byte_order; +}; + +static gboolean +g_memory_buffer_is_byteswapped (GMemoryBuffer *mbuf) +{ +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; +#else + return mbuf->byte_order == G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; +#endif +} + +static guchar +g_memory_buffer_read_byte (GMemoryBuffer *mbuf) +{ + if (mbuf->pos >= mbuf->valid_len) + return 0; + return mbuf->data [mbuf->pos++]; +} + +static gint16 +g_memory_buffer_read_int16 (GMemoryBuffer *mbuf) +{ + gint16 v; + + if (mbuf->pos > mbuf->valid_len - 2) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 2); + mbuf->pos += 2; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT16_SWAP_LE_BE (v); + + return v; +} + +static guint16 +g_memory_buffer_read_uint16 (GMemoryBuffer *mbuf) +{ + guint16 v; + + if (mbuf->pos > mbuf->valid_len - 2) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 2); + mbuf->pos += 2; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT16_SWAP_LE_BE (v); + + return v; +} + +static gint32 +g_memory_buffer_read_int32 (GMemoryBuffer *mbuf) +{ + gint32 v; + + if (mbuf->pos > mbuf->valid_len - 4) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 4); + mbuf->pos += 4; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT32_SWAP_LE_BE (v); + + return v; +} + +static guint32 +g_memory_buffer_read_uint32 (GMemoryBuffer *mbuf) +{ + guint32 v; + + if (mbuf->pos > mbuf->valid_len - 4) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 4); + mbuf->pos += 4; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT32_SWAP_LE_BE (v); + + return v; +} + +static gint64 +g_memory_buffer_read_int64 (GMemoryBuffer *mbuf) +{ + gint64 v; + + if (mbuf->pos > mbuf->valid_len - 8) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 8); + mbuf->pos += 8; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT64_SWAP_LE_BE (v); + + return v; +} + +static guint64 +g_memory_buffer_read_uint64 (GMemoryBuffer *mbuf) +{ + guint64 v; + + if (mbuf->pos > mbuf->valid_len - 8) + { + mbuf->pos = mbuf->valid_len; + return 0; + } + + memcpy (&v, mbuf->data + mbuf->pos, 8); + mbuf->pos += 8; + + if (g_memory_buffer_is_byteswapped (mbuf)) + v = GUINT64_SWAP_LE_BE (v); + + return v; +} + +#define MIN_ARRAY_SIZE 128 + +static gsize +g_nearest_pow (gsize num) +{ + gsize n = 1; + + while (n < num && n > 0) + n <<= 1; + + return n; +} + +static void +array_resize (GMemoryBuffer *mbuf, + gsize size) +{ + gpointer data; + gsize len; + + if (mbuf->len == size) + return; + + len = mbuf->len; + data = g_realloc (mbuf->data, size); + + if (size > len) + memset ((guint8 *)data + len, 0, size - len); + + mbuf->data = data; + mbuf->len = size; + + if (mbuf->len < mbuf->valid_len) + mbuf->valid_len = mbuf->len; +} + +static gboolean +g_memory_buffer_write (GMemoryBuffer *mbuf, + const void *buffer, + gsize count) +{ + guint8 *dest; + gsize new_size; + + if (count == 0) + return TRUE; + + /* Check for address space overflow, but only if the buffer is resizable. + Otherwise we just do a short write and don't worry. */ + if (mbuf->pos + count < mbuf->pos) + return FALSE; + + if (mbuf->pos + count > mbuf->len) + { + /* At least enought to fit the write, rounded up + for greater than linear growth. + TODO: This wastes a lot of memory at large buffer sizes. + Figure out a more rational allocation strategy. */ + new_size = g_nearest_pow (mbuf->pos + count); + /* Check for overflow again. We have checked if + pos + count > G_MAXSIZE, but now check if g_nearest_pow () has + overflowed */ + if (new_size == 0) + return FALSE; + + new_size = MAX (new_size, MIN_ARRAY_SIZE); + array_resize (mbuf, new_size); + } + + dest = (guint8 *)mbuf->data + mbuf->pos; + memcpy (dest, buffer, count); + mbuf->pos += count; + + if (mbuf->pos > mbuf->valid_len) + mbuf->valid_len = mbuf->pos; + + return TRUE; +} + +static gboolean +g_memory_buffer_put_byte (GMemoryBuffer *mbuf, + guchar data) +{ + return g_memory_buffer_write (mbuf, &data, 1); +} + +static gboolean +g_memory_buffer_put_int16 (GMemoryBuffer *mbuf, + gint16 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GINT16_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GINT16_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 2); +} + +static gboolean +g_memory_buffer_put_uint16 (GMemoryBuffer *mbuf, + guint16 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GUINT16_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GUINT16_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 2); +} + +static gboolean +g_memory_buffer_put_int32 (GMemoryBuffer *mbuf, + gint32 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GINT32_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GINT32_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 4); +} + +static gboolean +g_memory_buffer_put_uint32 (GMemoryBuffer *mbuf, + guint32 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GUINT32_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GUINT32_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 4); +} + +static gboolean +g_memory_buffer_put_int64 (GMemoryBuffer *mbuf, + gint64 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GINT64_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GINT64_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 8); +} + +static gboolean +g_memory_buffer_put_uint64 (GMemoryBuffer *mbuf, + guint64 data) +{ + switch (mbuf->byte_order) + { + case G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN: + data = GUINT64_TO_BE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN: + data = GUINT64_TO_LE (data); + break; + case G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN: + default: + break; + } + + return g_memory_buffer_write (mbuf, &data, 8); +} + +static gboolean +g_memory_buffer_put_string (GMemoryBuffer *mbuf, + const char *str) +{ + g_return_val_if_fail (str != NULL, FALSE); + + return g_memory_buffer_write (mbuf, str, strlen (str)); +} + + /** * SECTION:gdbusmessage * @short_description: D-Bus Message @@ -215,9 +581,9 @@ g_dbus_message_new (void) /** * g_dbus_message_new_method_call: - * @name: A valid D-Bus name or %NULL. + * @name: (allow-none): A valid D-Bus name or %NULL. * @path: A valid object path. - * @interface_: A valid D-Bus interface name or %NULL. + * @interface_: (allow-none): A valid D-Bus interface name or %NULL. * @method: A valid method name. * * Creates a new #GDBusMessage for a method call. @@ -413,6 +779,7 @@ g_dbus_message_new_method_error_literal (GDBusMessage *method_call_message, * * Since: 2.26 */ +G_GNUC_PRINTF(3, 0) GDBusMessage * g_dbus_message_new_method_error_valist (GDBusMessage *method_call_message, const gchar *error_name, @@ -606,6 +973,38 @@ g_dbus_message_set_serial (GDBusMessage *message, /* ---------------------------------------------------------------------------------------------------- */ +/** + * _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 */ /** @@ -633,7 +1032,7 @@ g_dbus_message_get_header (GDBusMessage *message, * g_dbus_message_set_header: * @message: A #GDBusMessage. * @header_field: A 8-bit unsigned integer (typically a value from the #GDBusMessageHeaderField enumeration) - * @value: A #GVariant to set the header field or %NULL to clear the header field. + * @value: (allow-none): A #GVariant to set the header field or %NULL to clear the header field. * * Sets a header field on @message. * @@ -671,9 +1070,9 @@ g_dbus_message_set_header (GDBusMessage *message, * * Gets an array of all header fields on @message that are set. * - * Returns: An array of header fields terminated by - * %G_DBUS_MESSAGE_HEADER_FIELD_INVALID. Each element is a - * #guchar. Free with g_free(). + * Returns: (array zero-terminated=1): An array of header fields + * terminated by %G_DBUS_MESSAGE_HEADER_FIELD_INVALID. Each element + * is a #guchar. Free with g_free(). * * Since: 2.26 */ @@ -708,7 +1107,8 @@ g_dbus_message_get_header_fields (GDBusMessage *message) * * Gets the body of a message. * - * Returns: A #GVariant or %NULL if the body is empty. Do not free, it is owned by @message. + * Returns: (transfer none): A #GVariant or %NULL if the body is + * empty. Do not free, it is owned by @message. * * Since: 2.26 */ @@ -836,6 +1236,27 @@ g_dbus_message_set_unix_fd_list (GDBusMessage *message, /* ---------------------------------------------------------------------------------------------------- */ +static guint +get_type_fixed_size (const GVariantType *type) +{ + /* NB: we do not treat 'b' as fixed-size here because GVariant and + * D-Bus disagree about the size. + */ + switch (*g_variant_type_peek_string (type)) + { + case 'y': + return 1; + case 'n': case 'q': + return 2; + case 'i': case 'u': case 'h': + return 4; + case 'x': case 't': case 'd': + return 8; + default: + return 0; + } +} + static gboolean validate_headers (GDBusMessage *message, GError **error) @@ -936,135 +1357,134 @@ validate_headers (GDBusMessage *message, /* ---------------------------------------------------------------------------------------------------- */ static gboolean -ensure_input_padding (GMemoryInputStream *mis, - gsize padding_size, - GError **error) +ensure_input_padding (GMemoryBuffer *buf, + gsize padding_size) { gsize offset; gsize wanted_offset; - offset = g_seekable_tell (G_SEEKABLE (mis)); + offset = buf->pos; wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size; - - if (offset != wanted_offset) - { - return g_seekable_seek (G_SEEKABLE (mis), wanted_offset, G_SEEK_SET, NULL, error); - } - else - { - return TRUE; - } + buf->pos = wanted_offset; + return TRUE; } -static gchar * -read_string (GMemoryInputStream *mis, - GDataInputStream *dis, - gsize len, - GError **error) +static const gchar * +read_string (GMemoryBuffer *mbuf, + gsize len, + GError **error) { - GString *s; - gchar buf[256]; - gsize remaining; - guchar nul; - GError *local_error; + gchar *str; const gchar *end_valid; - s = g_string_new (NULL); - - remaining = len; - while (remaining > 0) - { - gsize to_read; - gssize num_read; - - to_read = MIN (remaining, sizeof (buf)); - num_read = g_input_stream_read (G_INPUT_STREAM (mis), - buf, - to_read, - NULL, - error); - if (num_read < 0) - goto fail; - if (num_read == 0) - { - /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Wanted to read %lu bytes but got EOF"), - (gulong)to_read); - goto fail; - } - - remaining -= num_read; - g_string_append_len (s, buf, num_read); + if G_UNLIKELY (mbuf->pos + len >= mbuf->valid_len || mbuf->pos + len < mbuf->pos) + { + mbuf->pos = mbuf->valid_len; + /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + g_dngettext (GETTEXT_PACKAGE, + "Wanted to read %lu byte but only got %lu", + "Wanted to read %lu bytes but only got %lu", + (gulong)len), + (gulong)len, + (gulong)(mbuf->valid_len - mbuf->pos)); + return NULL; } - local_error = NULL; - nul = g_data_input_stream_read_byte (dis, NULL, &local_error); - if (local_error != NULL) + if G_UNLIKELY (mbuf->data[mbuf->pos + len] != '\0') { - g_propagate_error (error, local_error); - goto fail; + str = g_strndup (mbuf->data + mbuf->pos, len); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Expected NUL byte after the string '%s' but found byte %d"), + str, mbuf->data[mbuf->pos + len]); + g_free (str); + mbuf->pos += len + 1; + return NULL; } - if (!g_utf8_validate (s->str, -1, &end_valid)) + + str = mbuf->data + mbuf->pos; + mbuf->pos += len + 1; + + if G_UNLIKELY (!g_utf8_validate (str, -1, &end_valid)) { gint offset; gchar *valid_str; - offset = (gint) (end_valid - s->str); - valid_str = g_strndup (s->str, offset); + offset = (gint) (end_valid - str); + valid_str = g_strndup (str, offset); g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, _("Expected valid UTF-8 string but found invalid bytes at byte offset %d (length of string is %d). " - "The valid UTF-8 string up until that point was `%s'"), + "The valid UTF-8 string up until that point was '%s'"), offset, - (gint) s->len, + (gint) len, valid_str); g_free (valid_str); - goto fail; + return NULL; } - if (nul != '\0') + + return str; +} + +static gconstpointer +read_bytes (GMemoryBuffer *mbuf, + gsize len, + GError **error) +{ + gconstpointer result; + + if G_UNLIKELY (mbuf->pos + len > mbuf->valid_len || mbuf->pos + len < mbuf->pos) { + mbuf->pos = mbuf->valid_len; + /* G_GSIZE_FORMAT doesn't work with gettext, so we use %lu */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Expected NUL byte after the string `%s' but found byte %d"), - s->str, nul); - goto fail; + g_dngettext (GETTEXT_PACKAGE, + "Wanted to read %lu byte but only got %lu", + "Wanted to read %lu bytes but only got %lu", + (gulong)len), + (gulong)len, + (gulong)(mbuf->valid_len - mbuf->pos)); + return NULL; } - return g_string_free (s, FALSE); + result = mbuf->data + mbuf->pos; + mbuf->pos += len; - fail: - g_string_free (s, TRUE); - return NULL; + return result; } /* if just_align==TRUE, don't read a value, just align the input stream wrt padding */ /* returns a non-floating GVariant! */ static GVariant * -parse_value_from_blob (GMemoryInputStream *mis, - GDataInputStream *dis, - const GVariantType *type, - gboolean just_align, - guint indent, - GError **error) +parse_value_from_blob (GMemoryBuffer *buf, + const GVariantType *type, + gboolean just_align, + guint indent, + GError **error) { GVariant *ret; GError *local_error; gboolean is_leaf; + const gchar *type_string; + + type_string = g_variant_type_peek_string (type); #ifdef DEBUG_SERIALIZER - if (!just_align) { gchar *s; s = g_variant_type_dup_string (type); - g_print ("%*sReading type %s from offset 0x%04x", + g_print ("%*s%s type %s from offset 0x%04x", indent, "", + just_align ? "Aligning" : "Reading", s, - (gint) g_seekable_tell (G_SEEKABLE (mis))); + (gint) g_seekable_tell (G_SEEKABLE (buf))); g_free (s); } #endif /* DEBUG_SERIALIZER */ @@ -1073,154 +1493,123 @@ parse_value_from_blob (GMemoryInputStream *mis, is_leaf = TRUE; local_error = NULL; - if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) + switch (type_string[0]) { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + case 'b': /* G_VARIANT_TYPE_BOOLEAN */ + ensure_input_padding (buf, 4); if (!just_align) { gboolean v; - v = g_data_input_stream_read_uint32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_uint32 (buf); ret = g_variant_new_boolean (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)) - { + break; + + case 'y': /* G_VARIANT_TYPE_BYTE */ if (!just_align) { guchar v; - v = g_data_input_stream_read_byte (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_byte (buf); ret = g_variant_new_byte (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16)) - { - if (!ensure_input_padding (mis, 2, &local_error)) - goto fail; + break; + + case 'n': /* G_VARIANT_TYPE_INT16 */ + ensure_input_padding (buf, 2); if (!just_align) { gint16 v; - v = g_data_input_stream_read_int16 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_int16 (buf); ret = g_variant_new_int16 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) - { - if (!ensure_input_padding (mis, 2, &local_error)) - goto fail; + break; + + case 'q': /* G_VARIANT_TYPE_UINT16 */ + ensure_input_padding (buf, 2); if (!just_align) { guint16 v; - v = g_data_input_stream_read_uint16 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_uint16 (buf); ret = g_variant_new_uint16 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) - { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + break; + + case 'i': /* G_VARIANT_TYPE_INT32 */ + ensure_input_padding (buf, 4); if (!just_align) { gint32 v; - v = g_data_input_stream_read_int32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_int32 (buf); ret = g_variant_new_int32 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)) - { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + break; + + case 'u': /* G_VARIANT_TYPE_UINT32 */ + ensure_input_padding (buf, 4); if (!just_align) { guint32 v; - v = g_data_input_stream_read_uint32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_uint32 (buf); ret = g_variant_new_uint32 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64)) - { - if (!ensure_input_padding (mis, 8, &local_error)) - goto fail; + break; + + case 'x': /* G_VARIANT_TYPE_INT64 */ + ensure_input_padding (buf, 8); if (!just_align) { gint64 v; - v = g_data_input_stream_read_int64 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_int64 (buf); ret = g_variant_new_int64 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)) - { - if (!ensure_input_padding (mis, 8, &local_error)) - goto fail; + break; + + case 't': /* G_VARIANT_TYPE_UINT64 */ + ensure_input_padding (buf, 8); if (!just_align) { guint64 v; - v = g_data_input_stream_read_uint64 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_uint64 (buf); ret = g_variant_new_uint64 (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) - { - if (!ensure_input_padding (mis, 8, &local_error)) - goto fail; + break; + + case 'd': /* G_VARIANT_TYPE_DOUBLE */ + ensure_input_padding (buf, 8); if (!just_align) { - guint64 v; - gdouble *encoded; - v = g_data_input_stream_read_uint64 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + union { + guint64 v_uint64; + gdouble v_double; + } u; G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64)); - encoded = (gdouble *) &v; - ret = g_variant_new_double (*encoded); + u.v_uint64 = g_memory_buffer_read_uint64 (buf); + ret = g_variant_new_double (u.v_double); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) - { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + break; + + case 's': /* G_VARIANT_TYPE_STRING */ + ensure_input_padding (buf, 4); if (!just_align) { guint32 len; - gchar *v; - len = g_data_input_stream_read_uint32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; - v = read_string (mis, dis, (gsize) len, &local_error); + const gchar *v; + len = g_memory_buffer_read_uint32 (buf); + v = read_string (buf, (gsize) len, &local_error); if (v == NULL) goto fail; ret = g_variant_new_string (v); - g_free (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH)) - { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + break; + + case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */ + ensure_input_padding (buf, 4); if (!just_align) { guint32 len; - gchar *v; - len = g_data_input_stream_read_uint32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; - v = read_string (mis, dis, (gsize) len, &local_error); + const gchar *v; + len = g_memory_buffer_read_uint32 (buf); + v = read_string (buf, (gsize) len, &local_error); if (v == NULL) goto fail; if (!g_variant_is_object_path (v)) @@ -1228,25 +1617,21 @@ parse_value_from_blob (GMemoryInputStream *mis, g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Parsed value `%s' is not a valid D-Bus object path"), + _("Parsed value '%s' is not a valid D-Bus object path"), v); - g_free (v); goto fail; } ret = g_variant_new_object_path (v); - g_free (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE)) - { + break; + + case 'g': /* G_VARIANT_TYPE_SIGNATURE */ if (!just_align) { guchar len; - gchar *v; - len = g_data_input_stream_read_byte (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; - v = read_string (mis, dis, (gsize) len, &local_error); + const gchar *v; + len = g_memory_buffer_read_byte (buf); + v = read_string (buf, (gsize) len, &local_error); if (v == NULL) goto fail; if (!g_variant_is_signature (v)) @@ -1254,48 +1639,40 @@ parse_value_from_blob (GMemoryInputStream *mis, g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Parsed value `%s' is not a valid D-Bus signature"), + _("Parsed value '%s' is not a valid D-Bus signature"), v); - g_free (v); goto fail; } ret = g_variant_new_signature (v); - g_free (v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE)) - { - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + break; + + case 'h': /* G_VARIANT_TYPE_HANDLE */ + ensure_input_padding (buf, 4); if (!just_align) { gint32 v; - v = g_data_input_stream_read_int32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + v = g_memory_buffer_read_int32 (buf); ret = g_variant_new_handle (v); } - } - else if (g_variant_type_is_array (type)) - { - guint32 array_len; - goffset offset; - goffset target; - const GVariantType *element_type; - GVariantBuilder builder; + break; - if (!ensure_input_padding (mis, 4, &local_error)) - goto fail; + case 'a': /* G_VARIANT_TYPE_ARRAY */ + ensure_input_padding (buf, 4); - if (just_align) - { - array_len = 0; - } - else + /* If we are only aligning for this array type, it is the child type of + * another array, which is empty. So, we do not need to add padding for + * this nonexistent array's elements: we only need to align for this + * array itself (4 bytes). See + * . + */ + if (!just_align) { - array_len = g_data_input_stream_read_uint32 (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; + guint32 array_len; + const GVariantType *element_type; + guint fixed_size; + + array_len = g_memory_buffer_read_uint32 (buf); is_leaf = FALSE; #ifdef DEBUG_SERIALIZER @@ -1308,198 +1685,224 @@ parse_value_from_blob (GMemoryInputStream *mis, g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB)."), + g_dngettext (GETTEXT_PACKAGE, + "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB).", + "Encountered array of length %u bytes. Maximum length is 2<<26 bytes (64 MiB).", + array_len), array_len); goto fail; } - } - g_variant_builder_init (&builder, type); - element_type = g_variant_type_element (type); + element_type = g_variant_type_element (type); + fixed_size = get_type_fixed_size (element_type); - if (array_len == 0) - { - GVariant *item; - item = parse_value_from_blob (mis, - dis, - element_type, - TRUE, - indent + 2, - &local_error); - g_assert (item == NULL); - } - else - { - /* TODO: optimize array of primitive types */ - offset = g_seekable_tell (G_SEEKABLE (mis)); - target = offset + array_len; - while (offset < target) + /* Fast-path the cases like 'ay', etc. */ + if (fixed_size != 0) { - GVariant *item; - item = parse_value_from_blob (mis, - dis, - element_type, - FALSE, - indent + 2, - &local_error); - if (item == NULL) + gconstpointer array_data; + + if (array_len % fixed_size != 0) { - g_variant_builder_clear (&builder); + g_set_error (&local_error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Encountered array of type 'a%c', expected to have a length a multiple " + "of %u bytes, but found to be %u bytes in length"), + g_variant_type_peek_string (element_type)[0], fixed_size, array_len); goto fail; } - g_variant_builder_add_value (&builder, item); - g_variant_unref (item); - offset = g_seekable_tell (G_SEEKABLE (mis)); + + ensure_input_padding (buf, fixed_size); + array_data = read_bytes (buf, array_len, &local_error); + if (array_data == NULL) + goto fail; + + ret = g_variant_new_fixed_array (element_type, array_data, array_len / fixed_size, fixed_size); + + if (g_memory_buffer_is_byteswapped (buf)) + { + GVariant *tmp = g_variant_ref_sink (ret); + ret = g_variant_byteswap (tmp); + g_variant_unref (tmp); + } } - } + else + { + GVariantBuilder builder; + goffset offset; + goffset target; - if (!just_align) - { - ret = g_variant_builder_end (&builder); + g_variant_builder_init (&builder, type); + + if (array_len == 0) + { + GVariant *item; + item = parse_value_from_blob (buf, + element_type, + TRUE, + indent + 2, + NULL); + g_assert (item == NULL); + } + else + { + offset = buf->pos; + target = offset + array_len; + while (offset < target) + { + GVariant *item; + item = parse_value_from_blob (buf, + element_type, + FALSE, + indent + 2, + &local_error); + if (item == NULL) + { + g_variant_builder_clear (&builder); + goto fail; + } + g_variant_builder_add_value (&builder, item); + g_variant_unref (item); + offset = buf->pos; + } + } + + ret = g_variant_builder_end (&builder); + } } - else + break; + + default: + if (g_variant_type_is_dict_entry (type)) { - g_variant_builder_clear (&builder); - } - } - else if (g_variant_type_is_dict_entry (type)) - { - const GVariantType *key_type; - const GVariantType *value_type; - GVariant *key; - GVariant *value; + const GVariantType *key_type; + const GVariantType *value_type; + GVariant *key; + GVariant *value; - if (!ensure_input_padding (mis, 8, &local_error)) - goto fail; + ensure_input_padding (buf, 8); - is_leaf = FALSE; + is_leaf = FALSE; #ifdef DEBUG_SERIALIZER - g_print ("\n"); + g_print ("\n"); #endif /* DEBUG_SERIALIZER */ - if (!just_align) - { - key_type = g_variant_type_key (type); - key = parse_value_from_blob (mis, - dis, - key_type, - FALSE, - indent + 2, - &local_error); - if (key == NULL) - goto fail; - value_type = g_variant_type_value (type); - value = parse_value_from_blob (mis, - dis, - value_type, - FALSE, - indent + 2, - &local_error); - if (value == NULL) + if (!just_align) { + key_type = g_variant_type_key (type); + key = parse_value_from_blob (buf, + key_type, + FALSE, + indent + 2, + &local_error); + if (key == NULL) + goto fail; + value_type = g_variant_type_value (type); + value = parse_value_from_blob (buf, + value_type, + FALSE, + indent + 2, + &local_error); + if (value == NULL) + { + g_variant_unref (key); + goto fail; + } + ret = g_variant_new_dict_entry (key, value); g_variant_unref (key); - goto fail; + g_variant_unref (value); } - ret = g_variant_new_dict_entry (key, value); - g_variant_unref (key); - g_variant_unref (value); } - } - else if (g_variant_type_is_tuple (type)) - { - if (!ensure_input_padding (mis, 8, &local_error)) - goto fail; + else if (g_variant_type_is_tuple (type)) + { + ensure_input_padding (buf, 8); - is_leaf = FALSE; + is_leaf = FALSE; #ifdef DEBUG_SERIALIZER - g_print ("\n"); + g_print ("\n"); #endif /* DEBUG_SERIALIZER */ - if (!just_align) - { - const GVariantType *element_type; - GVariantBuilder builder; - - g_variant_builder_init (&builder, type); - element_type = g_variant_type_first (type); - while (element_type != NULL) + if (!just_align) { - GVariant *item; - item = parse_value_from_blob (mis, - dis, - element_type, - FALSE, - indent + 2, - &local_error); - if (item == NULL) + const GVariantType *element_type; + GVariantBuilder builder; + + g_variant_builder_init (&builder, type); + element_type = g_variant_type_first (type); + while (element_type != NULL) { - g_variant_builder_clear (&builder); - goto fail; - } - g_variant_builder_add_value (&builder, item); - g_variant_unref (item); + GVariant *item; + item = parse_value_from_blob (buf, + element_type, + FALSE, + indent + 2, + &local_error); + if (item == NULL) + { + g_variant_builder_clear (&builder); + goto fail; + } + g_variant_builder_add_value (&builder, item); + g_variant_unref (item); - element_type = g_variant_type_next (element_type); + element_type = g_variant_type_next (element_type); + } + ret = g_variant_builder_end (&builder); } - ret = g_variant_builder_end (&builder); } - } - else if (g_variant_type_is_variant (type)) - { - is_leaf = FALSE; + else if (g_variant_type_is_variant (type)) + { + is_leaf = FALSE; #ifdef DEBUG_SERIALIZER - g_print ("\n"); + g_print ("\n"); #endif /* DEBUG_SERIALIZER */ - if (!just_align) - { - guchar siglen; - gchar *sig; - GVariantType *variant_type; - GVariant *value; - - siglen = g_data_input_stream_read_byte (dis, NULL, &local_error); - if (local_error != NULL) - goto fail; - sig = read_string (mis, dis, (gsize) siglen, &local_error); - if (sig == NULL) - goto fail; - if (!g_variant_is_signature (sig)) + if (!just_align) { - g_set_error (&local_error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Parsed value `%s' for variant is not a valid D-Bus signature"), - sig); - g_free (sig); - goto fail; + guchar siglen; + const gchar *sig; + GVariantType *variant_type; + GVariant *value; + + siglen = g_memory_buffer_read_byte (buf); + sig = read_string (buf, (gsize) siglen, &local_error); + if (sig == NULL) + goto fail; + if (!g_variant_is_signature (sig)) + { + g_set_error (&local_error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Parsed value '%s' for variant is not a valid D-Bus signature"), + sig); + goto fail; + } + variant_type = g_variant_type_new (sig); + value = parse_value_from_blob (buf, + variant_type, + FALSE, + indent + 2, + &local_error); + g_variant_type_free (variant_type); + if (value == NULL) + goto fail; + ret = g_variant_new_variant (value); + g_variant_unref (value); } - variant_type = g_variant_type_new (sig); - g_free (sig); - value = parse_value_from_blob (mis, - dis, - variant_type, - FALSE, - indent + 2, - &local_error); - g_variant_type_free (variant_type); - if (value == NULL) - goto fail; - ret = g_variant_new_variant (value); - g_variant_unref (value); } - } - else - { - gchar *s; - s = g_variant_type_dup_string (type); - g_set_error (&local_error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Error deserializing GVariant with type string `%s' from the D-Bus wire format"), - s); - g_free (s); - goto fail; + else + { + gchar *s; + s = g_variant_type_dup_string (type); + g_set_error (&local_error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Error deserializing GVariant with type string '%s' from the D-Bus wire format"), + s); + g_free (s); + goto fail; + } + break; } g_assert ((just_align && ret == NULL) || (!just_align && ret != NULL)); @@ -1522,14 +1925,13 @@ parse_value_from_blob (GMemoryInputStream *mis, g_free (s); } } +#else + is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */ #endif /* DEBUG_SERIALIZER */ - /* sink the reference */ + /* sink the reference, if floating */ if (ret != NULL) - { - g_assert (g_variant_is_floating (ret)); - g_variant_ref_sink (ret); - } + g_variant_take_ref (ret); return ret; fail: @@ -1551,7 +1953,7 @@ parse_value_from_blob (GMemoryInputStream *mis, /** * g_dbus_message_bytes_needed: - * @blob: A blob represent a binary D-Bus message. + * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message. * @blob_len: The length of @blob (must be at least 16). * @error: Return location for error or %NULL. * @@ -1565,9 +1967,9 @@ parse_value_from_blob (GMemoryInputStream *mis, * Since: 2.26 */ gssize -g_dbus_message_bytes_needed (guchar *blob, - gsize blob_len, - GError **error) +g_dbus_message_bytes_needed (guchar *blob, + gsize blob_len, + GError **error) { gssize ret; @@ -1595,85 +1997,285 @@ g_dbus_message_bytes_needed (guchar *blob, /* finally add the body size */ ret += GUINT32_FROM_BE (((guint32 *) blob)[1]); } - else + else + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "Unable to determine message blob length - given blob is malformed"); + } + + if (ret > (2<<27)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + "Blob indicates that message exceeds maximum message length (128MiB)"); + ret = -1; + } + + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/** + * g_dbus_message_new_from_blob: + * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message. + * @blob_len: The length of @blob. + * @capabilities: A #GDBusCapabilityFlags describing what protocol features are supported. + * @error: Return location for error or %NULL. + * + * Creates a new #GDBusMessage from the data stored at @blob. The byte + * order that the message was in can be retrieved using + * g_dbus_message_get_byte_order(). + * + * Returns: A new #GDBusMessage or %NULL if @error is set. Free with + * g_object_unref(). + * + * Since: 2.26 + */ +GDBusMessage * +g_dbus_message_new_from_blob (guchar *blob, + gsize blob_len, + GDBusCapabilityFlags capabilities, + GError **error) +{ + gboolean ret; + GMemoryBuffer mbuf; + GDBusMessage *message; + guchar endianness; + guchar major_protocol_version; + guint32 message_body_len; + GVariant *headers; + GVariant *item; + GVariantIter iter; + GVariant *signature; + + /* TODO: check against @capabilities */ + + ret = FALSE; + + g_return_val_if_fail (blob != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + g_return_val_if_fail (blob_len >= 12, NULL); + + message = g_dbus_message_new (); + + memset (&mbuf, 0, sizeof (mbuf)); + mbuf.data = (gchar *)blob; + mbuf.len = mbuf.valid_len = blob_len; + + 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 != 1) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid major protocol version. Expected 1 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); + +#ifdef DEBUG_SERIALIZER + g_print ("Parsing blob (blob_len = 0x%04x bytes)\n", (gint) blob_len); + { + gchar *s; + s = _g_dbus_hexdump ((const gchar *) blob, blob_len, 2); + g_print ("%s\n", s); + g_free (s); + } +#endif /* DEBUG_SERIALIZER */ + +#ifdef DEBUG_SERIALIZER + g_print ("Parsing headers (blob_len = 0x%04x bytes)\n", (gint) blob_len); +#endif /* DEBUG_SERIALIZER */ + headers = parse_value_from_blob (&mbuf, + G_VARIANT_TYPE ("a{yv}"), + FALSE, + 2, + error); + 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); + + /* signature but no body */ + if (message_body_len == 0 && signature_str_len > 0) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Signature header with signature '%s' found but message body is empty"), + signature_str); + goto out; + } + else if (signature_str_len > 0) + { + GVariantType *variant_type; + gchar *tupled_signature_str; + + 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); +#ifdef DEBUG_SERIALIZER + g_print ("Parsing body (blob_len = 0x%04x bytes)\n", (gint) blob_len); +#endif /* DEBUG_SERIALIZER */ + message->body = parse_value_from_blob (&mbuf, + variant_type, + FALSE, + 2, + error); + 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_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "Unable to determine message blob length - given blob is malformed"); + g_prefix_error (error, _("Cannot deserialize message: ")); + goto out; } - if (ret > (2<<27)) + ret = TRUE; + + out: + if (ret) { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - "Blob indicates that message exceeds maximum message length (128MiB)"); - ret = -1; + return message; + } + else + { + if (message != NULL) + g_object_unref (message); + return NULL; } - - return ret; } /* ---------------------------------------------------------------------------------------------------- */ -/** - * g_dbus_message_new_from_blob: - * @blob: A blob represent a binary D-Bus message. - * @blob_len: The length of @blob. - * @capabilities: A #GDBusCapabilityFlags describing what protocol features are supported. - * @error: Return location for error or %NULL. - * - * Creates a new #GDBusMessage from the data stored at @blob. The byte - * order that the message was in can be retrieved using - * g_dbus_message_get_byte_order(). +/* + * _g_dbus_message_new_from_kdbus_items: * - * Returns: A new #GDBusMessage or %NULL if @error is set. Free with - * g_object_unref(). + * 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. * - * Since: 2.26 + * TODO: Add support for two and more items */ + GDBusMessage * -g_dbus_message_new_from_blob (guchar *blob, - gsize blob_len, - GDBusCapabilityFlags capabilities, - GError **error) +_g_dbus_message_new_from_kdbus_items (GSList *kdbus_msg_items, + GError **error) { gboolean ret; - GMemoryInputStream *mis; - GDataInputStream *dis; + GMemoryBuffer mbuf; GDBusMessage *message; guchar endianness; guchar major_protocol_version; - GDataStreamByteOrder byte_order; guint32 message_body_len; + guint32 message_headers_len; GVariant *headers; GVariant *item; GVariantIter iter; GVariant *signature; - /* TODO: check against @capabilities */ - ret = FALSE; - g_return_val_if_fail (blob != NULL, NULL); + g_return_val_if_fail (kdbus_msg_items != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - g_return_val_if_fail (blob_len >= 12, NULL); message = g_dbus_message_new (); + memset (&mbuf, 0, sizeof (mbuf)); - mis = G_MEMORY_INPUT_STREAM (g_memory_input_stream_new_from_data (blob, blob_len, NULL)); - dis = g_data_input_stream_new (G_INPUT_STREAM (mis)); + /* + * 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_data_input_stream_read_byte (dis, NULL, NULL); + endianness = g_memory_buffer_read_byte (&mbuf); switch (endianness) { case 'l': - byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN; break; case 'B': - byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN; break; default: @@ -1684,42 +2286,33 @@ g_dbus_message_new_from_blob (guchar *blob, endianness); goto out; } - g_data_input_stream_set_byte_order (dis, byte_order); - message->type = g_data_input_stream_read_byte (dis, NULL, NULL); - message->flags = g_data_input_stream_read_byte (dis, NULL, NULL); - major_protocol_version = g_data_input_stream_read_byte (dis, NULL, NULL); - if (major_protocol_version != 1) + 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 1 but found %d"), + _("Invalid major protocol version. Expected 2 but found %d"), major_protocol_version); goto out; } - message_body_len = g_data_input_stream_read_uint32 (dis, NULL, NULL); - message->serial = g_data_input_stream_read_uint32 (dis, NULL, NULL); -#ifdef DEBUG_SERIALIZER - g_print ("Parsing blob (blob_len = 0x%04x bytes)\n", (gint) blob_len); - { - gchar *s; - s = _g_dbus_hexdump ((const gchar *) blob, blob_len, 2); - g_print ("%s\n", s); - g_free (s); - } -#endif /* DEBUG_SERIALIZER */ + 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; -#ifdef DEBUG_SERIALIZER - g_print ("Parsing headers (blob_len = 0x%04x bytes)\n", (gint) blob_len); -#endif /* DEBUG_SERIALIZER */ - headers = parse_value_from_blob (mis, - dis, - G_VARIANT_TYPE ("a{yv}"), - FALSE, - 2, - error); if (headers == NULL) goto out; g_variant_iter_init (&iter, headers); @@ -1745,42 +2338,62 @@ g_dbus_message_new_from_blob (guchar *blob, signature_str = g_variant_get_string (signature, &signature_str_len); - /* signature but no body */ - if (message_body_len == 0 && signature_str_len > 0) - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Signature header with signature `%s' found but message body is empty"), - signature_str); - goto out; - } - else if (signature_str_len > 0) + 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)"), + _("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); -#ifdef DEBUG_SERIALIZER - g_print ("Parsing body (blob_len = 0x%04x bytes)\n", (gint) blob_len); -#endif /* DEBUG_SERIALIZER */ - message->body = parse_value_from_blob (mis, - dis, - variant_type, - FALSE, - 2, - error); + + /* + * 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; @@ -1795,7 +2408,10 @@ g_dbus_message_new_from_blob (guchar *blob, g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("No signature header in message but the message body is %u bytes"), + 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; } @@ -1810,9 +2426,6 @@ g_dbus_message_new_from_blob (guchar *blob, ret = TRUE; out: - g_object_unref (dis); - g_object_unref (mis); - if (ret) { return message; @@ -1825,127 +2438,129 @@ g_dbus_message_new_from_blob (guchar *blob, } } -/* ---------------------------------------------------------------------------------------------------- */ - static gsize -ensure_output_padding (GMemoryOutputStream *mos, - GDataOutputStream *dos, - gsize padding_size) +ensure_output_padding (GMemoryBuffer *mbuf, + gsize padding_size) { gsize offset; gsize wanted_offset; gsize padding_needed; guint n; - offset = g_memory_output_stream_get_data_size (mos); + offset = mbuf->pos; wanted_offset = ((offset + padding_size - 1) / padding_size) * padding_size; padding_needed = wanted_offset - offset; for (n = 0; n < padding_needed; n++) - g_data_output_stream_put_byte (dos, '\0', NULL, NULL); + g_memory_buffer_put_byte (mbuf, '\0'); return padding_needed; } /* note that value can be NULL for e.g. empty arrays - type is never NULL */ static gboolean -append_value_to_blob (GVariant *value, - const GVariantType *type, - GMemoryOutputStream *mos, - GDataOutputStream *dos, - gsize *out_padding_added, - GError **error) +append_value_to_blob (GVariant *value, + const GVariantType *type, + GMemoryBuffer *mbuf, + gsize *out_padding_added, + GError **error) { gsize padding_added; + const gchar *type_string; + + type_string = g_variant_type_peek_string (type); padding_added = 0; - if (g_variant_type_equal (type, G_VARIANT_TYPE_BOOLEAN)) + switch (type_string[0]) { - padding_added = ensure_output_padding (mos, dos, 4); + case 'b': /* G_VARIANT_TYPE_BOOLEAN */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { gboolean v = g_variant_get_boolean (value); - g_data_output_stream_put_uint32 (dos, v, NULL, NULL); + g_memory_buffer_put_uint32 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_BYTE)) - { + break; + + case 'y': /* G_VARIANT_TYPE_BYTE */ if (value != NULL) { guint8 v = g_variant_get_byte (value); - g_data_output_stream_put_byte (dos, v, NULL, NULL); + g_memory_buffer_put_byte (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT16)) - { - padding_added = ensure_output_padding (mos, dos, 2); + break; + + case 'n': /* G_VARIANT_TYPE_INT16 */ + padding_added = ensure_output_padding (mbuf, 2); if (value != NULL) { gint16 v = g_variant_get_int16 (value); - g_data_output_stream_put_int16 (dos, v, NULL, NULL); + g_memory_buffer_put_int16 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT16)) - { - padding_added = ensure_output_padding (mos, dos, 2); + break; + + case 'q': /* G_VARIANT_TYPE_UINT16 */ + padding_added = ensure_output_padding (mbuf, 2); if (value != NULL) { guint16 v = g_variant_get_uint16 (value); - g_data_output_stream_put_uint16 (dos, v, NULL, NULL); + g_memory_buffer_put_uint16 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32)) - { - padding_added = ensure_output_padding (mos, dos, 4); + break; + + case 'i': /* G_VARIANT_TYPE_INT32 */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { gint32 v = g_variant_get_int32 (value); - g_data_output_stream_put_int32 (dos, v, NULL, NULL); + g_memory_buffer_put_int32 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT32)) - { - padding_added = ensure_output_padding (mos, dos, 4); + break; + + case 'u': /* G_VARIANT_TYPE_UINT32 */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { guint32 v = g_variant_get_uint32 (value); - g_data_output_stream_put_uint32 (dos, v, NULL, NULL); + g_memory_buffer_put_uint32 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT64)) - { - padding_added = ensure_output_padding (mos, dos, 8); + break; + + case 'x': /* G_VARIANT_TYPE_INT64 */ + padding_added = ensure_output_padding (mbuf, 8); if (value != NULL) { gint64 v = g_variant_get_int64 (value); - g_data_output_stream_put_int64 (dos, v, NULL, NULL); + g_memory_buffer_put_int64 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_UINT64)) - { - padding_added = ensure_output_padding (mos, dos, 8); + break; + + case 't': /* G_VARIANT_TYPE_UINT64 */ + padding_added = ensure_output_padding (mbuf, 8); if (value != NULL) { guint64 v = g_variant_get_uint64 (value); - g_data_output_stream_put_uint64 (dos, v, NULL, NULL); + g_memory_buffer_put_uint64 (mbuf, v); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE)) - { - padding_added = ensure_output_padding (mos, dos, 8); + break; + + case 'd': /* G_VARIANT_TYPE_DOUBLE */ + padding_added = ensure_output_padding (mbuf, 8); if (value != NULL) { - guint64 *encoded; - gdouble v = g_variant_get_double (value); + union { + guint64 v_uint64; + gdouble v_double; + } u; G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64)); - encoded = (guint64 *) &v; - g_data_output_stream_put_uint64 (dos, *encoded, NULL, NULL); + u.v_double = g_variant_get_double (value); + g_memory_buffer_put_uint64 (mbuf, u.v_uint64); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING)) - { - padding_added = ensure_output_padding (mos, dos, 4); + break; + + case 's': /* G_VARIANT_TYPE_STRING */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { gsize len; @@ -1953,184 +2568,201 @@ append_value_to_blob (GVariant *value, const gchar *end; v = g_variant_get_string (value, &len); g_assert (g_utf8_validate (v, -1, &end) && (end == v + len)); - g_data_output_stream_put_uint32 (dos, len, NULL, NULL); - g_data_output_stream_put_string (dos, v, NULL, NULL); - g_data_output_stream_put_byte (dos, '\0', NULL, NULL); + g_memory_buffer_put_uint32 (mbuf, len); + g_memory_buffer_put_string (mbuf, v); + g_memory_buffer_put_byte (mbuf, '\0'); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_OBJECT_PATH)) - { - padding_added = ensure_output_padding (mos, dos, 4); + break; + + case 'o': /* G_VARIANT_TYPE_OBJECT_PATH */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { gsize len; const gchar *v = g_variant_get_string (value, &len); g_assert (g_variant_is_object_path (v)); - g_data_output_stream_put_uint32 (dos, len, NULL, NULL); - g_data_output_stream_put_string (dos, v, NULL, NULL); - g_data_output_stream_put_byte (dos, '\0', NULL, NULL); + g_memory_buffer_put_uint32 (mbuf, len); + g_memory_buffer_put_string (mbuf, v); + g_memory_buffer_put_byte (mbuf, '\0'); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_SIGNATURE)) - { + break; + + case 'g': /* G_VARIANT_TYPE_SIGNATURE */ if (value != NULL) { gsize len; const gchar *v = g_variant_get_string (value, &len); g_assert (g_variant_is_signature (v)); - g_data_output_stream_put_byte (dos, len, NULL, NULL); - g_data_output_stream_put_string (dos, v, NULL, NULL); - g_data_output_stream_put_byte (dos, '\0', NULL, NULL); + g_memory_buffer_put_byte (mbuf, len); + g_memory_buffer_put_string (mbuf, v); + g_memory_buffer_put_byte (mbuf, '\0'); } - } - else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE)) - { - padding_added = ensure_output_padding (mos, dos, 4); + break; + + case 'h': /* G_VARIANT_TYPE_HANDLE */ + padding_added = ensure_output_padding (mbuf, 4); if (value != NULL) { gint32 v = g_variant_get_handle (value); - g_data_output_stream_put_int32 (dos, v, NULL, NULL); + g_memory_buffer_put_int32 (mbuf, v); } - } - else if (g_variant_type_is_array (type)) - { - GVariant *item; - GVariantIter iter; - goffset array_len_offset; - goffset array_payload_begin_offset; - goffset cur_offset; - gsize array_len; + break; - padding_added = ensure_output_padding (mos, dos, 4); - if (value != NULL) - { - /* array length - will be filled in later */ - array_len_offset = g_memory_output_stream_get_data_size (mos); - g_data_output_stream_put_uint32 (dos, 0xF00DFACE, NULL, NULL); - - /* From the D-Bus spec: - * - * "A UINT32 giving the length of the array data in bytes, - * followed by alignment padding to the alignment boundary of - * the array element type, followed by each array element. The - * array length is from the end of the alignment padding to - * the end of the last element, i.e. it does not include the - * padding after the length, or any padding after the last - * element." - * - * Thus, we need to count how much padding the first element - * contributes and subtract that from the array length. - */ - array_payload_begin_offset = g_memory_output_stream_get_data_size (mos); + case 'a': /* G_VARIANT_TYPE_ARRAY */ + { + const GVariantType *element_type; + GVariant *item; + GVariantIter iter; + goffset array_len_offset; + goffset array_payload_begin_offset; + goffset cur_offset; + gsize array_len; + guint fixed_size; + + padding_added = ensure_output_padding (mbuf, 4); + if (value != NULL) + { + /* array length - will be filled in later */ + array_len_offset = mbuf->valid_len; + g_memory_buffer_put_uint32 (mbuf, 0xF00DFACE); + + /* From the D-Bus spec: + * + * "A UINT32 giving the length of the array data in bytes, + * followed by alignment padding to the alignment boundary of + * the array element type, followed by each array element. The + * array length is from the end of the alignment padding to + * the end of the last element, i.e. it does not include the + * padding after the length, or any padding after the last + * element." + * + * Thus, we need to count how much padding the first element + * contributes and subtract that from the array length. + */ + array_payload_begin_offset = mbuf->valid_len; + + element_type = g_variant_type_element (type); + fixed_size = get_type_fixed_size (element_type); + + if (g_variant_n_children (value) == 0) + { + gsize padding_added_for_item; + if (!append_value_to_blob (NULL, + element_type, + mbuf, + &padding_added_for_item, + error)) + goto fail; + array_payload_begin_offset += padding_added_for_item; + } + else if (fixed_size != 0) + { + GVariant *use_value; + + if (g_memory_buffer_is_byteswapped (mbuf)) + use_value = g_variant_byteswap (value); + else + use_value = g_variant_ref (value); + + array_payload_begin_offset += ensure_output_padding (mbuf, fixed_size); + + array_len = g_variant_get_size (use_value); + g_memory_buffer_write (mbuf, g_variant_get_data (use_value), array_len); + g_variant_unref (use_value); + } + else + { + guint n; + n = 0; + g_variant_iter_init (&iter, value); + while ((item = g_variant_iter_next_value (&iter)) != NULL) + { + gsize padding_added_for_item; + if (!append_value_to_blob (item, + g_variant_get_type (item), + mbuf, + &padding_added_for_item, + error)) + { + g_variant_unref (item); + goto fail; + } + g_variant_unref (item); + if (n == 0) + { + array_payload_begin_offset += padding_added_for_item; + } + n++; + } + } + + cur_offset = mbuf->valid_len; + array_len = cur_offset - array_payload_begin_offset; + mbuf->pos = array_len_offset; + + g_memory_buffer_put_uint32 (mbuf, array_len); + mbuf->pos = cur_offset; + } + } + break; - if (g_variant_n_children (value) == 0) - { - gsize padding_added_for_item; - if (!append_value_to_blob (NULL, - g_variant_type_element (type), - mos, - dos, - &padding_added_for_item, - error)) - goto fail; - array_payload_begin_offset += padding_added_for_item; - } - else + default: + if (g_variant_type_is_dict_entry (type) || g_variant_type_is_tuple (type)) + { + padding_added = ensure_output_padding (mbuf, 8); + if (value != NULL) { - guint n; - n = 0; + GVariant *item; + GVariantIter iter; g_variant_iter_init (&iter, value); while ((item = g_variant_iter_next_value (&iter)) != NULL) { - gsize padding_added_for_item; if (!append_value_to_blob (item, g_variant_get_type (item), - mos, - dos, - &padding_added_for_item, + mbuf, + NULL, error)) { g_variant_unref (item); goto fail; } g_variant_unref (item); - if (n == 0) - { - array_payload_begin_offset += padding_added_for_item; - } - n++; } } - - cur_offset = g_memory_output_stream_get_data_size (mos); - - array_len = cur_offset - array_payload_begin_offset; - - if (!g_seekable_seek (G_SEEKABLE (mos), array_len_offset, G_SEEK_SET, NULL, error)) - goto fail; - - g_data_output_stream_put_uint32 (dos, array_len, NULL, NULL); - - if (!g_seekable_seek (G_SEEKABLE (mos), cur_offset, G_SEEK_SET, NULL, error)) - goto fail; } - } - else if (g_variant_type_is_dict_entry (type) || g_variant_type_is_tuple (type)) - { - padding_added = ensure_output_padding (mos, dos, 8); - if (value != NULL) + else if (g_variant_type_is_variant (type)) { - GVariant *item; - GVariantIter iter; - g_variant_iter_init (&iter, value); - while ((item = g_variant_iter_next_value (&iter)) != NULL) + if (value != NULL) { - if (!append_value_to_blob (item, - g_variant_get_type (item), - mos, - dos, + GVariant *child; + const gchar *signature; + child = g_variant_get_child_value (value, 0); + signature = g_variant_get_type_string (child); + g_memory_buffer_put_byte (mbuf, strlen (signature)); + g_memory_buffer_put_string (mbuf, signature); + g_memory_buffer_put_byte (mbuf, '\0'); + if (!append_value_to_blob (child, + g_variant_get_type (child), + mbuf, NULL, error)) { - g_variant_unref (item); + g_variant_unref (child); goto fail; } - g_variant_unref (item); + g_variant_unref (child); } } - } - else if (g_variant_type_is_variant (type)) - { - if (value != NULL) + else { - GVariant *child; - const gchar *signature; - child = g_variant_get_child_value (value, 0); - signature = g_variant_get_type_string (child); - g_data_output_stream_put_byte (dos, strlen (signature), NULL, NULL); - g_data_output_stream_put_string (dos, signature, NULL, NULL); - g_data_output_stream_put_byte (dos, '\0', NULL, NULL); - if (!append_value_to_blob (child, - g_variant_get_type (child), - mos, - dos, - NULL, - error)) - { - g_variant_unref (child); - goto fail; - } - g_variant_unref (child); + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Error serializing GVariant with type string '%s' to the D-Bus wire format"), + g_variant_get_type_string (value)); + goto fail; } - } - else - { - g_set_error (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Error serializing GVariant with type string `%s' to the D-Bus wire format"), - g_variant_get_type_string (value)); - goto fail; + break; } if (out_padding_added != NULL) @@ -2143,17 +2775,13 @@ append_value_to_blob (GVariant *value, } static gboolean -append_body_to_blob (GVariant *value, - GMemoryOutputStream *mos, - GDataOutputStream *dos, - GError **error) +append_body_to_blob (GVariant *value, + GMemoryBuffer *mbuf, + GError **error) { - gboolean ret; GVariant *item; GVariantIter iter; - ret = FALSE; - if (!g_variant_is_of_type (value, G_VARIANT_TYPE_TUPLE)) { g_set_error (error, @@ -2168,8 +2796,7 @@ append_body_to_blob (GVariant *value, { if (!append_value_to_blob (item, g_variant_get_type (item), - mos, - dos, + mbuf, NULL, error)) { @@ -2186,6 +2813,12 @@ append_body_to_blob (GVariant *value, /* ---------------------------------------------------------------------------------------------------- */ +/* [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. @@ -2196,8 +2829,9 @@ append_body_to_blob (GVariant *value, * Serializes @message to a blob. The byte order returned by * g_dbus_message_get_byte_order() will be used. * - * Returns: A pointer to a valid binary D-Bus message of @out_size bytes - * generated by @message or %NULL if @error is set. Free with g_free(). + * Returns: (array length=out_size) (transfer full): A pointer to a + * valid binary D-Bus message of @out_size bytes generated by @message + * or %NULL if @error is set. Free with g_free(). * * Since: 2.26 */ @@ -2207,15 +2841,17 @@ g_dbus_message_to_blob (GDBusMessage *message, GDBusCapabilityFlags capabilities, GError **error) { - GMemoryOutputStream *mos; - GDataOutputStream *dos; + GMemoryBuffer mbuf; guchar *ret; gsize size; - GDataStreamByteOrder byte_order; 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; @@ -2233,30 +2869,47 @@ g_dbus_message_to_blob (GDBusMessage *message, g_return_val_if_fail (out_size != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - mos = G_MEMORY_OUTPUT_STREAM (g_memory_output_stream_new (NULL, 0, g_realloc, g_free)); - dos = g_data_output_stream_new (G_OUTPUT_STREAM (mos)); + /* 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); - byte_order = G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN; + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_HOST_ENDIAN; switch (message->byte_order) { case G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN: - byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; break; case G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN: - byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; break; } - g_data_output_stream_set_byte_order (dos, byte_order); /* Core header */ - g_data_output_stream_put_byte (dos, (guchar) message->byte_order, NULL, NULL); - g_data_output_stream_put_byte (dos, message->type, NULL, NULL); - g_data_output_stream_put_byte (dos, message->flags, NULL, NULL); - g_data_output_stream_put_byte (dos, 1, NULL, NULL); /* major protocol version */ - body_len_offset = g_memory_output_stream_get_data_size (mos); + 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); + + body_len_offset = mbuf.valid_len; /* body length - will be filled in later */ - g_data_output_stream_put_uint32 (dos, 0xF00DFACE, NULL, NULL); - g_data_output_stream_put_uint32 (dos, message->serial, NULL, NULL); + g_memory_buffer_put_uint32 (&mbuf, 0xF00DFACE); + g_memory_buffer_put_uint32 (&mbuf, message->serial); num_fds_in_message = 0; #ifdef G_OS_UNIX @@ -2269,7 +2922,7 @@ g_dbus_message_to_blob (GDBusMessage *message, g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Message has %d fds but the header field indicates %d fds"), + _("Message has %d file descriptors but the header field indicates %d file descriptors"), num_fds_in_message, num_fds_according_to_header); goto out; @@ -2292,21 +2945,36 @@ g_dbus_message_to_blob (GDBusMessage *message, } header_fields = g_variant_builder_end (&builder); - if (!append_value_to_blob (header_fields, - g_variant_get_type (header_fields), - mos, dos, - NULL, - error)) + /* header - dbus1 marshaliling */ + if (message->major_protocol_version == 1) { - g_variant_unref (header_fields); - goto out; + 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) + { + 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); /* header size must be a multiple of 8 */ - ensure_output_padding (mos, dos, 8); + ensure_output_padding (&mbuf, 8); - body_start_offset = g_memory_output_stream_get_data_size (mos); + body_start_offset = mbuf.valid_len; signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE); signature_str = NULL; @@ -2321,7 +2989,7 @@ g_dbus_message_to_blob (GDBusMessage *message, g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Message body has signature `%s' but there is no signature header"), + _("Message body has signature '%s' but there is no signature header"), signature_str); g_free (tupled_signature_str); goto out; @@ -2331,14 +2999,29 @@ g_dbus_message_to_blob (GDBusMessage *message, g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Message body has type signature `%s' but signature in the header field is `%s'"), + _("Message body has type signature '%s' but signature in the header field is '%s'"), tupled_signature_str, g_variant_get_type_string (message->body)); g_free (tupled_signature_str); goto out; } g_free (tupled_signature_str); - if (!append_body_to_blob (message->body, mos, dos, error)) - goto out; + + /* 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 } else { @@ -2347,31 +3030,24 @@ g_dbus_message_to_blob (GDBusMessage *message, g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Message body is empty but signature in the header field is `(%s)'"), + _("Message body is empty but signature in the header field is '(%s)'"), signature_str); goto out; } } /* OK, we're done writing the message - set the body length */ - size = g_memory_output_stream_get_data_size (mos); + size = mbuf.valid_len; body_size = size - body_start_offset; - if (!g_seekable_seek (G_SEEKABLE (mos), body_len_offset, G_SEEK_SET, NULL, error)) - goto out; - - g_data_output_stream_put_uint32 (dos, body_size, NULL, NULL); + mbuf.pos = body_len_offset; - if (!g_output_stream_close (G_OUTPUT_STREAM (dos), NULL, error)) - goto out; + g_memory_buffer_put_uint32 (&mbuf, body_size); *out_size = size; - ret = g_memory_output_stream_steal_data (mos); + ret = (guchar *)mbuf.data; out: - g_object_unref (dos); - g_object_unref (mos); - return ret; } @@ -2904,7 +3580,7 @@ g_dbus_message_to_gerror (GDBusMessage *message, g_dbus_error_set_dbus_error (error, error_name, "", - _("Error return with body of type `%s'"), + _("Error return with body of type '%s'"), g_variant_get_type_string (body)); } else @@ -2987,7 +3663,7 @@ _sort_keys_func (gconstpointer a, * The contents of the description has no ABI guarantees, the contents * and formatting is subject to change at any time. Typical output * looks something like this: - * + * |[ * Type: method-call * Flags: none * Version: 0 @@ -3000,9 +3676,9 @@ _sort_keys_func (gconstpointer a, * Body: () * UNIX File Descriptors: * (none) - * + * ]| * or - * + * |[ * Type: method-return * Flags: no-reply-expected * Version: 0 @@ -3015,7 +3691,7 @@ _sort_keys_func (gconstpointer a, * Body: () * UNIX File Descriptors: * fd 12: dev=0:10,mode=020620,ino=5,uid=500,gid=5,rdev=136:2,size=0,atime=1273085037,mtime=1273085851,ctime=1272982635 - * + * ]| * * Returns: A string that should be freed with g_free(). * @@ -3104,10 +3780,10 @@ g_dbus_message_print (GDBusMessage *message, statbuf.st_mode); g_string_append_printf (fs, "%s" "ino=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "", (guint64) statbuf.st_ino); - g_string_append_printf (fs, "%s" "uid=%d", fs->len > 0 ? "," : "", - statbuf.st_uid); - g_string_append_printf (fs, "%s" "gid=%d", fs->len > 0 ? "," : "", - statbuf.st_gid); + g_string_append_printf (fs, "%s" "uid=%u", fs->len > 0 ? "," : "", + (guint) statbuf.st_uid); + g_string_append_printf (fs, "%s" "gid=%u", fs->len > 0 ? "," : "", + (guint) statbuf.st_gid); g_string_append_printf (fs, "%s" "rdev=%d:%d", fs->len > 0 ? "," : "", major (statbuf.st_rdev), minor (statbuf.st_rdev)); g_string_append_printf (fs, "%s" "size=%" G_GUINT64_FORMAT, fs->len > 0 ? "," : "", @@ -3195,8 +3871,8 @@ g_dbus_message_lock (GDBusMessage *message) * This operation can fail if e.g. @message contains file descriptors * and the per-process or system-wide open files limit is reached. * - * Returns: (transfer full): A new #GDBusMessage or %NULL if @error is set. Free with - * g_object_unref(). + * Returns: (transfer full): A new #GDBusMessage or %NULL if @error is set. + * Free with g_object_unref(). * * Since: 2.26 */ @@ -3210,7 +3886,7 @@ g_dbus_message_copy (GDBusMessage *message, GVariant *header_value; g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); - g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); ret = g_dbus_message_new (); ret->type = message->type; @@ -3250,7 +3926,8 @@ g_dbus_message_copy (GDBusMessage *message, while (g_hash_table_iter_next (&iter, &header_key, (gpointer) &header_value)) g_hash_table_insert (ret->headers, header_key, g_variant_ref (header_value)); +#ifdef G_OS_UNIX out: +#endif return ret; } -