From d64e2f172ea8c5ee1ae1f954cf7a2b8e5187439c Mon Sep 17 00:00:00 2001 From: Lukasz Skalski Date: Fri, 21 Nov 2014 17:23:28 +0100 Subject: [PATCH] [kdbus][wip] Import code from tizen.org repo --- gio/gdbusconnection.c | 12 + gio/gdbusmessage.c | 321 ++++++++++++++++++++- gio/gdbusmessage.h | 10 + gio/gdbusprivate.c | 195 ++++++++++--- gio/gkdbus.c | 754 +++++++++++++++++++++++++++++++++++++++++++++++++- gio/gkdbus.h | 27 ++ 6 files changed, 1260 insertions(+), 59 deletions(-) diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 55c2156..d9ee982 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -2124,6 +2124,18 @@ g_dbus_connection_send_message_unlocked (GDBusConnection *connection, error)) goto out; + /* [KDBUS] + * Setting protocol version, before invoking g_dbus_message_to_blob() will + * be removed after preparing new function only for kdbus transport purposes + * (this function will be able to create blob directly/unconditionally in memfd + * object, without making copy) + */ + + if (G_IS_KDBUS_CONNECTION (connection->stream)) + _g_dbus_message_set_protocol_ver (message,2); + else + _g_dbus_message_set_protocol_ver (message,1); + blob = g_dbus_message_to_blob (message, &blob_size, connection->capabilities, diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 766609e..bfe91e6 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -49,6 +49,7 @@ #include "gdbusprivate.h" #ifdef G_OS_UNIX +#include "gkdbus.h" #include "gunixfdlist.h" #endif @@ -972,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 */ /** @@ -2192,6 +2225,219 @@ g_dbus_message_new_from_blob (guchar *blob, /* ---------------------------------------------------------------------------------------------------- */ +/* + * _g_dbus_message_new_from_kdbus_items: + * + * Single kdbus message may contain zero, one or more items + * (PAYLOAD_VEC or PAYLOAD_MEMFD), so we need this function + * (only for kdbus transport purposes) to parse them to GDBusMessage. + * kdbus_msg_items list contain list of pointer + data pair for each received item. + * + * TODO: Add support for two and more items + */ + +GDBusMessage * +_g_dbus_message_new_from_kdbus_items (GSList *kdbus_msg_items, + GError **error) +{ + gboolean ret; + GMemoryBuffer mbuf; + GDBusMessage *message; + guchar endianness; + guchar major_protocol_version; + guint32 message_body_len; + guint32 message_headers_len; + GVariant *headers; + GVariant *item; + GVariantIter iter; + GVariant *signature; + + ret = FALSE; + + g_return_val_if_fail (kdbus_msg_items != NULL, NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + message = g_dbus_message_new (); + memset (&mbuf, 0, sizeof (mbuf)); + + /* + * MESSAGE HEADER + * message header in its entirety must be contained in a first single item + */ + mbuf.data = ((msg_part*)kdbus_msg_items->data)->data; + mbuf.len = mbuf.valid_len = ((msg_part*)kdbus_msg_items->data)->size; + + endianness = g_memory_buffer_read_byte (&mbuf); + switch (endianness) + { + case 'l': + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_LITTLE_ENDIAN; + message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_LITTLE_ENDIAN; + break; + case 'B': + mbuf.byte_order = G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN; + message->byte_order = G_DBUS_MESSAGE_BYTE_ORDER_BIG_ENDIAN; + break; + default: + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid endianness value. Expected 0x6c ('l') or 0x42 ('B') but found value 0x%02x"), + endianness); + goto out; + } + + message->type = g_memory_buffer_read_byte (&mbuf); + message->flags = g_memory_buffer_read_byte (&mbuf); + major_protocol_version = g_memory_buffer_read_byte (&mbuf); + + if (major_protocol_version != 2) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Invalid major protocol version. Expected 2 but found %d"), + major_protocol_version); + goto out; + } + + message_body_len = g_memory_buffer_read_uint32 (&mbuf); + message->serial = g_memory_buffer_read_uint32 (&mbuf); + + message_headers_len = g_memory_buffer_read_uint32 (&mbuf); + headers = g_variant_new_from_data (G_VARIANT_TYPE ("a{yv}"), + mbuf.data + mbuf.pos, + message_headers_len, + TRUE, + NULL, + NULL); + mbuf.pos += message_headers_len; + + if (headers == NULL) + goto out; + g_variant_iter_init (&iter, headers); + while ((item = g_variant_iter_next_value (&iter)) != NULL) + { + guchar header_field; + GVariant *value; + g_variant_get (item, + "{yv}", + &header_field, + &value); + g_dbus_message_set_header (message, header_field, value); + g_variant_unref (value); + g_variant_unref (item); + } + g_variant_unref (headers); + + signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE); + if (signature != NULL) + { + const gchar *signature_str; + gsize signature_str_len; + + signature_str = g_variant_get_string (signature, &signature_str_len); + + if (signature_str_len > 0) + { + GVariantType *variant_type; + gchar *tupled_signature_str; + + gchar *data = NULL; + gsize size = NULL; + + if (!g_variant_is_signature (signature_str)) + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("Parsed value '%s' is not a valid D-Bus signature (for body)"), + signature_str); + goto out; + } + tupled_signature_str = g_strdup_printf ("(%s)", signature_str); + variant_type = g_variant_type_new (tupled_signature_str); + g_free (tupled_signature_str); + + /* + * MESSAGE BODY + */ + + if (g_slist_length(kdbus_msg_items) == 1) + { + /* if kdbus_msg_items has only one element, head and body are + contained in a single PAYLOAD_VEC item */ + ensure_input_padding (&mbuf,8); + data = mbuf.data + mbuf.pos; + size = message_body_len; + } + else if (g_slist_length(kdbus_msg_items) > 1) + { + /* message consists two or more items + TODO: Add support for three and more items */ + data = ((msg_part*)g_slist_next(kdbus_msg_items)->data)->data; + size = ((msg_part*)g_slist_next(kdbus_msg_items)->data)->size; + } + else + { + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + _("[KDBUS] Received message is not valid")); + goto out; + } + + message->body = g_variant_new_from_data (variant_type, + data, + size, + TRUE, + NULL, + NULL); + + g_variant_type_free (variant_type); + if (message->body == NULL) + goto out; + } + } + else + { + /* no signature, this is only OK if the body is empty */ + if (message_body_len != 0) + { + /* G_GUINT32_FORMAT doesn't work with gettext, just use %u */ + g_set_error (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_ARGUMENT, + g_dngettext (GETTEXT_PACKAGE, + "No signature header in message but the message body is %u byte", + "No signature header in message but the message body is %u bytes", + message_body_len), + message_body_len); + goto out; + } + } + + if (!validate_headers (message, error)) + { + g_prefix_error (error, _("Cannot deserialize message: ")); + goto out; + } + + ret = TRUE; + + out: + if (ret) + { + return message; + } + else + { + if (message != NULL) + g_object_unref (message); + return NULL; + } +} + static gsize ensure_output_padding (GMemoryBuffer *mbuf, gsize padding_size) @@ -2567,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. @@ -2595,7 +2847,11 @@ g_dbus_message_to_blob (GDBusMessage *message, 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; @@ -2613,6 +2869,20 @@ 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); + /* 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); @@ -2632,7 +2902,10 @@ g_dbus_message_to_blob (GDBusMessage *message, 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); - g_memory_buffer_put_byte (&mbuf, 1); /* major protocol version */ + + /* 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_memory_buffer_put_uint32 (&mbuf, 0xF00DFACE); @@ -2672,15 +2945,30 @@ 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), - &mbuf, - 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 */ @@ -2717,8 +3005,21 @@ g_dbus_message_to_blob (GDBusMessage *message, goto out; } g_free (tupled_signature_str); - if (!append_body_to_blob (message->body, &mbuf, error)) - goto out; + + /* body - dbus1 marshaliling */ + if (message->major_protocol_version == 1) + { + if (!append_body_to_blob (message->body, &mbuf, error)) + goto out; + } + /* 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); + } } else { diff --git a/gio/gdbusmessage.h b/gio/gdbusmessage.h index f791889..8f9b25e 100644 --- a/gio/gdbusmessage.h +++ b/gio/gdbusmessage.h @@ -192,6 +192,16 @@ GLIB_AVAILABLE_IN_ALL gboolean g_dbus_message_to_gerror (GDBusMessage *message, GError **error); +GDBusMessage *_g_dbus_message_new_from_kdbus_items (GSList *kdbus_msg_items, + GError **error); + +/* to remove */ +guint32 _g_dbus_message_get_protocol_ver (GDBusMessage *message); + +/* to remove */ +void _g_dbus_message_set_protocol_ver (GDBusMessage *message, + guint32 protocol_ver); + G_END_DECLS #endif /* __G_DBUS_MESSAGE_H__ */ diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 91feb41..e3f1cda 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -477,6 +477,10 @@ struct GDBusWorker GUnixFDList *read_fd_list; GSocketControlMessage **read_ancillary_messages; gint read_num_ancillary_messages; +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + GSList *read_kdbus_msg_items; +#endif + /* Whether an async write, flush or close, or none of those, is pending. * Only the worker thread may change its value, and only with the write_lock. @@ -697,7 +701,15 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, bytes_read = _g_kdbus_read_finish (worker->kdbus, res, &error); - g_error ("[KDBUS] _g_dbus_worker_do_read_cb() - work in progress"); + + /* [KDBUS] Get all received items*/ + worker->read_kdbus_msg_items = _g_kdbus_get_last_msg_items (worker->kdbus); + + /* [KDBUS] Attach fds (if any) to worker->read_fd_list */ + _g_kdbus_attach_fds_to_msg (worker->kdbus, &worker->read_fd_list); + + /* [KDBUS] For KDBUS transport we read whole message at once*/ + worker->read_buffer_bytes_wanted = bytes_read; } #endif else if (worker->socket == NULL) @@ -779,9 +791,8 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, _g_dbus_debug_print_lock (); g_print ("========================================================================\n" "GDBus-debug:Transport:\n" - " ---- READ ERROR on stream of type %s:\n" + " ---- READ ERROR:\n" " ---- %s %d: %s\n", - g_type_name (G_TYPE_FROM_INSTANCE (g_io_stream_get_input_stream (worker->stream))), g_quark_to_string (error->domain), error->code, error->message); _g_dbus_debug_print_unlock (); @@ -835,7 +846,9 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, goto out; } - read_message_print_transport_debug (bytes_read, worker); + /* [KDBUS] don't print transport dbus debug for kdbus connection */ + if (!G_IS_KDBUS_CONNECTION (worker->stream)) + read_message_print_transport_debug (bytes_read, worker); worker->read_buffer_cur_size += bytes_read; if (worker->read_buffer_bytes_wanted == worker->read_buffer_cur_size) @@ -867,25 +880,61 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, /* TODO: use connection->priv->auth to decode the message */ - message = g_dbus_message_new_from_blob ((guchar *) worker->read_buffer, - worker->read_buffer_cur_size, - worker->capabilities, - &error); - if (message == NULL) + if (FALSE) { - gchar *s; - s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2); - g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n" - "The error is: %s\n" - "The payload is as follows:\n" - "%s\n", - worker->read_buffer_cur_size, - error->message, - s); - g_free (s); - _g_dbus_worker_emit_disconnected (worker, FALSE, error); - g_error_free (error); - goto out; + } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + else if (G_IS_KDBUS_CONNECTION (worker->stream)) + { + GDBusMessageType message_type; + gchar *sender; + gchar *destination; + + message = _g_dbus_message_new_from_kdbus_items (worker->read_kdbus_msg_items, + &error); + + /* [KDBUS] override informations from the user header with kernel msg header */ + sender = _g_kdbus_get_last_msg_sender (worker->kdbus); + g_dbus_message_set_sender (message, sender); + + message_type = g_dbus_message_get_message_type (message); + if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL) + { + destination = _g_kdbus_get_last_msg_destination (worker->kdbus); + g_dbus_message_set_destination (message, destination); + } + + if (message == NULL) + { + g_warning ("Error decoding D-Bus (kdbus) message\n"); + g_error_free (error); + goto out; + } + } +#endif + else + { + message = g_dbus_message_new_from_blob ((guchar *) worker->read_buffer, + worker->read_buffer_cur_size, + worker->capabilities, + &error); + + if (message == NULL) + { + gchar *s; + s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2); + g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n" + "The error is: %s\n" + "The payload is as follows:\n" + "%s\n", + worker->read_buffer_cur_size, + error->message, + s); + g_free (s); + _g_dbus_worker_emit_disconnected (worker, FALSE, error); + g_error_free (error); + goto out; + } } #ifdef G_OS_UNIX @@ -910,7 +959,15 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, g_free (s); if (G_UNLIKELY (_g_dbus_debug_payload ())) { - s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2); + if (FALSE) + { + } +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + else if (G_IS_KDBUS_CONNECTION (worker->stream)) + s = _g_kdbus_hexdump_all_items (worker->read_kdbus_msg_items); +#endif + else + s = _g_dbus_hexdump (worker->read_buffer, worker->read_buffer_cur_size, 2); g_print ("%s\n", s); g_free (s); } @@ -933,6 +990,20 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, } out: + +#if defined (G_OS_UNIX) && (KDBUS_TRANSPORT) + /* [KDBUS] release memory occupied by kdbus message */ + if (G_IS_KDBUS_CONNECTION (worker->stream)) + { + if (!_g_kdbus_is_closed (worker->kdbus)) + { + _g_kdbus_release_kmsg (worker->kdbus); + worker->read_kdbus_msg_items = NULL; + } + worker->read_buffer = NULL; + } +#endif + g_mutex_unlock (&worker->read_lock); /* gives up the reference acquired when calling g_input_stream_read_async() */ @@ -1119,22 +1190,41 @@ static void write_message_continue_writing (MessageToWriteData *data) { GOutputStream *ostream; + #ifdef G_OS_UNIX GSimpleAsyncResult *simple; GUnixFDList *fd_list; -#endif -#ifdef G_OS_UNIX /* Note: we can't access data->simple after calling g_async_result_complete () because the * callback can free @data and we're not completing in idle. So use a copy of the pointer. */ simple = data->simple; -#endif - ostream = g_io_stream_get_output_stream (data->worker->stream); -#ifdef G_OS_UNIX fd_list = g_dbus_message_get_unix_fd_list (data->message); -#endif + +#ifdef KDBUS_TRANSPORT + if (G_IS_KDBUS_CONNECTION (data->worker->stream)) + { + GError *error; + error = NULL; + data->total_written = _g_kdbus_send (data->worker, + data->worker->kdbus, + data->message, + data->blob, + data->blob_size, + fd_list, + data->worker->cancellable, + &error); + + g_simple_async_result_complete (simple); + g_object_unref (simple); + goto out; + } +#endif /* KDBUS_TRANSPORT */ + +#endif /* G_OS_UNIX */ + + ostream = g_io_stream_get_output_stream (data->worker->stream); g_assert (!g_output_stream_has_pending (ostream)); g_assert_cmpint (data->total_written, <, data->blob_size); @@ -1370,11 +1460,33 @@ ostream_flush_cb (GObject *source_object, static void start_flush (FlushAsyncData *data) { - g_output_stream_flush_async (g_io_stream_get_output_stream (data->worker->stream), - G_PRIORITY_DEFAULT, - data->worker->cancellable, - ostream_flush_cb, - data); + /*[KDBUS]: TODO: to investigate */ + if (G_IS_KDBUS_CONNECTION (data->worker->stream)) + { + g_assert (data->flushers != NULL); + flush_data_list_complete (data->flushers, NULL); + g_list_free (data->flushers); + + g_mutex_lock (&data->worker->write_lock); + data->worker->write_num_messages_flushed = data->worker->write_num_messages_written; + g_assert (data->worker->output_pending == PENDING_FLUSH); + data->worker->output_pending = PENDING_NONE; + g_mutex_unlock (&data->worker->write_lock); + + /* OK, cool, finally kick off the next write */ + continue_writing (data->worker); + + _g_dbus_worker_unref (data->worker); + g_free (data); + } + else + { + g_output_stream_flush_async (g_io_stream_get_output_stream (data->worker->stream), + G_PRIORITY_DEFAULT, + data->worker->cancellable, + ostream_flush_cb, + data); + } } /* called in private thread shared by all GDBusConnection instances @@ -1645,6 +1757,21 @@ continue_writing (GDBusWorker *worker) { /* filters altered the message -> reencode */ error = NULL; + + /* [KDBUS] + * Setting protocol version, before invoking g_dbus_message_to_blob() will + * be removed after preparing new function only for kdbus transport purposes + * (this function will be able to create blob directly/unconditionally in memfd + * object, without making copy): + * + * [1] https://code.google.com/p/d-bus/source/browse/TODO + */ + + if (G_IS_KDBUS_CONNECTION (worker->stream)) + _g_dbus_message_set_protocol_ver (data->message,2); + else + _g_dbus_message_set_protocol_ver (data->message,1); + new_blob = g_dbus_message_to_blob (data->message, &new_blob_size, worker->capabilities, diff --git a/gio/gkdbus.c b/gio/gkdbus.c index e612b8f..fabeba0 100644 --- a/gio/gkdbus.c +++ b/gio/gkdbus.c @@ -34,6 +34,7 @@ #include #include #include +#include #ifdef HAVE_SYS_FILIO_H # include @@ -43,6 +44,13 @@ #include #endif +#include +#include +#include + +#include "glibintl.h" +#include "gunixfdmessage.h" + #define KDBUS_POOL_SIZE (16 * 1024LU * 1024LU) #define KDBUS_ALIGN8(l) (((l) + 7) & ~7) #define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p)) @@ -93,6 +101,16 @@ struct _GKdbusPrivate guint64 attach_flags_send; guint64 attach_flags_recv; + GString *msg_sender; + GString *msg_destination; + GSList *kdbus_msg_items; + + gint *fds; + gint num_fds; + + gsize bloom_size; + guint bloom_n_hash; + guint closed : 1; guint inited : 1; guint timeout; @@ -117,6 +135,94 @@ typedef gboolean (*GKdbusSourceFunc) (GKdbus *kdbus, GIOCondition condition, gpointer user_data); +/* Hash keys for bloom filters*/ +const guint8 hash_keys[8][16] = +{ + {0xb9,0x66,0x0b,0xf0,0x46,0x70,0x47,0xc1,0x88,0x75,0xc4,0x9c,0x54,0xb9,0xbd,0x15}, + {0xaa,0xa1,0x54,0xa2,0xe0,0x71,0x4b,0x39,0xbf,0xe1,0xdd,0x2e,0x9f,0xc5,0x4a,0x3b}, + {0x63,0xfd,0xae,0xbe,0xcd,0x82,0x48,0x12,0xa1,0x6e,0x41,0x26,0xcb,0xfa,0xa0,0xc8}, + {0x23,0xbe,0x45,0x29,0x32,0xd2,0x46,0x2d,0x82,0x03,0x52,0x28,0xfe,0x37,0x17,0xf5}, + {0x56,0x3b,0xbf,0xee,0x5a,0x4f,0x43,0x39,0xaf,0xaa,0x94,0x08,0xdf,0xf0,0xfc,0x10}, + {0x31,0x80,0xc8,0x73,0xc7,0xea,0x46,0xd3,0xaa,0x25,0x75,0x0f,0x9e,0x4c,0x09,0x29}, + {0x7d,0xf7,0x18,0x4b,0x7b,0xa4,0x44,0xd5,0x85,0x3c,0x06,0xe0,0x65,0x53,0x96,0x6d}, + {0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35} +}; + + +/** + * _g_kdbus_get_last_msg_sender + * + */ +gchar * +_g_kdbus_get_last_msg_sender (GKdbus *kdbus) +{ + return kdbus->priv->msg_sender->str; +} + + +/** + * _g_kdbus_get_last_msg_destination + * + */ +gchar * +_g_kdbus_get_last_msg_destination (GKdbus *kdbus) +{ + return kdbus->priv->msg_destination->str; +} + + +/** + * _g_kdbus_get_last_msg_items: + * + */ +GSList * +_g_kdbus_get_last_msg_items (GKdbus *kdbus) +{ + return kdbus->priv->kdbus_msg_items; +} + + +/** + * g_kdbus_add_msg_part: + * + */ +static void +g_kdbus_add_msg_part (GKdbus *kdbus, + gchar *data, + gsize size) +{ + msg_part* part = g_new (msg_part, 1); + part->data = data; + part->size = size; + kdbus->priv->kdbus_msg_items = g_slist_append (kdbus->priv->kdbus_msg_items, part); +} + + +/** + * _g_kdbus_hexdump_all_items: + * + */ +gchar * +_g_kdbus_hexdump_all_items (GSList *kdbus_msg_items) +{ + + GString *ret; + gint item = 1; + ret = g_string_new (NULL); + + while (kdbus_msg_items != NULL) + { + g_string_append_printf (ret, "\n Item %d\n", item); + g_string_append (ret, _g_dbus_hexdump (((msg_part*)kdbus_msg_items->data)->data, ((msg_part*)kdbus_msg_items->data)->size, 2)); + + kdbus_msg_items = g_slist_next(kdbus_msg_items); + item++; + } + + return g_string_free (ret, FALSE); +} + + /** * g_kdbus_finalize: * @@ -134,6 +240,9 @@ g_kdbus_finalize (GObject *object) if (kdbus->priv->fd != -1 && !kdbus->priv->closed) _g_kdbus_close (kdbus, NULL); + g_string_free (kdbus->priv->msg_sender, TRUE); + g_string_free (kdbus->priv->msg_destination, TRUE); + if (G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (*G_OBJECT_CLASS (g_kdbus_parent_class)->finalize) (object); } @@ -179,10 +288,17 @@ g_kdbus_init (GKdbus *kdbus) kdbus->priv->unique_name = NULL; kdbus->priv->kdbus_buffer = NULL; + kdbus->priv->kdbus_msg_items = NULL; + + kdbus->priv->msg_sender = g_string_new (NULL); + kdbus->priv->msg_destination = g_string_new (NULL); kdbus->priv->flags = 0; /* KDBUS_HELLO_ACCEPT_FD */ kdbus->priv->attach_flags_send = _KDBUS_ATTACH_ALL; kdbus->priv->attach_flags_recv = _KDBUS_ATTACH_ALL; + + kdbus->priv->fds = NULL; + kdbus->priv->num_fds = 0; } @@ -288,7 +404,6 @@ kdbus_source_dispatch (GSource *source, if (kdbus->priv->timeout) kdbus_source->timeout_time = g_get_monotonic_time () + kdbus->priv->timeout * 1000000; - else kdbus_source->timeout_time = 0; @@ -609,11 +724,15 @@ _g_kdbus_Hello (GIOStream *stream, kdbus->priv->unique_id = hello->id; asprintf(&kdbus->priv->unique_name, ":1.%llu", (unsigned long long) hello->id); + /* read bloom filters parameters */ + kdbus->priv->bloom_size = (gsize) hello->bloom.size; + kdbus->priv->bloom_n_hash = (guint) hello->bloom.n_hash; + return g_variant_new ("(s)", kdbus->priv->unique_name); } -/* +/** * _g_kdbus_RequestName: * */ @@ -697,7 +816,7 @@ _g_kdbus_RequestName (GDBusConnection *connection, } -/* +/** * _g_kdbus_ReleaseName: * */ @@ -1198,7 +1317,7 @@ _g_kdbus_GetConnectionUnixUser (GDBusConnection *connection, } -/* +/** * _g_kdbus_match_remove: * */ @@ -1221,7 +1340,7 @@ _g_kdbus_match_remove (GDBusConnection *connection, } -/* +/** * _g_kdbus_subscribe_name_acquired: * */ @@ -1296,7 +1415,7 @@ _g_kdbus_subscribe_name_owner_changed (GDBusConnection *connection, } -/* +/** * _g_kdbus_subscribe_name_acquired: * */ @@ -1341,7 +1460,7 @@ _g_kdbus_subscribe_name_acquired (GDBusConnection *connection, } -/* +/** * _g_kdbus_subscribe_name_lost: * */ @@ -1386,7 +1505,7 @@ _g_kdbus_subscribe_name_lost (GDBusConnection *connection, } -/* +/** * _g_kdbus_unsubscribe_name_acquired: * */ @@ -1400,7 +1519,7 @@ _g_kdbus_unsubscribe_name_acquired (GDBusConnection *connection) } -/* +/** * _g_kdbus_unsubscribe_name_lost: * */ @@ -1415,9 +1534,334 @@ _g_kdbus_unsubscribe_name_lost (GDBusConnection *connection) /** -* g_kdbus_decode_kernel_msg: -* -*/ + * _g_kdbus_release_msg: + * + */ +void +_g_kdbus_release_kmsg (GKdbus *kdbus) +{ + struct kdbus_item *item = NULL; + GSList *iterator = NULL; + guint64 offset; + + offset = (guint8 *)kdbus->priv->kmsg - (guint8 *)kdbus->priv->kdbus_buffer; + ioctl(kdbus->priv->fd, KDBUS_CMD_FREE, &offset); + + for (iterator = kdbus->priv->kdbus_msg_items; iterator; iterator = iterator->next) + g_free ((msg_part*)iterator->data); + + g_slist_free (kdbus->priv->kdbus_msg_items); + kdbus->priv->kdbus_msg_items = NULL; + + KDBUS_ITEM_FOREACH (item, kdbus->priv->kmsg, items) + { + if (item->type == KDBUS_ITEM_PAYLOAD_MEMFD) + close(item->memfd.fd); + else if (item->type == KDBUS_ITEM_FDS) + { + gint i; + gint num_fds = (item->size - G_STRUCT_OFFSET(struct kdbus_item, fds)) / sizeof(int); + + for (i = 0; i < num_fds; i++) + close(item->fds[i]); + } + } +} + + +/** + * g_kdbus_append_payload_vec: + * + */ +static void +g_kdbus_append_payload_vec (struct kdbus_item **item, + const void *data_ptr, + gssize size) +{ + *item = KDBUS_ALIGN8_PTR(*item); + (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, vec) + sizeof(struct kdbus_vec); + (*item)->type = KDBUS_ITEM_PAYLOAD_VEC; + (*item)->vec.address = (guint64)((guintptr)data_ptr); + (*item)->vec.size = size; + *item = KDBUS_ITEM_NEXT(*item); +} + + +/** + * g_kdbus_append_payload_destiantion: + * + */ +static void +g_kdbus_append_destination (struct kdbus_item **item, + const gchar *destination, + gsize size) +{ + *item = KDBUS_ALIGN8_PTR(*item); + (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, str) + size + 1; + (*item)->type = KDBUS_ITEM_DST_NAME; + memcpy ((*item)->str, destination, size+1); + *item = KDBUS_ITEM_NEXT(*item); +} + + +/** + * g_kdbus_append_payload_bloom: + * + */ +static struct kdbus_bloom_filter * +g_kdbus_append_bloom (struct kdbus_item **item, + gsize size) +{ + struct kdbus_item *bloom_item; + + bloom_item = KDBUS_ALIGN8_PTR(*item); + bloom_item->size = G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) + + G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) + + size; + + bloom_item->type = KDBUS_ITEM_BLOOM_FILTER; + + *item = KDBUS_ITEM_NEXT(bloom_item); + return &bloom_item->bloom_filter; +} + + +/** + * g_kdbus_append_fds: + * + */ +static void +g_kdbus_append_fds (struct kdbus_item **item, + GUnixFDList *fd_list) +{ + *item = KDBUS_ALIGN8_PTR(*item); + (*item)->size = G_STRUCT_OFFSET (struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list); + (*item)->type = KDBUS_ITEM_FDS; + memcpy ((*item)->fds, g_unix_fd_list_peek_fds(fd_list, NULL), sizeof(int) * g_unix_fd_list_get_length(fd_list)); + + *item = KDBUS_ITEM_NEXT(*item); +} + + +/** + * _g_kdbus_attach_fds_to_msg: + * + */ +void +_g_kdbus_attach_fds_to_msg (GKdbus *kdbus, + GUnixFDList **fd_list) +{ + if ((kdbus->priv->fds != NULL) && (kdbus->priv->num_fds > 0)) + { + gint n; + + if (*fd_list == NULL) + *fd_list = g_unix_fd_list_new(); + + for (n = 0; n < kdbus->priv->num_fds; n++) + { + g_unix_fd_list_append (*fd_list, kdbus->priv->fds[n], NULL); + (void) g_close (kdbus->priv->fds[n], NULL); + } + + g_free (kdbus->priv->fds); + kdbus->priv->fds = NULL; + kdbus->priv->num_fds = 0; + } +} + +/** + * g_kdbus_bloom_add_data: + * Based on bus-bloom.c from systemd + * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c + */ +static void +g_kdbus_bloom_add_data (GKdbus *kdbus, + guint64 bloom_data [], + const void *data, + gsize n) +{ + guint8 hash[8]; + guint64 bit_num; + guint bytes_num = 0; + guint cnt_1, cnt_2; + + guint c = 0; + guint64 p = 0; + + bit_num = kdbus->priv->bloom_size * 8; + + if (bit_num > 1) + bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8; + + for (cnt_1 = 0; cnt_1 < (kdbus->priv->bloom_n_hash); cnt_1++) + { + for (cnt_2 = 0; cnt_2 < bytes_num; cnt_2++) + { + if (c <= 0) + { + g_siphash24(hash, data, n, hash_keys[cnt_1++]); + c += 8; + } + + p = (p << 8ULL) | (guint64) hash[8 - c]; + c--; + } + + p &= bit_num - 1; + bloom_data[p >> 6] |= 1ULL << (p & 63); + } +} + + +/** + * g_kdbus_bloom_add_pair: + * + */ +static void +g_kdbus_bloom_add_pair (GKdbus *kdbus, + guint64 bloom_data [], + const gchar *parameter, + const gchar *value) +{ + GString *data = g_string_new (NULL); + + g_string_printf (data,"%s:%s",parameter,value); + g_kdbus_bloom_add_data(kdbus, bloom_data, data->str, data->len); + g_string_free (data, TRUE); +} + + +/** + * g_kdbus_bloom_add_prefixes: + * + */ +static void +g_kdbus_bloom_add_prefixes (GKdbus *kdbus, + guint64 bloom_data [], + const gchar *parameter, + const gchar *value, + gchar separator) +{ + GString *data = g_string_new (NULL); + + g_string_printf (data,"%s:%s",parameter,value); + + for (;;) + { + gchar *last_sep; + last_sep = strrchr(data->str, separator); + if (!last_sep || last_sep == data->str) + break; + + *last_sep = 0; + g_kdbus_bloom_add_data(kdbus, bloom_data, data->str, last_sep-(data->str)); + } + g_string_free (data, TRUE); +} + + +/** + * g_kdbus_setup_bloom: + * Based on bus-bloom.c from systemd + * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c + */ +static void +g_kdbus_setup_bloom (GKdbus *kdbus, + GDBusMessage *dbus_msg, + struct kdbus_bloom_filter *bloom_filter) +{ + GVariant *body; + GVariantIter iter; + GVariant *child; + + const gchar *message_type; + const gchar *interface; + const gchar *member; + const gchar *path; + + void *bloom_data; + gint cnt = 0; + + body = g_dbus_message_get_body (dbus_msg); + message_type = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, g_dbus_message_get_message_type (dbus_msg)); + interface = g_dbus_message_get_interface (dbus_msg); + member = g_dbus_message_get_member (dbus_msg); + path = g_dbus_message_get_path (dbus_msg); + + bloom_data = bloom_filter->data; + memset (bloom_data, 0, kdbus->priv->bloom_size); + bloom_filter->generation = 0; + + g_kdbus_bloom_add_pair(kdbus, bloom_data, "message-type", message_type); + + if (interface) + g_kdbus_bloom_add_pair(kdbus, bloom_data, "interface", interface); + + if (member) + g_kdbus_bloom_add_pair(kdbus, bloom_data, "member", member); + + if (path) + { + g_kdbus_bloom_add_pair(kdbus, bloom_data, "path", path); + g_kdbus_bloom_add_pair(kdbus, bloom_data, "path-slash-prefix", path); + g_kdbus_bloom_add_prefixes(kdbus, bloom_data, "path-slash-prefix", path, '/'); + } + + if (body != NULL) + { + g_variant_iter_init (&iter, body); + while ((child = g_variant_iter_next_value (&iter))) + { + gchar buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")]; + gchar *child_string; + gchar *e; + + /* Is it necessary? */ + //if (g_variant_is_container (child)) + // iterate_container_recursive (child); + + if (!(g_variant_is_of_type (child, G_VARIANT_TYPE_STRING)) && + !(g_variant_is_of_type (child, G_VARIANT_TYPE_OBJECT_PATH)) && + !(g_variant_is_of_type (child, G_VARIANT_TYPE_SIGNATURE))) + break; + + child_string = g_variant_dup_string (child, NULL); + + e = stpcpy(buf, "arg"); + if (cnt < 10) + *(e++) = '0' + (char) cnt; + else + { + *(e++) = '0' + (char) (cnt / 10); + *(e++) = '0' + (char) (cnt % 10); + } + + *e = 0; + g_kdbus_bloom_add_pair(kdbus, bloom_data, buf, child_string); + + strcpy(e, "-dot-prefix"); + g_kdbus_bloom_add_prefixes(kdbus, bloom_data, buf, child_string, '.'); + + strcpy(e, "-slash-prefix"); + g_kdbus_bloom_add_prefixes(kdbus, bloom_data, buf, child_string, '/'); + + g_free (child_string); + g_variant_unref (child); + cnt++; + } + } +} + + +/* + * TODO: g_kdbus_NameOwnerChanged_generate, g_kdbus_KernelMethodError_generate + */ + +/** + * g_kdbus_decode_kernel_msg: + * + */ static gssize g_kdbus_decode_kernel_msg (GKdbus *kdbus) { @@ -1448,7 +1892,7 @@ g_kdbus_decode_kernel_msg (GKdbus *kdbus) } } -#if 0 + /* Override information from the user header with data from the kernel */ g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus"); @@ -1460,13 +1904,120 @@ g_kdbus_decode_kernel_msg (GKdbus *kdbus) g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id); else g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id); -#endif return size; } /** + * g_kdbus_decode_dbus_msg: + * + */ +static gssize +g_kdbus_decode_dbus_msg (GKdbus *kdbus) +{ + struct kdbus_item *item; + gchar *msg_ptr; + gssize ret_size = 0; + gssize data_size = 0; + const gchar *destination = NULL; + + KDBUS_ITEM_FOREACH(item, kdbus->priv->kmsg, items) + { + if (item->size <= KDBUS_ITEM_HEADER_SIZE) + g_error("[KDBUS] %llu bytes - invalid data record\n", item->size); + + data_size = item->size - KDBUS_ITEM_HEADER_SIZE; + + switch (item->type) + { + + /* KDBUS_ITEM_DST_NAME */ + case KDBUS_ITEM_DST_NAME: + destination = item->str; + break; + + /* KDBUS_ITEM_PALOAD_OFF */ + case KDBUS_ITEM_PAYLOAD_OFF: + + msg_ptr = (gchar*) kdbus->priv->kmsg + item->vec.offset; + g_kdbus_add_msg_part (kdbus, msg_ptr, item->vec.size); + ret_size += item->vec.size; + + break; + + /* KDBUS_ITEM_PAYLOAD_MEMFD */ + case KDBUS_ITEM_PAYLOAD_MEMFD: + + msg_ptr = mmap(NULL, item->memfd.size, PROT_READ, MAP_SHARED, item->memfd.fd, 0); + + if (msg_ptr == MAP_FAILED) + { + g_print ("mmap() fd=%i failed:%m", item->memfd.fd); + break; + } + + g_kdbus_add_msg_part (kdbus, msg_ptr, item->memfd.size); + ret_size += item->memfd.size; + + break; + + /* KDBUS_ITEM_FDS */ + case KDBUS_ITEM_FDS: + + kdbus->priv->num_fds = data_size / sizeof(int); + kdbus->priv->fds = g_malloc0 (sizeof(int) * kdbus->priv->num_fds); + memcpy(kdbus->priv->fds, item->fds, sizeof(int) * kdbus->priv->num_fds); + + break; + + /* All of the following items, like CMDLINE, + CGROUP, etc. need some GDBUS API extensions and + should be implemented in the future */ + case KDBUS_ITEM_CREDS: + case KDBUS_ITEM_TIMESTAMP: + case KDBUS_ITEM_PID_COMM: + case KDBUS_ITEM_TID_COMM: + case KDBUS_ITEM_EXE: + case KDBUS_ITEM_CMDLINE: + case KDBUS_ITEM_CGROUP: + case KDBUS_ITEM_AUDIT: + case KDBUS_ITEM_CAPS: + case KDBUS_ITEM_SECLABEL: + case KDBUS_ITEM_CONN_DESCRIPTION: + case KDBUS_ITEM_AUXGROUPS: + case KDBUS_ITEM_OWNED_NAME: + case KDBUS_ITEM_NAME: + break; + + default: + g_error ("[KDBUS] DBUS_PAYLOAD: Unknown filed - %lld", item->type); + break; + } + } + + /* Override information from the user header with data from the kernel */ + + if (kdbus->priv->kmsg->src_id == KDBUS_SRC_ID_KERNEL) + g_string_printf (kdbus->priv->msg_sender, "org.freedesktop.DBus"); + else + g_string_printf (kdbus->priv->msg_sender, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->src_id); + + if (destination) + g_string_printf (kdbus->priv->msg_destination, "%s", destination); + else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_BROADCAST) + /* for broadcast messages we don't have to set destination */ + ; + else if (kdbus->priv->kmsg->dst_id == KDBUS_DST_ID_NAME) + g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->unique_id); + else + g_string_printf (kdbus->priv->msg_destination, ":1.%" G_GUINT64_FORMAT, (guint64) kdbus->priv->kmsg->dst_id); + + return ret_size; +} + + +/** * _g_kdbus_receive: * */ @@ -1497,7 +2048,7 @@ again: kdbus->priv->kmsg = (struct kdbus_msg *)((guint8 *)kdbus->priv->kdbus_buffer + recv.offset); if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_DBUS) - g_error ("Received standard dbus message - not supported yet"); + size = g_kdbus_decode_dbus_msg (kdbus); else if (kdbus->priv->kmsg->payload_type == KDBUS_PAYLOAD_KERNEL) size = g_kdbus_decode_kernel_msg (kdbus); else @@ -1511,3 +2062,176 @@ again: return size; } + + +/** + * _g_kdbus_send: + * Returns: size of data sent or -1 when error + */ +gsize +_g_kdbus_send (GDBusWorker *worker, + GKdbus *kdbus, + GDBusMessage *dbus_msg, + gchar *blob, + gsize blob_size, + GUnixFDList *fd_list, + GCancellable *cancellable, + GError **error) +{ + struct kdbus_msg* kmsg; + struct kdbus_item *item; + guint64 kmsg_size = 0; + const gchar *name; + guint64 dst_id = KDBUS_DST_ID_BROADCAST; + + g_return_val_if_fail (G_IS_KDBUS (kdbus), -1); + + if (g_cancellable_set_error_if_cancelled (cancellable, error)) + return -1; + + /* + * check destination + */ + if ((name = g_dbus_message_get_destination(dbus_msg))) + { + dst_id = KDBUS_DST_ID_NAME; + if ((name[0] == ':') && (name[1] == '1') && (name[2] == '.')) + { + dst_id = strtoull(&name[3], NULL, 10); + name=NULL; + } + } + + /* + * check and set message size + */ + kmsg_size = sizeof(struct kdbus_msg); + kmsg_size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_vec)); /* header + body */ + + if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0) + kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, fds) + sizeof(int) * g_unix_fd_list_get_length(fd_list)); + + if (name) + kmsg_size += KDBUS_ITEM_SIZE(strlen(name) + 1); + else if (dst_id == KDBUS_DST_ID_BROADCAST) + kmsg_size += KDBUS_ALIGN8(G_STRUCT_OFFSET(struct kdbus_item, bloom_filter) + + G_STRUCT_OFFSET(struct kdbus_bloom_filter, data) + + kdbus->priv->bloom_size); + + kmsg = malloc(kmsg_size); + if (!kmsg) + g_error ("[KDBUS] kmsg malloc error"); + + + /* + * set message header + */ + memset(kmsg, 0, kmsg_size); + kmsg->size = kmsg_size; + kmsg->payload_type = KDBUS_PAYLOAD_DBUS; + kmsg->dst_id = name ? 0 : dst_id; + kmsg->src_id = kdbus->priv->unique_id; + kmsg->cookie = g_dbus_message_get_serial(dbus_msg); + kmsg->priority = 0; + + + /* + * set message flags + */ + kmsg->flags = ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) | + ((g_dbus_message_get_flags (dbus_msg) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0); + + if ((kmsg->flags) & KDBUS_MSG_FLAGS_EXPECT_REPLY) + kmsg->timeout_ns = 2000000000; + else + kmsg->cookie_reply = g_dbus_message_get_reply_serial(dbus_msg); + + + /* + * append payload + */ + item = kmsg->items; + + /* if we don't use memfd, send whole message as a PAYLOAD_VEC item */ + g_kdbus_append_payload_vec (&item, blob, blob_size); + + + /* + * append destination or bloom filters + */ + if (name) + g_kdbus_append_destination (&item, name, strlen(name)); + else if (dst_id == KDBUS_DST_ID_BROADCAST) + { + struct kdbus_bloom_filter *bloom_filter; + + bloom_filter = g_kdbus_append_bloom (&item, kdbus->priv->bloom_size); + g_kdbus_setup_bloom (kdbus, dbus_msg, bloom_filter); + } + + /* + * append fds if any + */ + if (fd_list != NULL && g_unix_fd_list_get_length (fd_list) > 0) + g_kdbus_append_fds (&item, fd_list); + + + /* + * send message + */ +//again: + if (ioctl(kdbus->priv->fd, KDBUS_CMD_MSG_SEND, kmsg)) + { +/* + GString *error_name; + error_name = g_string_new (NULL); + + if(errno == EINTR) + { + g_string_free (error_name,TRUE); + goto again; + } + else if (errno == ENXIO) + { + g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg)); + g_kdbus_generate_local_error (worker, + dbus_msg, + g_variant_new ("(s)",error_name->str), + G_DBUS_ERROR_SERVICE_UNKNOWN); + g_string_free (error_name,TRUE); + return 0; + } + else if ((errno == ESRCH) || (errno == EADDRNOTAVAIL)) + { + if (kmsg->flags & KDBUS_MSG_FLAGS_NO_AUTO_START) + { + g_string_printf (error_name, "Name %s does not exist", g_dbus_message_get_destination(dbus_msg)); + g_kdbus_generate_local_error (worker, + dbus_msg, + g_variant_new ("(s)",error_name->str), + G_DBUS_ERROR_SERVICE_UNKNOWN); + g_string_free (error_name,TRUE); + return 0; + } + else + { + g_string_printf (error_name, "The name %s was not provided by any .service files", g_dbus_message_get_destination(dbus_msg)); + g_kdbus_generate_local_error (worker, + dbus_msg, + g_variant_new ("(s)",error_name->str), + G_DBUS_ERROR_SERVICE_UNKNOWN); + g_string_free (error_name,TRUE); + return 0; + } + } + + g_print ("[KDBUS] ioctl error sending kdbus message:%d (%m)\n",errno); + g_set_error (error, G_IO_ERROR, g_io_error_from_errno(errno), _("Error sending message - KDBUS_CMD_MSG_SEND error")); +*/ + g_error ("IOCTL SEND: %d\n",errno); + return -1; + } + + free(kmsg); + return blob_size; +} diff --git a/gio/gkdbus.h b/gio/gkdbus.h index 82386dc..7ba6f35 100644 --- a/gio/gkdbus.h +++ b/gio/gkdbus.h @@ -55,6 +55,12 @@ struct _GKdbus GKdbusPrivate *priv; }; +typedef struct +{ + gchar *data; + gsize size; +} msg_part; + GType _g_kdbus_get_type (void) G_GNUC_CONST; gboolean _g_kdbus_open (GKdbus *kdbus, @@ -115,10 +121,31 @@ void _g_kdbus_unsubscribe_name_acquired (GDB void _g_kdbus_unsubscribe_name_lost (GDBusConnection *connection); +gsize _g_kdbus_send (GDBusWorker *worker, + GKdbus *kdbus, + GDBusMessage *dbus_msg, + gchar *blob, + gsize blob_size, + GUnixFDList *fd_list, + GCancellable *cancellable, + GError **error); + gssize _g_kdbus_receive (GKdbus *kdbus, GCancellable *cancellable, GError **error); +GSList * _g_kdbus_get_last_msg_items (GKdbus *kdbus); + +gchar * _g_kdbus_get_last_msg_sender (GKdbus *kdbus); + +gchar * _g_kdbus_get_last_msg_destination (GKdbus *kdbus); + +gchar * _g_kdbus_hexdump_all_items (GSList *kdbus_msg_items); + +void _g_kdbus_release_kmsg (GKdbus *kdbus); + +void _g_kdbus_attach_fds_to_msg (GKdbus *kdbus, + GUnixFDList **fd_list); G_END_DECLS #endif /* __G_KDBUS_H__ */ -- 2.7.4