2003-01-07 Anders Carlsson <andersca@codefactory.se>
authorAnders Carlsson <andersca@codefactory.se>
Tue, 7 Jan 2003 20:18:23 +0000 (20:18 +0000)
committerAnders Carlsson <andersca@codefactory.se>
Tue, 7 Jan 2003 20:18:23 +0000 (20:18 +0000)
* dbus/dbus-connection-internal.h:
* dbus/dbus-connection.c: (_dbus_connection_new_for_transport),
(_dbus_connection_get_next_client_serial),
(dbus_connection_send_message):
* dbus/dbus-internals.h:
* dbus/dbus-marshal.c: (unpack_uint32), (dbus_unpack_int32),
(dbus_pack_int32), (_dbus_marshal_double), (_dbus_marshal_int32),
(_dbus_marshal_uint32), (_dbus_demarshal_double),
(_dbus_demarshal_int32), (_dbus_demarshal_uint32),
(_dbus_demarshal_string), (_dbus_marshal_get_field_end_pos),
(_dbus_verbose_bytes), (_dbus_marshal_test):
* dbus/dbus-marshal.h:
* dbus/dbus-message-internal.h:
* dbus/dbus-message.c: (_dbus_message_set_client_serial),
(dbus_message_write_header), (_dbus_message_lock),
(dbus_message_new), (dbus_message_ref), (dbus_message_unref),
(dbus_message_get_name), (dbus_message_append_int32),
(dbus_message_append_uint32), (dbus_message_append_double),
(dbus_message_append_string), (dbus_message_append_byte_array),
(dbus_message_get_fields_iter), (dbus_message_iter_ref),
(dbus_message_iter_unref), (dbus_message_iter_has_next),
(dbus_message_iter_next), (dbus_message_iter_get_field_type),
(dbus_message_iter_get_string), (dbus_message_iter_get_int32),
(dbus_message_iter_get_uint32), (dbus_message_iter_get_double),
(decode_header_data), (_dbus_message_loader_return_buffer),
(message_iter_test), (_dbus_message_test):
* dbus/dbus-message.h:
* dbus/dbus-protocol.h:
* dbus/dbus-test.c: (main):
* dbus/dbus-test.h:
* glib/test-dbus-glib.c: (message_handler), (main):
* test/echo-client.c: (main):
* test/watch.c: (check_messages):
Make messages sendable and receivable for real.

15 files changed:
ChangeLog
dbus/dbus-connection-internal.h
dbus/dbus-connection.c
dbus/dbus-internals.h
dbus/dbus-marshal.c
dbus/dbus-marshal.h
dbus/dbus-message-internal.h
dbus/dbus-message.c
dbus/dbus-message.h
dbus/dbus-protocol.h
dbus/dbus-test.c
dbus/dbus-test.h
glib/test-dbus-glib.c
test/echo-client.c
test/watch.c

index a73d3f3..7a01a8f 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,42 @@
 2003-01-07  Anders Carlsson  <andersca@codefactory.se>
 
+       * dbus/dbus-connection-internal.h:
+       * dbus/dbus-connection.c: (_dbus_connection_new_for_transport),
+       (_dbus_connection_get_next_client_serial),
+       (dbus_connection_send_message):
+       * dbus/dbus-internals.h:
+       * dbus/dbus-marshal.c: (unpack_uint32), (dbus_unpack_int32),
+       (dbus_pack_int32), (_dbus_marshal_double), (_dbus_marshal_int32),
+       (_dbus_marshal_uint32), (_dbus_demarshal_double),
+       (_dbus_demarshal_int32), (_dbus_demarshal_uint32),
+       (_dbus_demarshal_string), (_dbus_marshal_get_field_end_pos),
+       (_dbus_verbose_bytes), (_dbus_marshal_test):
+       * dbus/dbus-marshal.h:
+       * dbus/dbus-message-internal.h:
+       * dbus/dbus-message.c: (_dbus_message_set_client_serial),
+       (dbus_message_write_header), (_dbus_message_lock),
+       (dbus_message_new), (dbus_message_ref), (dbus_message_unref),
+       (dbus_message_get_name), (dbus_message_append_int32),
+       (dbus_message_append_uint32), (dbus_message_append_double),
+       (dbus_message_append_string), (dbus_message_append_byte_array),
+       (dbus_message_get_fields_iter), (dbus_message_iter_ref),
+       (dbus_message_iter_unref), (dbus_message_iter_has_next),
+       (dbus_message_iter_next), (dbus_message_iter_get_field_type),
+       (dbus_message_iter_get_string), (dbus_message_iter_get_int32),
+       (dbus_message_iter_get_uint32), (dbus_message_iter_get_double),
+       (decode_header_data), (_dbus_message_loader_return_buffer),
+       (message_iter_test), (_dbus_message_test):
+       * dbus/dbus-message.h:
+       * dbus/dbus-protocol.h:
+       * dbus/dbus-test.c: (main):
+       * dbus/dbus-test.h:
+       * glib/test-dbus-glib.c: (message_handler), (main):
+       * test/echo-client.c: (main):
+       * test/watch.c: (check_messages):
+       Make messages sendable and receivable for real.
+       
+2003-01-07  Anders Carlsson  <andersca@codefactory.se>
+
        * dbus/dbus-marshal.c: (_dbus_marshal_double),
        (_dbus_marshal_string), (_dbus_marshal_byte_array):
        * dbus/dbus-message.c: (dbus_message_append_int32),
index cf932dd..7a64874 100644 (file)
@@ -51,7 +51,6 @@ void            _dbus_connection_remove_watch           (DBusConnection *connect
                                                          DBusWatch      *watch);
 DBusConnection* _dbus_connection_new_for_transport      (DBusTransport  *transport);
 
-
 void            _dbus_connection_do_iteration           (DBusConnection *connection,
                                                          unsigned int    flags,
                                                          int             timeout_milliseconds);
