From 1b53cbcce333381754b0568b740ece550a8f6ac9 Mon Sep 17 00:00:00 2001 From: Anders Carlsson Date: Tue, 7 Jan 2003 20:18:23 +0000 Subject: 2003-01-07 Anders Carlsson * 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. --- ChangeLog | 37 +++ dbus/dbus-connection-internal.h | 1 - dbus/dbus-connection.c | 19 +- dbus/dbus-internals.h | 17 ++ dbus/dbus-marshal.c | 162 ++++++++--- dbus/dbus-marshal.h | 12 +- dbus/dbus-message-internal.h | 10 +- dbus/dbus-message.c | 594 ++++++++++++++++++++++++++++++++++++---- dbus/dbus-message.h | 18 +- dbus/dbus-protocol.h | 7 +- dbus/dbus-test.c | 4 + dbus/dbus-test.h | 1 + glib/test-dbus-glib.c | 4 +- test/echo-client.c | 2 +- test/watch.c | 2 +- 15 files changed, 784 insertions(+), 106 deletions(-) diff --git a/ChangeLog b/ChangeLog index a73d3f31..7a01a8f9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,40 @@ +2003-01-07 Anders Carlsson + + * 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 * dbus/dbus-marshal.c: (_dbus_marshal_double), diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h index cf932ddd..7a648745 100644 --- a/dbus/dbus-connection-internal.h +++ b/dbus/dbus-connection-internal.h @@ -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); diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 66bd0645..8efa0014 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -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) diff --git a/dbus/dbus-internals.h b/dbus/dbus-internals.h index 2f025c14..87dfbf12 100644 --- a/dbus/dbus-internals.h +++ b/dbus/dbus-internals.h @@ -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) diff --git a/dbus/dbus-marshal.c b/dbus/dbus-marshal.c index 49d06a73..7c85ded0 100644 --- a/dbus/dbus-marshal.c +++ b/dbus/dbus-marshal.c @@ -53,23 +53,6 @@ #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); @@ -124,6 +114,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. * @@ -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); diff --git a/dbus/dbus-marshal.h b/dbus/dbus-marshal.h index 6a9d752f..1f5e27a8 100644 --- a/dbus/dbus-marshal.h +++ b/dbus/dbus-marshal.h @@ -39,6 +39,13 @@ #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); diff --git a/dbus/dbus-message-internal.h b/dbus/dbus-message-internal.h index 9706a284..c57af04f 100644 --- a/dbus/dbus-message-internal.h +++ b/dbus/dbus-message-internal.h @@ -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); diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 864887ad..fb28ced0 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -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. @@ -88,6 +106,69 @@ _dbus_message_get_network_data (DBusMessage *message, *body = &message->body; } +/** + * 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 @@ -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); +} + /** @} */ /** @@ -477,6 +750,65 @@ _dbus_message_loader_get_buffer (DBusMessageLoader *loader, loader->buffer_outstanding = TRUE; } +/** + * 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 @@ -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 + +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 */ diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index f427780f..b8eb0eec 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -33,8 +33,10 @@ 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; diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index e1a17b54..634283c6 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -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 diff --git a/dbus/dbus-test.c b/dbus/dbus-test.c index 095675b3..2866e084 100644 --- a/dbus/dbus-test.c +++ b/dbus/dbus-test.c @@ -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 ()) diff --git a/dbus/dbus-test.h b/dbus/dbus-test.h index e2624ede..881d0e42 100644 --- a/dbus/dbus-test.h +++ b/dbus/dbus-test.h @@ -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 */ diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c index 3637678d..cdce2899 100644 --- a/glib/test-dbus-glib.c +++ b/glib/test-dbus-glib.c @@ -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); diff --git a/test/echo-client.c b/test/echo-client.c index 5c6ee425..fe2fa713 100644 --- a/test/echo-client.c +++ b/test/echo-client.c @@ -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); diff --git a/test/watch.c b/test/watch.c index 4387a9d6..f9b8b8d9 100644 --- a/test/watch.c +++ b/test/watch.c @@ -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); -- cgit