Bug 19567 - Make marshaling code usable without DBusConnection
authorWilliam Lachance <wrlach@gmail.com>
Tue, 21 Apr 2009 17:51:46 +0000 (13:51 -0400)
committerColin Walters <walters@verbum.org>
Wed, 6 May 2009 16:51:18 +0000 (12:51 -0400)
Some projects want to reuse the DBus message format, without
actually going through a DBusConnection.  This set of changes
makes a few functions from DBusMessage public, and adds a new
function to determine the number of bytes needed to demarshal
a message.

Signed-off-by: Colin Walters <walters@verbum.org>
dbus/dbus-connection.c
dbus/dbus-message-factory.c
dbus/dbus-message-internal.h
dbus/dbus-message-util.c
dbus/dbus-message.c
dbus/dbus-message.h
dbus/dbus-transport-socket.c

index d44d728..947c0af 100644 (file)
@@ -1950,7 +1950,7 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection       *con
   if (dbus_message_get_serial (message) == 0)
     {
       serial = _dbus_connection_get_next_client_serial (connection);
-      _dbus_message_set_serial (message, serial);
+      dbus_message_set_serial (message, serial);
       if (client_serial)
         *client_serial = serial;
     }
@@ -1963,7 +1963,7 @@ _dbus_connection_send_preallocated_unlocked_no_update (DBusConnection       *con
   _dbus_verbose ("Message %p serial is %u\n",
                  message, dbus_message_get_serial (message));
   
-  _dbus_message_lock (message);
+  dbus_message_lock (message);
 
   /* Now we need to run an iteration to hopefully just write the messages
    * out immediately, and otherwise get them queued up
@@ -3208,7 +3208,7 @@ dbus_connection_send_with_reply (DBusConnection     *connection,
   if (serial == 0)
     {
       serial = _dbus_connection_get_next_client_serial (connection);
-      _dbus_message_set_serial (message, serial);
+      dbus_message_set_serial (message, serial);
     }
 
   if (!_dbus_pending_call_set_timeout_error_unlocked (pending, message, serial))
index ceffc76..8550ee8 100644 (file)
@@ -222,8 +222,8 @@ generate_from_message (DBusString            *data,
                        DBusValidity          *expected_validity,
                        DBusMessage           *message)
 {
-  _dbus_message_set_serial (message, 1);
-  _dbus_message_lock (message);
+  dbus_message_set_serial (message, 1);
+  dbus_message_lock (message);
 
   *expected_validity = DBUS_VALID;
   
index 7661585..2e995b4 100644 (file)
@@ -37,8 +37,6 @@ void _dbus_message_get_network_data  (DBusMessage       *message,
 
 void        _dbus_message_lock                  (DBusMessage  *message);
 void        _dbus_message_unlock                (DBusMessage  *message);
-void        _dbus_message_set_serial            (DBusMessage  *message,
-                                                 dbus_uint32_t serial);
 dbus_bool_t _dbus_message_add_size_counter      (DBusMessage  *message,
                                                  DBusCounter  *counter);
 void        _dbus_message_add_size_counter_link (DBusMessage  *message,
index 0fa010c..46cbe4e 100644 (file)
@@ -949,7 +949,7 @@ _dbus_message_test (const char *test_data_dir)
                                              "TestMethod"));
   _dbus_assert (strcmp (dbus_message_get_path (message),
                         "/org/freedesktop/TestPath") == 0);
-  _dbus_message_set_serial (message, 1234);
+  dbus_message_set_serial (message, 1234);
 
   /* string length including nul byte not a multiple of 4 */
   if (!dbus_message_set_sender (message, "org.foo.bar1"))
@@ -1041,7 +1041,7 @@ _dbus_message_test (const char *test_data_dir)
                                           "/org/freedesktop/TestPath",
                                           "Foo.TestInterface",
                                           "TestMethod");
-  _dbus_message_set_serial (message, 1);
+  dbus_message_set_serial (message, 1);
   dbus_message_set_reply_serial (message, 5678);
 
   v_INT16 = -0x123;