index 66bd064..8efa001 100644 (file)
@@ -92,6 +92,8 @@ struct DBusConnection
   int handlers_serial;          /**< Increments when the handler table is changed. */
   DBusDataSlot *data_slots;        /**< Data slots */
   int           n_slots; /**< Slots allocated so far. */
+
+  int client_serial;            /**< Client serial. Increments each time a message is sent  */
 };
 
 static void _dbus_connection_free_data_slots (DBusConnection *connection);
@@ -330,6 +332,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
 
   connection->data_slots = NULL;
   connection->n_slots = 0;
+  connection->client_serial = 1;
   
   _dbus_transport_ref (transport);
   _dbus_transport_set_connection (transport, connection);
@@ -350,6 +353,19 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
   return NULL;
 }
 
+static dbus_int32_t
+_dbus_connection_get_next_client_serial (DBusConnection *connection)
+{
+  int serial;
+
+  serial = connection->client_serial++;
+
+  if (connection->client_serial < 0)
+    connection->client_serial = 1;
+  
+  return serial;
+}
+
 /**
  * Used to notify a connection when a DBusMessageHandler is
  * destroyed, so the connection can drop any reference
@@ -580,7 +596,8 @@ dbus_connection_send_message (DBusConnection *connection,
 
   _dbus_verbose ("Message %p added to outgoing queue, %d pending to send\n",
                  message, connection->n_outgoing);
-  
+
+  _dbus_message_set_client_serial (message, _dbus_connection_get_next_client_serial (connection));
   _dbus_message_lock (message);
   
   if (connection->n_outgoing == 1)
index 2f025c1..87dfbf1 100644 (file)
@@ -72,6 +72,23 @@ do {
 #define _DBUS_STRUCT_OFFSET(struct_type, member)       \
     ((long) ((unsigned char*) &((struct_type*) 0)->member))
 
+/* This alignment thing is from ORBit2 */
+/* Align a value upward to a boundary, expressed as a number of bytes.
+ * E.g. align to an 8-byte boundary with argument of 8.
+ */
+
+/*
+ *   (this + boundary - 1)
+ *          &
+ *    ~(boundary - 1)
+ */
+
+#define _DBUS_ALIGN_VALUE(this, boundary) \
+  (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
+
+#define _DBUS_ALIGN_ADDRESS(this, boundary) \
+  ((void*)_DBUS_ALIGN_VALUE(this, boundary))
+
 char* _dbus_strdup (const char *str);
 
 #define _DBUS_INT_MIN  (-_DBUS_INT_MAX - 1)
index 49d06a7..7c85ded 100644 (file)
 #define DBUS_UINT32_FROM_BE(val) (DBUS_UINT32_TO_BE (val))
 
 
-/* This alignment thing is from ORBit2 */
-/* Align a value upward to a boundary, expressed as a number of bytes.
- * E.g. align to an 8-byte boundary with argument of 8.
- */
-
-/*
- *   (this + boundary - 1)
- *          &
- *    ~(boundary - 1)
- */
-
-#define DBUS_ALIGN_VALUE(this, boundary) \
-  (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1)))
-
-#define DBUS_ALIGN_ADDRESS(this, boundary) \
-  ((void*)DBUS_ALIGN_VALUE(this, boundary))
-
 /* from ORBit */
 static void
 swap_bytes (unsigned char *data,
@@ -93,7 +76,7 @@ static dbus_uint32_t
 unpack_uint32 (int                  byte_order,
                const unsigned char *data)
 {
-  _dbus_assert (DBUS_ALIGN_ADDRESS (data, 4) == data);
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
   
   if (byte_order == DBUS_LITTLE_ENDIAN)
     return DBUS_UINT32_FROM_LE (*(dbus_uint32_t*)data);
@@ -101,11 +84,18 @@ unpack_uint32 (int                  byte_order,
     return DBUS_UINT32_FROM_BE (*(dbus_uint32_t*)data);
 }             
 
-static dbus_int32_t
-unpack_int32 (int                  byte_order,
-              const unsigned char *data)
+/**
+ * Unpacks a 32 bit unsigned integer from a data pointer
+ *
+ * @param byte_order The byte order to use
+ * @param data the data pointer
+ * @returns the integer
+ */
+dbus_int32_t
+dbus_unpack_int32 (int                  byte_order,
+                  const unsigned char *data)
 {
-  _dbus_assert (DBUS_ALIGN_ADDRESS (data, 4) == data);
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
   
   if (byte_order == DBUS_LITTLE_ENDIAN)
     return DBUS_INT32_FROM_LE (*(dbus_int32_t*)data);
@@ -125,6 +115,26 @@ unpack_int32 (int                  byte_order,
  */
 
 /**
+ * Packs a 32 bit unsigned integer into a data pointer.
+ *
+ * @param value the value
+ * @param byte_order the byte order to use
+ * @param data the data pointer
+ */
+void
+dbus_pack_int32 (dbus_int32_t   value,
+                int            byte_order,
+                unsigned char *data)
+{
+  _dbus_assert (_DBUS_ALIGN_ADDRESS (data, 4) == data);
+  
+  if ((byte_order) == DBUS_LITTLE_ENDIAN)                  
+    *((dbus_int32_t*)(data)) = DBUS_INT32_TO_LE (value);       
+  else
+    *((dbus_int32_t*)(data)) = DBUS_INT32_TO_BE (value);
+}
+
+/**
  * Marshals a double value.
  *
  * @param str the string to append the marshalled value to
@@ -137,6 +147,11 @@ _dbus_marshal_double (DBusString *str,
                      int         byte_order,
                      double      value)
 {
+  if (!_dbus_string_set_length (str,
+                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
+                                                 sizeof (double))))
+    return FALSE;
+  
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
     swap_bytes ((unsigned char *)&value, sizeof (double));
 
@@ -157,7 +172,7 @@ _dbus_marshal_int32  (DBusString   *str,
                      dbus_int32_t  value)
 {
   if (!_dbus_string_set_length (str,
-                               DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
+                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
                                                  sizeof (dbus_int32_t))))
     return FALSE;
   
@@ -181,7 +196,7 @@ _dbus_marshal_uint32 (DBusString    *str,
                      dbus_uint32_t  value)
 {
   if (!_dbus_string_set_length (str,
-                               DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
+                               _DBUS_ALIGN_VALUE (_dbus_string_get_length (str),
                                                  sizeof (dbus_uint32_t))))
     return FALSE;
 
@@ -269,8 +284,8 @@ _dbus_demarshal_double (DBusString  *str,
   double retval;
   const char *buffer;
 
-  pos = DBUS_ALIGN_VALUE (pos, sizeof (double));
-  
+  pos = _DBUS_ALIGN_VALUE (pos, sizeof (double));
+
   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (double));
 
   retval = *(double *)buffer;
@@ -301,14 +316,14 @@ _dbus_demarshal_int32  (DBusString *str,
 {
   const char *buffer;
 
-  pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
+  pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_int32_t));
   
   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_int32_t));
 
   if (new_pos)
     *new_pos = pos + sizeof (dbus_int32_t);
 
-  return unpack_int32 (byte_order, buffer);
+  return dbus_unpack_int32 (byte_order, buffer);
 }
 
 /**
@@ -328,7 +343,7 @@ _dbus_demarshal_uint32  (DBusString *str,
 {
   const char *buffer;
 
-  pos = DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
+  pos = _DBUS_ALIGN_VALUE (pos, sizeof (dbus_uint32_t));
   
   _dbus_string_get_const_data_len (str, &buffer, pos, sizeof (dbus_uint32_t));
 
@@ -368,7 +383,7 @@ _dbus_demarshal_string (DBusString *str,
   if (!retval)
     return NULL;
 
-  _dbus_string_get_const_data_len (str, &data, pos, 3);
+  _dbus_string_get_const_data_len (str, &data, pos, len);
 
   if (!data)
     return NULL;
@@ -381,6 +396,86 @@ _dbus_demarshal_string (DBusString *str,
   return retval;
 }
 
+/** 
+ * Returns the position right after the end position 
+ * end position of a field
+ *
+ * @param str a string
+ * @param byte_order the byte order to use
+ * @param pos the pos where the field starts
+ * @param end_pos pointer where the position right
+ * after the end position will follow
+ * @returns TRUE if more data exists after the field
+ */
+dbus_bool_t
+_dbus_marshal_get_field_end_pos (DBusString *str,
+                                int         byte_order,
+                                int         pos,
+                                int        *end_pos)
+{
+  const char *data;
+
+  if (pos >= _dbus_string_get_length (str))
+    return FALSE;
+
+  _dbus_string_get_const_data_len (str, &data, pos, 1);
+  
+  switch (*data)
+    {
+    case DBUS_TYPE_INVALID:
+      return FALSE;
+      break;
+
+    case DBUS_TYPE_INT32:
+      *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_int32_t)) + sizeof (dbus_int32_t);
+
+      break;
+
+    case DBUS_TYPE_UINT32:
+      *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (dbus_uint32_t)) + sizeof (dbus_uint32_t);
+
+      break;
+
+    case DBUS_TYPE_DOUBLE:
+      *end_pos = _DBUS_ALIGN_VALUE (pos + 1, sizeof (double)) + sizeof (double);
+
+      break;
+
+    case DBUS_TYPE_STRING:
+      {
+       int len, new_pos;
+
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
+
+       *end_pos = new_pos + len + 1;
+
+       break;
+      }
+
+    case DBUS_TYPE_BYTE_ARRAY:
+      {
+       int len, new_pos;
+
+       /* Demarshal the length */
+       len = _dbus_demarshal_uint32 (str, byte_order, pos + 1, &new_pos);
+       
+       *end_pos = new_pos + len;
+
+       break;
+      }
+      
+    default:
+      _dbus_warn ("Unknown message field type %d\n", *data);
+      return FALSE;
+    }
+
+  if (*end_pos >= _dbus_string_get_length (str))
+    return FALSE;
+  
+  return TRUE;
+}
+
 /**
  * If in verbose mode, print a block of binary data.
  *
@@ -397,7 +492,7 @@ _dbus_verbose_bytes (const unsigned char *data,
   const unsigned char *aligned;
 
   /* Print blanks on first row if appropriate */
-  aligned = DBUS_ALIGN_ADDRESS (data, 4);
+  aligned = _DBUS_ALIGN_ADDRESS (data, 4);
   if (aligned > data)
     aligned -= 4;
   _dbus_assert (aligned <= data);
@@ -416,7 +511,7 @@ _dbus_verbose_bytes (const unsigned char *data,
   i = 0;
   while (i < len)
     {
-      if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
+      if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
         {
           _dbus_verbose ("%5d\t%p: ",
                    i, &data[i]);
@@ -431,7 +526,7 @@ _dbus_verbose_bytes (const unsigned char *data,
 
       ++i;
 
-      if (DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
+      if (_DBUS_ALIGN_ADDRESS (&data[i], 4) == &data[i])
         {
           if (i > 3)
             _dbus_verbose ("big: %d little: %d",
@@ -486,7 +581,6 @@ _dbus_marshal_test (void)
     _dbus_assert_not_reached ("could not marshal double value");
   _dbus_assert (_dbus_demarshal_double (&str, DBUS_BIG_ENDIAN, pos, &pos) == 3.14);
 
-  
   if (!_dbus_marshal_double (&str, DBUS_LITTLE_ENDIAN, 3.14))
     _dbus_assert_not_reached ("could not marshal double value");
   _dbus_assert (_dbus_demarshal_double (&str, DBUS_LITTLE_ENDIAN, pos, &pos) == 3.14);
index 6a9d752..1f5e27a 100644 (file)
 #define DBUS_COMPILER_BYTE_ORDER DBUS_LITTLE_ENDIAN
 #endif
 
+void         dbus_pack_int32   (dbus_int32_t         value,
+                               int                  byte_order,
+                               unsigned char       *data);
+dbus_int32_t dbus_unpack_int32 (int                  byte_order,
+                               const unsigned char *data);
+
+      
 dbus_bool_t _dbus_marshal_double     (DBusString          *str,
                                      int                  byte_order,
                                      double               value);
@@ -73,7 +80,10 @@ char *        _dbus_demarshal_string (DBusString *str,
                                      int         pos,
                                      int        *new_pos);
 
-
+dbus_bool_t _dbus_marshal_get_field_end_pos (DBusString *str,
+                                            int         byte_order,
+                                            int         pos,
+                                            int        *end_pos);
 
 
 
index 9706a28..c57af04 100644 (file)
@@ -29,12 +29,14 @@ DBUS_BEGIN_DECLS;
 
 typedef struct DBusMessageLoader DBusMessageLoader;
 
-void _dbus_message_get_network_data (DBusMessage          *message,
-                                     const DBusString    **header,
-                                     const DBusString    **body);
+void _dbus_message_get_network_data  (DBusMessage       *message,
+                                     const DBusString **header,
+                                     const DBusString **body);
 
-void _dbus_message_lock             (DBusMessage          *message);
+void _dbus_message_lock              (DBusMessage       *message);
 
+void _dbus_message_set_client_serial (DBusMessage       *message,
+                                     dbus_int32_t       client_serial);
 
 DBusMessageLoader* _dbus_message_loader_new                   (void);
 void               _dbus_message_loader_ref                   (DBusMessageLoader  *loader);
index 864887a..fb28ced 100644 (file)
@@ -2,6 +2,7 @@
 /* dbus-message.c  DBusMessage object
  *
  * Copyright (C) 2002  Red Hat Inc.
+ * Copyright (C) 2002, 2003  CodeFactory AB
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -64,9 +65,26 @@ struct DBusMessage
 
   DBusString body;   /**< Body network data. */
 
+  char byte_order; /**< Message byte order. */
+  
+  char *name; /**< Message name. */
+  char *service; /**< Message destination service. */
+  
+  dbus_int32_t client_serial; /**< Client serial or -1 if not set */
+  dbus_int32_t reply_serial; /**< Reply serial or -1 if not set */
+  
   unsigned int locked : 1; /**< Message being sent, no modifications allowed. */
 };
 
+struct DBusMessageIter
+{
+  int refcount; /**< Reference count */
+
+  int pos; /**< Current position in the string */
+  
+  DBusMessage *message; /**< Message used */
+};
+
 /**
  * Gets the data to be sent over the network for this message.
  * The header and then the body should be written out.
@@ -89,6 +107,69 @@ _dbus_message_get_network_data (DBusMessage          *message,
 }
 
 /**
+ * Sets the client serial of a message. 
+ * This can only be done once on a message.
+ *
+ * @param message the message
+ * @param client_serial the client serial
+ */
+void
+_dbus_message_set_client_serial (DBusMessage  *message,
+                                dbus_int32_t  client_serial)
+{
+  _dbus_assert (message->client_serial == -1);
+  
+  message->client_serial = client_serial;
+}
+
+static void
+dbus_message_write_header (DBusMessage *message)
+{
+  char *header;
+  
+  _dbus_assert (message->client_serial != -1);
+  
+  _dbus_string_append_byte (&message->header, DBUS_COMPILER_BYTE_ORDER);
+  _dbus_string_append_len (&message->header, "\0\0\0", 3);
+
+  /* We just lengthen the string here and pack in the real length later */
+  _dbus_string_lengthen (&message->header, 4);
+  
+  _dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, _dbus_string_get_length (&message->body));
+
+  /* Marshal client serial */
+  _dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, message->client_serial);
+
+  /* Marshal message service */
+  if (message->service)
+    {
+      _dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_SERVICE, 4);
+      _dbus_string_append_byte (&message->header, DBUS_TYPE_STRING);
+      
+      _dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER, message->service);
+    }
+
+  /* Marshal message name */
+  _dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_NAME, 4);
+  _dbus_string_append_byte (&message->header, DBUS_TYPE_STRING);
+
+  _dbus_marshal_string (&message->header, DBUS_COMPILER_BYTE_ORDER, message->name);
+
+  /* Marshal reply serial */
+  if (message->reply_serial != -1)
+    {
+      _dbus_string_append_len (&message->header, DBUS_HEADER_FIELD_REPLY, 4);
+
+      _dbus_string_append_byte (&message->header, DBUS_TYPE_INT32);
+      _dbus_marshal_int32 (&message->header, DBUS_COMPILER_BYTE_ORDER, message->reply_serial);
+    }
+  
+  /* Fill in the length */
+  _dbus_string_get_data_len (&message->header, &header, 4, 4);
+  dbus_pack_int32 (_dbus_string_get_length (&message->header), DBUS_COMPILER_BYTE_ORDER, header);
+}
+
+/**
  * Locks a message. Allows checking that applications don't keep a
  * reference to a message in the outgoing queue and change it
  * underneath us. Messages are locked when they enter the outgoing
@@ -98,8 +179,11 @@ _dbus_message_get_network_data (DBusMessage          *message,
  * @param message the message to lock.
  */
 void
-_dbus_message_lock (DBusMessage *message)
+_dbus_message_lock (DBusMessage  *message)
 {
+  if (!message->locked)
+    dbus_message_write_header (message);
+  
   message->locked = TRUE;
 }
 
@@ -128,12 +212,16 @@ _dbus_message_lock (DBusMessage *message)
 /**
  * Constructs a new message. Returns #NULL if memory
  * can't be allocated for the message.
- * 
- * @return a new DBusMessage, free with dbus_message_unref()
+ *
+ * @param service service that the message should be sent to
+ * should be sent to
+ * @param name name of the message
+ * @returns a new DBusMessage, free with dbus_message_unref()
  * @see dbus_message_unref()
  */
 DBusMessage*
-dbus_message_new (void)
+dbus_message_new (const char *service,
+                 const char *name)
 {
   DBusMessage *message;
 
@@ -142,7 +230,14 @@ dbus_message_new (void)
     return NULL;
   
   message->refcount = 1;
+  message->byte_order = DBUS_COMPILER_BYTE_ORDER;
 
+  message->service = _dbus_strdup (service);
+  message->name = _dbus_strdup (name);
+  
+  message->client_serial = -1;
+  message->reply_serial = -1;
+  
   if (!_dbus_string_init (&message->header, _DBUS_MAX_MESSAGE_LENGTH))
     {
       dbus_free (message);
@@ -156,13 +251,6 @@ dbus_message_new (void)
       return NULL;
     }
   
-  /* We need to decide what a message contains. ;-) */
-  /* (not bothering to check failure of these appends) */
-  _dbus_string_append (&message->header, "H");
-  _dbus_string_append_byte (&message->header, '\0');
-  _dbus_string_append (&message->body, "Body");
-  _dbus_string_append_byte (&message->body, '\0');
-  
   return message;
 }
 
@@ -176,6 +264,8 @@ dbus_message_new (void)
 void
 dbus_message_ref (DBusMessage *message)
 {
+  _dbus_assert (message->refcount > 0);
+  
   message->refcount += 1;
 }
 
@@ -188,7 +278,6 @@ dbus_message_ref (DBusMessage *message)
 void
 dbus_message_unref (DBusMessage *message)
 {
-  _dbus_assert (message != NULL);
   _dbus_assert (message->refcount > 0);
 
   message->refcount -= 1;
@@ -197,6 +286,7 @@ dbus_message_unref (DBusMessage *message)
       _dbus_string_free (&message->header);
       _dbus_string_free (&message->body);
       
+      dbus_free (message->name);
       dbus_free (message);
     }
 }
@@ -210,9 +300,7 @@ dbus_message_unref (DBusMessage *message)
 const char*
 dbus_message_get_name (DBusMessage *message)
 {
-  /* FIXME */
-  
-  return NULL;
+  return message->name;
 }
 
 /**
@@ -226,7 +314,6 @@ dbus_bool_t
 dbus_message_append_int32 (DBusMessage  *message,
                           dbus_int32_t  value)
 {
-  _dbus_assert (message != NULL);  
   _dbus_assert (!message->locked);
 
   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
@@ -250,7 +337,6 @@ dbus_bool_t
 dbus_message_append_uint32 (DBusMessage   *message,
                            dbus_uint32_t  value)
 {
-  _dbus_assert (message != NULL);  
   _dbus_assert (!message->locked);
 
   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UINT32))
@@ -274,10 +360,9 @@ dbus_bool_t
 dbus_message_append_double (DBusMessage *message,
                            double       value)
 {
-  _dbus_assert (message != NULL);  
   _dbus_assert (!message->locked);
 
-  if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_INT32))
+  if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_DOUBLE))
     {
       _dbus_string_shorten (&message->body, 1);
       return FALSE;
@@ -298,11 +383,9 @@ dbus_bool_t
 dbus_message_append_string (DBusMessage *message,
                            const char  *value)
 {
-  _dbus_assert (message != NULL);
   _dbus_assert (!message->locked);
-  _dbus_assert (value != NULL);
 
-  if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_UTF8_STRING))
+  if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_STRING))
     {
       _dbus_string_shorten (&message->body, 1);
       return FALSE;
@@ -325,9 +408,7 @@ dbus_message_append_byte_array (DBusMessage         *message,
                                unsigned const char *value,
                                int                 len)
 {
-  _dbus_assert (message != NULL);
   _dbus_assert (!message->locked);
-  _dbus_assert (value != NULL);
 
   if (!_dbus_string_append_byte (&message->body, DBUS_TYPE_BYTE_ARRAY))
     {
@@ -339,6 +420,198 @@ dbus_message_append_byte_array (DBusMessage         *message,
                                   DBUS_COMPILER_BYTE_ORDER, value, len);
 }
 
+/**
+ * Returns a DBusMessageIter representing the fields of the
+ * message passed in.
+ *
+ * @param message the message
+ * @returns a new iter.
+ */
+DBusMessageIter *
+dbus_message_get_fields_iter (DBusMessage *message)
+{
+  DBusMessageIter *iter;
+  
+  iter = dbus_new (DBusMessageIter, 1);
+
+  dbus_message_ref (message);
+  
+  iter->refcount = 1;
+  iter->message = message;
+  iter->pos = 0;
+
+  return iter;
+}
+
+/**
+ * Increments the reference count of a DBusMessageIter.
+ *
+ * @param iter the message iter
+ * @see dbus_message_iter_unref
+ */
+void
+dbus_message_iter_ref (DBusMessageIter *iter)
+{
+  _dbus_assert (iter->refcount > 0);
+  
+  iter->refcount += 1;
+}
+
+/**
+ * Decrements the reference count of a DBusMessageIter.
+ *
+ * @param iter The message iter
+ * @see dbus_message_iter_ref
+ */
+void
+dbus_message_iter_unref (DBusMessageIter *iter)
+{
+  _dbus_assert (iter->refcount > 0);
+
+  iter->refcount -= 1;
+
+  if (iter->refcount == 0)
+    {
+      dbus_message_unref (iter->message);
+
+      dbus_free (iter);
+    }
+}
+
+/**
+ * Checks if an iterator has any more fields.
+ *
+ * @param iter the message iter
+ * @returns #TRUE if there are more fields
+ * following
+ */
+dbus_bool_t
+dbus_message_iter_has_next (DBusMessageIter *iter)
+{
+  int end_pos;
+  
+  if (!_dbus_marshal_get_field_end_pos (&iter->message->body, iter->message->byte_order,
+                                       iter->pos, &end_pos))
+    return FALSE;
+  
+  if (end_pos >= _dbus_string_get_length (&iter->message->body))
+    return FALSE;
+  
+  return TRUE;  
+}
+
+/**
+ * Moves the iterator to the next field.
+ *
+ * @param iter The message iter
+ * @returns #TRUE if the iterator was moved to the next field
+ */
+dbus_bool_t
+dbus_message_iter_next (DBusMessageIter *iter)
+{
+  int end_pos;
+  
+  if (!_dbus_marshal_get_field_end_pos (&iter->message->body, iter->message->byte_order,
+                                       iter->pos, &end_pos))
+    return FALSE;
+
+  if (end_pos >= _dbus_string_get_length (&iter->message->body))
+    return FALSE;
+
+  iter->pos = end_pos;
+
+  return TRUE;
+}
+
+/**
+ * Returns the field type of the field that the
+ * message iterator points at.
+ *
+ * @param iter the message iter
+ * @returns the field type
+ */
+int
+dbus_message_iter_get_field_type (DBusMessageIter *iter)
+{
+  const char *data;
+  
+  if (iter->pos >= _dbus_string_get_length (&iter->message->body))
+    return DBUS_TYPE_INVALID;
+
+  _dbus_string_get_const_data_len (&iter->message->body, &data, iter->pos, 1);
+
+  if (*data > DBUS_TYPE_INVALID && *data <= DBUS_TYPE_STRING)
+    return *data;
+
+  return DBUS_TYPE_INVALID;
+}
+
+/**
+ * Returns the string value that an iterator may point to.
+ * Note that you need to check that the iterator points to
+ * a string value before using this function.
+ *
+ * @see dbus_message_iter_get_field_type
+ * @param iter the message iter
+ * @returns the string
+ */
+char *
+dbus_message_iter_get_string (DBusMessageIter *iter)
+{
+  _dbus_assert (dbus_message_iter_get_field_type (iter) == DBUS_TYPE_STRING);
+
+  return _dbus_demarshal_string (&iter->message->body, iter->message->byte_order,
+                               iter->pos + 1, NULL);
+}
+
+/**
+ * Returns the 32 bit signed integer value that an iterator may point to.
+ * Note that you need to check that the iterator points to
+ * a string value before using this function.
+ *
+ * @see dbus_message_iter_get_field_type
+ * @param iter the message iter
+ * @returns the integer
+ */
+int
+dbus_message_iter_get_int32 (DBusMessageIter *iter)
+{
+  return _dbus_demarshal_int32 (&iter->message->body, iter->message->byte_order,
+                               iter->pos + 1, NULL);
+}
+
+/**
+ * Returns the 32 bit unsigned integer value that an iterator may point to.
+ * Note that you need to check that the iterator points to
+ * a string value before using this function.
+ *
+ * @see dbus_message_iter_get_field_type
+ * @param iter the message iter
+ * @returns the integer
+ */
+int
+dbus_message_iter_get_uint32 (DBusMessageIter *iter)
+{
+  return _dbus_demarshal_uint32 (&iter->message->body, iter->message->byte_order,
+                                iter->pos + 1, NULL);
+}
+
+/**
+ * Returns the double value that an iterator may point to.
+ * Note that you need to check that the iterator points to
+ * a string value before using this function.
+ *
+ * @see dbus_message_iter_get_field_type
+ * @param iter the message iter
+ * @returns the double
+ */
+double
+dbus_message_iter_get_double (DBusMessageIter *iter)
+{
+  return _dbus_demarshal_double (&iter->message->body, iter->message->byte_order,
+                                iter->pos + 1, NULL);
+}
+
 /** @} */
 
 /**
@@ -478,6 +751,65 @@ _dbus_message_loader_get_buffer (DBusMessageLoader  *loader,
 }
 
 /**
+ * The smallest header size that can occur. 
+ * (It won't be valid)
+ */
+#define DBUS_MINIMUM_HEADER_SIZE 16
+
+static dbus_bool_t
+decode_header_data (DBusString   *data,
+                   int           header_len,
+                   int           byte_order,
+                   dbus_int32_t *client_serial,
+                   char        **service,
+                   char        **name)
+{
+  const char *field;
+  int pos, new_pos;
+  
+  /* First demarshal the client serial */
+  *client_serial = _dbus_demarshal_int32 (data, byte_order, 12, &pos);
+
+  *service = NULL;
+  *name = NULL;
+  
+  /* Now handle the fields */
+  while (pos < header_len)
+    {
+      _dbus_string_get_const_data_len (data, &field, pos, 4);
+      pos += 4;
+
+      if (pos > header_len)
+         return FALSE;
+      
+      if (strncmp (field, DBUS_HEADER_FIELD_SERVICE, 4) == 0)
+       {
+         *service = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos);
+       }
+      else if (strncmp (field, DBUS_HEADER_FIELD_NAME, 4) == 0)
+       {
+         *name = _dbus_demarshal_string (data, byte_order, pos + 1, &new_pos);
+       }
+      else
+       {
+         _dbus_verbose ("Encountered an unknown header field: %c%c%c%c\n",
+                        field[0], field[1], field[2], field[3]);
+         
+         if (!_dbus_marshal_get_field_end_pos (data, byte_order, pos, &new_pos))
+           return FALSE;
+       }
+
+      if (new_pos > header_len)
+       return FALSE;
+      
+      pos = new_pos;
+    }
+  
+  return TRUE;
+  
+}
+
+/**
  * Returns a buffer obtained from _dbus_message_loader_get_buffer(),
  * indicating to the loader how many bytes of the buffer were filled
  * in. This function must always be called, even if no bytes were
@@ -495,49 +827,67 @@ _dbus_message_loader_return_buffer (DBusMessageLoader  *loader,
   _dbus_assert (loader->buffer_outstanding);
   _dbus_assert (buffer == &loader->data);
 
-  /* FIXME fake implementation just creates a message for every 7
-   * bytes. The real implementation will pass ownership of
-   * loader->data bytes to new messages, to avoid memcpy.  We can also
-   * smart-realloc loader->data to shrink it if it's too big, though
-   * _dbus_message_loader_get_buffer() could strategically arrange for
-   * that to usually not happen.
-   */
-
   loader->buffer_outstanding = FALSE;
 
   if (loader->corrupted)
     return;
