[kdbus][wip] Import code from tizen.org repo
authorLukasz Skalski <l.skalski@samsung.com>
Fri, 21 Nov 2014 16:23:28 +0000 (17:23 +0100)
committerMaciej Wereski <m.wereski@partner.samsung.com>
Fri, 10 Jul 2015 09:47:44 +0000 (11:47 +0200)
gio/gdbusconnection.c
gio/gdbusmessage.c
gio/gdbusmessage.h
gio/gdbusprivate.c
gio/gkdbus.c
gio/gkdbus.h

index 55c2156..d9ee982 100644 (file)
@@ -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,
index 766609e..bfe91e6 100644 (file)
@@ -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
     {
index f791889..8f9b25e 100644 (file)
@@ -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__ */
index 91feb41..e3f1cda 100644 (file)
@@ -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,
index e612b8f..fabeba0 100644 (file)
@@ -34,6 +34,7 @@
 #include <sys/mman.h>
 #include <sys/ioctl.h>
 #include <stdio.h>
+#include <stdint.h>
 
 #ifdef HAVE_SYS_FILIO_H
 # include <sys/filio.h>
 #include <sys/uio.h>
 #endif
 
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+
+#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;
+}
index 82386dc..7ba6f35 100644 (file)
@@ -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__ */