@@ -1172,7 +1172,7 @@ _dbus_message_test (const char *test_data_dir)
   dbus_message_unref (copy);
 
   /* Message loader test */
-  _dbus_message_lock (message);
+  dbus_message_lock (message);
   loader = _dbus_message_loader_new ();
   
   /* check ref/unref */
@@ -1226,6 +1226,7 @@ _dbus_message_test (const char *test_data_dir)
       DBusError error = DBUS_ERROR_INIT;
       char *marshalled = NULL;
       int len = 0;
+      char garbage_header[DBUS_MINIMUM_HEADER_SIZE] = "xxx";
 
       if (!dbus_message_marshal (message, &marshalled, &len))
         _dbus_assert_not_reached ("failed to marshal message");
@@ -1233,6 +1234,7 @@ _dbus_message_test (const char *test_data_dir)
       _dbus_assert (len != 0);
       _dbus_assert (marshalled != NULL);
 
+      _dbus_assert (dbus_message_demarshal_bytes_needed (marshalled, len) == len);
       message2 = dbus_message_demarshal (marshalled, len, &error);
 
       _dbus_assert (message2 != NULL);
@@ -1255,6 +1257,14 @@ _dbus_message_test (const char *test_data_dir)
       _dbus_assert (message2 == NULL);
       _dbus_assert (dbus_error_is_set (&error));
       dbus_error_free (&error);
+
+      /* Bytes needed to demarshal empty message: 0 (more) */
+
+      _dbus_assert (dbus_message_demarshal_bytes_needed ("", 0) == 0);
+      
+      /* Bytes needed to demarshal invalid message: -1 (error). */
+
+      _dbus_assert (dbus_message_demarshal_bytes_needed (garbage_header, DBUS_MINIMUM_HEADER_SIZE) == -1);
     }
 
   dbus_message_unref (message);
index e2c4771..edae425 100644 (file)
@@ -142,7 +142,7 @@ _dbus_message_byteswap (DBusMessage *message)
  * Gets the data to be sent over the network for this message.
  * The header and then the body should be written out.
  * This function is guaranteed to always return the same
- * data once a message is locked (with _dbus_message_lock()).
+ * data once a message is locked (with dbus_message_lock()).
  *
  * @param message the message.
  * @param header return location for message header data.