-  
-  while (_dbus_string_get_length (&loader->data) >= 7)
+
+  while (_dbus_string_get_length (&loader->data) >= 16)
     {
-      DBusMessage *message;
-      const char *d;
-
-      _dbus_string_get_const_data (&loader->data, &d);
-      if (d[0] != 'H' ||
-          d[1] != '\0' ||
-          d[2] != 'B' ||
-          d[3] != 'o' ||
-          d[4] != 'd' ||
-          d[5] != 'y' ||
-          d[6] != '\0')
-        {
-          _dbus_verbose_bytes (d,
-                               _dbus_string_get_length (&loader->data));
-          loader->corrupted = TRUE;
-          return;
-        }
+      DBusMessage *message;      
+      const char *header_data;
+      int byte_order, header_len, body_len;
       
-      message = dbus_message_new ();
-      if (message == NULL)
-        break; /* ugh, postpone this I guess. */
+      _dbus_string_get_const_data_len (&loader->data, &header_data, 0, 16);
+      byte_order = header_data[0];
 
-      _dbus_list_append (&loader->messages, message);
+      if (byte_order != DBUS_LITTLE_ENDIAN &&
+         byte_order != DBUS_BIG_ENDIAN)
+       {
+         loader->corrupted = TRUE;
+         return;
+       }
 
-      _dbus_string_delete (&loader->data,
-                           0, 7);
-      
-      _dbus_verbose ("Loaded message %p\n", message);
+      header_len = dbus_unpack_int32 (byte_order, header_data + 4);
+      body_len = dbus_unpack_int32 (byte_order, header_data + 8);
+
+      if (header_len + body_len > _DBUS_MAX_MESSAGE_LENGTH)
+       {
+         loader->corrupted = TRUE;
+
+         return;
+       }
+
+      if (_dbus_string_get_length (&loader->data) >= header_len + body_len)
+       {
+         dbus_int32_t client_serial;
+         char *service, *name;
+         
+         if (!decode_header_data (&loader->data, header_len, byte_order,
+                                  &client_serial, &service, &name))
+           {
+             loader->corrupted = TRUE;
+
+             return;
+           }
+
+         message = dbus_message_new (service, name);
+         dbus_free (service);
+         dbus_free (name);
+         
+         if (message == NULL)
+           break; /* ugh, postpone this I guess. */
+
+         _dbus_string_copy (&loader->data, header_len, &message->body, 0);
+         _dbus_message_set_client_serial (message, client_serial);
+         
+         _dbus_list_append (&loader->messages, message);
+         _dbus_string_delete (&loader->data, 0, header_len + body_len);
+
+         _dbus_verbose ("Loaded message %p\n", message);         
+       }
+      else
+       break;
     }
 }
 
@@ -572,3 +922,129 @@ _dbus_message_loader_get_is_corrupted (DBusMessageLoader *loader)
 }
 
 /** @} */
+#ifdef DBUS_BUILD_TESTS
+#include "dbus-test.h"
+#include <stdio.h>
+
+static void
+message_iter_test (DBusMessage *message)
+{
+  DBusMessageIter *iter;
+  char *str;
+  
+  iter = dbus_message_get_fields_iter (message);
+
+  /* String tests */
+  if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_STRING)
+    _dbus_assert_not_reached ("Field type isn't string");
+
+  str = dbus_message_iter_get_string (iter);
+  if (strcmp (str, "Test string") != 0)
+    _dbus_assert_not_reached ("Strings differ");
+  dbus_free (str);
+
+  if (!dbus_message_iter_next (iter))
+    _dbus_assert_not_reached ("Reached end of fields");
+
+  /* Signed integer tests */
+  if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_INT32)
+    _dbus_assert_not_reached ("Field type isn't int32");
+
+  if (dbus_message_iter_get_int32 (iter) != -0x12345678)
+    _dbus_assert_not_reached ("Signed integers differ");
+
+  if (!dbus_message_iter_next (iter))
+    _dbus_assert_not_reached ("Reached end of fields");
+  
+  /* Unsigned integer tests */
+  if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_UINT32)
+    _dbus_assert_not_reached ("Field type isn't int32");
+
+  if (dbus_message_iter_get_int32 (iter) != 0xedd1e)
+    _dbus_assert_not_reached ("Unsigned integers differ");
+
+  if (!dbus_message_iter_next (iter))
+    _dbus_assert_not_reached ("Reached end of fields");
+
+  /* Double tests */
+  if (dbus_message_iter_get_field_type (iter) != DBUS_TYPE_DOUBLE)
+    _dbus_assert_not_reached ("Field type isn't double");
+
+  if (dbus_message_iter_get_double (iter) != 3.14159)
+    _dbus_assert_not_reached ("Doubles differ");
+
+  if (dbus_message_iter_next (iter))
+    _dbus_assert_not_reached ("Didn't reach end of fields");
+  
+  dbus_message_iter_unref (iter);
+}
+
+/**
+ * @ingroup DBusMessageInternals
+ * Unit test for DBusMessage.
+ *
+ * @returns #TRUE on success.
+ */
+dbus_bool_t
+_dbus_message_test (void)
+{
+  DBusMessage *message;
+
+  DBusMessageLoader *loader;
+  int i;
+  const char *data;
+
+  message = dbus_message_new ("org.freedesktop.DBus.Test", "testMessage");
+  message->client_serial = 1;
+  dbus_message_append_string (message, "Test string");
+  dbus_message_append_int32 (message, -0x12345678);
+  dbus_message_append_uint32 (message, 0xedd1e);
+  dbus_message_append_double (message, 3.14159);
+
+  message_iter_test (message);
+
+  /* Message loader test */
+  _dbus_message_lock (message);
+  loader = _dbus_message_loader_new ();
+
+  /* Write the header data one byte at a time */
+  _dbus_string_get_const_data (&message->header, &data);
+  for (i = 0; i < _dbus_string_get_length (&message->header); i++)
+    {
+      DBusString *buffer;
+
+      _dbus_message_loader_get_buffer (loader, &buffer);
+      _dbus_string_append_byte (buffer, data[i]);
+      _dbus_message_loader_return_buffer (loader, buffer, 1);
+    }
+
+  /* Write the body data one byte at a time */
+  _dbus_string_get_const_data (&message->body, &data);
+  for (i = 0; i < _dbus_string_get_length (&message->body); i++)
+    {
+      DBusString *buffer;
+
+      _dbus_message_loader_get_buffer (loader, &buffer);
+      _dbus_string_append_byte (buffer, data[i]);
+      _dbus_message_loader_return_buffer (loader, buffer, 1);
+    }
+
+  dbus_message_unref (message);
+
+  /* Now pop back the message */
+  if (_dbus_message_loader_get_is_corrupted (loader))
+    _dbus_assert_not_reached ("message loader corrupted");
+  
+  message = _dbus_message_loader_pop_message (loader);
+  if (!message)
+    _dbus_assert_not_reached ("received a NULL message");
+
+  message_iter_test (message);
+  
+  dbus_message_unref (message);
+  _dbus_message_loader_unref (loader);
+
+  return TRUE;
+}
+
+#endif /* DBUS_BUILD_TESTS */
index f427780..b8eb0ee 100644 (file)
 DBUS_BEGIN_DECLS;
 
 typedef struct DBusMessage DBusMessage;