@@ -163,16 +163,19 @@ _dbus_message_get_network_data (DBusMessage          *message,
  * Sets the serial number of a message.
  * This can only be done once on a message.
  *
+ * DBusConnection will automatically set the serial to an appropriate value 
+ * when the message is sent; this function is only needed when encapsulating 
+ * messages in another protocol, or otherwise bypassing DBusConnection.
+ *
  * @param message the message
  * @param serial the serial
  */
-void
-_dbus_message_set_serial (DBusMessage   *message,
-                          dbus_uint32_t  serial)
+void 
+dbus_message_set_serial (DBusMessage   *message,
+                         dbus_uint32_t  serial)
 {
-  _dbus_assert (message != NULL);
-  _dbus_assert (!message->locked);
-  _dbus_assert (dbus_message_get_serial (message) == 0);
+  _dbus_return_if_fail (message != NULL);
+  _dbus_return_if_fail (!message->locked);
 
   _dbus_header_set_serial (&message->header, serial);
 }
@@ -277,12 +280,13 @@ _dbus_message_remove_size_counter (DBusMessage  *message,
  * reference to a message in the outgoing queue and change it
  * underneath us. Messages are locked when they enter the outgoing
  * queue (dbus_connection_send_message()), and the library complains
- * if the message is modified while locked.
+ * if the message is modified while locked. This function may also 
+ * called externally, for applications wrapping D-Bus in another protocol.
  *
  * @param message the message to lock.
  */
 void
-_dbus_message_lock (DBusMessage  *message)
+dbus_message_lock (DBusMessage  *message)
 {
   if (!message->locked)
     {
@@ -3941,7 +3945,7 @@ dbus_message_marshal (DBusMessage  *msg,
   _dbus_return_val_if_fail (msg != NULL, FALSE);
   _dbus_return_val_if_fail (marshalled_data_p != NULL, FALSE);
   _dbus_return_val_if_fail (len_p != NULL, FALSE);
-
+  
   if (!_dbus_string_init (&tmp))
     return FALSE;
 
@@ -4023,6 +4027,57 @@ dbus_message_demarshal (const char *str,
   return NULL;
 }
 
+/**
+ * Returns the number of bytes required to be in the buffer to demarshal a
+ * D-Bus message.
+ *
+ * Generally, this function is only useful for encapsulating D-Bus messages in
+ * a different protocol.
+ *
+ * @param str data to be marshalled
+ * @param len the length of str
+ * @param error the location to save errors to
+ * @returns -1 if there was no valid data to be demarshalled, 0 if there wasn't enough data to determine how much should be demarshalled. Otherwise returns the number of bytes to be demarshalled
+ * 
+ */
+int 
+dbus_message_demarshal_bytes_needed(const char *buf, 
+                                    int         len)
+{
+  DBusString str;
+  int byte_order, fields_array_len, header_len, body_len;
+  DBusValidity validity = DBUS_VALID;
+  int have_message;
+
+  if (!buf || len < DBUS_MINIMUM_HEADER_SIZE)
+    return 0;
+
+  if (len > DBUS_MAXIMUM_MESSAGE_LENGTH)
+    len = DBUS_MAXIMUM_MESSAGE_LENGTH;
+  _dbus_string_init_const_len (&str, buf, len);
+  
+  validity = DBUS_VALID;
+  have_message
+    = _dbus_header_have_message_untrusted(DBUS_MAXIMUM_MESSAGE_LENGTH,
+                                          &validity, &byte_order,
+                                          &fields_array_len,
+                                          &header_len,
+                                          &body_len,
+                                          &str, 0,
+                                          len);
+  _dbus_string_free (&str);
+
+  if (validity == DBUS_VALID)
+    {
+      _dbus_assert(have_message);
+      return header_len + body_len;
+    }
+  else
+    {
+      return -1; /* broken! */
+    }
+}
+
 /** @} */
 
 /* tests in dbus-message-util.c */
index 1bf7d0c..2e29fef 100644 (file)
@@ -131,6 +131,8 @@ dbus_bool_t   dbus_message_has_sender       (DBusMessage   *message,
 dbus_bool_t   dbus_message_has_signature    (DBusMessage   *message,
                                              const char    *signature);
 dbus_uint32_t dbus_message_get_serial       (DBusMessage   *message);
+void          dbus_message_set_serial       (DBusMessage   *message, 
+                                             dbus_uint32_t  serial);
 dbus_bool_t   dbus_message_set_reply_serial (DBusMessage   *message,
                                              dbus_uint32_t  reply_serial);
 dbus_uint32_t dbus_message_get_reply_serial (DBusMessage   *message);
@@ -196,6 +198,7 @@ dbus_bool_t dbus_message_iter_open_container     (DBusMessageIter *iter,
 dbus_bool_t dbus_message_iter_close_container    (DBusMessageIter *iter,
                                                   DBusMessageIter *sub);
 
+void dbus_message_lock    (DBusMessage  *message);
 
 dbus_bool_t  dbus_set_error_from_message  (DBusError    *error,
                                            DBusMessage  *message);
@@ -220,6 +223,9 @@ DBusMessage* dbus_message_demarshal (const char *str,
                                      int         len,
                                      DBusError  *error);
 
+int          dbus_message_demarshal_bytes_needed (const char *str, 
+                                                  int len);
+
 /** @} */
 
 DBUS_END_DECLS
index 10b671c..6d7c89c 100644 (file)
@@ -537,7 +537,7 @@ do_writing (DBusTransport *transport)
       
       message = _dbus_connection_get_message_to_send (transport->connection);
       _dbus_assert (message != NULL);
-      _dbus_message_lock (message);
+      dbus_message_lock (message);
 
 #if 0
       _dbus_verbose ("writing message %p\n", message);