+typedef struct DBusMessageIter DBusMessageIter;
 
-DBusMessage* dbus_message_new   (void);
+DBusMessage* dbus_message_new   (const char *service,
+                                const char *name);
 
 void         dbus_message_ref   (DBusMessage *message);
 void         dbus_message_unref (DBusMessage *message);
@@ -53,6 +55,20 @@ dbus_bool_t dbus_message_append_byte_array (DBusMessage         *message,
                                            unsigned const char *value,
                                            int                  len);
 
+DBusMessageIter *dbus_message_get_fields_iter     (DBusMessage     *message);
+
+void        dbus_message_iter_ref            (DBusMessageIter *iter);
+void        dbus_message_iter_unref          (DBusMessageIter *iter);
+
+dbus_bool_t dbus_message_iter_has_next      (DBusMessageIter *iter);
+dbus_bool_t dbus_message_iter_next           (DBusMessageIter *iter);
+int         dbus_message_iter_get_field_type (DBusMessageIter *iter);
+int         dbus_message_iter_get_int32      (DBusMessageIter *iter);
+int         dbus_message_iter_get_uint32     (DBusMessageIter *iter);
+double      dbus_message_iter_get_double     (DBusMessageIter *iter);
+char *      dbus_message_iter_get_string     (DBusMessageIter *iter);
+
+
 
 DBUS_END_DECLS;
 
index e1a17b5..634283c 100644 (file)
@@ -45,8 +45,13 @@ extern "C" {
 #define DBUS_TYPE_UINT32_ARRAY  5
 #define DBUS_TYPE_DOUBLE_ARRAY  6
 #define DBUS_TYPE_BYTE_ARRAY    7
-#define DBUS_TYPE_UTF8_STRING   8
+#define DBUS_TYPE_STRING        8
   
+/* Header fields */
+#define DBUS_HEADER_FIELD_NAME    "name"
+#define DBUS_HEADER_FIELD_SERVICE "srvc"
+#define DBUS_HEADER_FIELD_REPLY          "rply"
+
 #ifdef __cplusplus
 }
 #endif
index 095675b..2866e08 100644 (file)
@@ -44,6 +44,10 @@ main (int    argc,
   printf ("%s: running marshalling tests\n", argv[0]);
   if (!_dbus_marshal_test ())
     die ("marshalling");
+
+  printf ("%s: running message tests\n", argv[0]);
+  if (!_dbus_message_test ())
+    die ("messages");
   
   printf ("%s: running memory pool tests\n", argv[0]);
   if (!_dbus_mem_pool_test ())
index e2624ed..881d0e4 100644 (file)
@@ -31,5 +31,6 @@ dbus_bool_t _dbus_list_test     (void);
 dbus_bool_t _dbus_marshal_test  (void);
 dbus_bool_t _dbus_mem_pool_test (void);
 dbus_bool_t _dbus_string_test   (void);
+dbus_bool_t _dbus_message_test  (void);
 
 #endif /* DBUS_TEST_H */
index 3637678..cdce289 100644 (file)
@@ -10,7 +10,7 @@ message_handler (DBusConnection *connection,
   static int count = 0;
   DBusMessage *reply;
 
-  reply = dbus_message_new ();
+  reply = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
   dbus_connection_send_message (connection,
                                reply,
                                NULL);
@@ -47,7 +47,7 @@ main (int argc, char **argv)
   g_source_attach (source, NULL);
   g_source_set_callback (source, (GSourceFunc)message_handler, NULL, NULL);
   
-  message = dbus_message_new ();
+  message = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
   dbus_connection_send_message (connection,
                                 message,
                                 NULL);
index 5c6ee42..fe2fa71 100644 (file)
@@ -27,7 +27,7 @@ main (int    argc,
   setup_connection (connection);
 
   /* Send a message to get things going */
-  message = dbus_message_new ();
+  message = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
   dbus_connection_send_message (connection,
                                 message,
                                 NULL);
index 4387a9d..f9b8b8d 100644 (file)
@@ -148,7 +148,7 @@ check_messages (void)
 
           printf ("Received message %d, sending reply\n", count);
           
-          reply = dbus_message_new ();
+          reply = dbus_message_new ("org.freedesktop.DBus.Test", "org.freedesktop.DBus.Test");
           dbus_connection_send_message (connection,
                                         reply,
                                         NULL);