From 9c5d01f0fe1ba855c0f7518c4f27d75a609b8faa Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sat, 2 Aug 2003 03:39:35 +0000 Subject: 2003-08-01 Havoc Pennington * dbus/dbus-object-registry.c (_dbus_object_registry_handle_and_unlock): implement * dbus/dbus-message.c (dbus_message_get_type): new function * doc/dbus-specification.sgml: add "type" byte to messages --- dbus/dbus-bus.c | 16 ++-- dbus/dbus-connection.c | 6 +- dbus/dbus-message-builder.c | 8 +- dbus/dbus-message.c | 174 +++++++++++++++++++++++++++++++++----------- dbus/dbus-message.h | 16 ++-- dbus/dbus-object-registry.c | 85 +++++++++++++++++++++- dbus/dbus-object.c | 5 +- dbus/dbus-protocol.h | 1 + 8 files changed, 247 insertions(+), 64 deletions(-) (limited to 'dbus') diff --git a/dbus/dbus-bus.c b/dbus/dbus-bus.c index 6ab1eccc..214978da 100644 --- a/dbus/dbus-bus.c +++ b/dbus/dbus-bus.c @@ -398,8 +398,8 @@ dbus_bus_register (DBusConnection *connection, return TRUE; } - message = dbus_message_new (DBUS_MESSAGE_HELLO, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_HELLO, + DBUS_SERVICE_DBUS); if (!message) @@ -516,8 +516,8 @@ dbus_bus_acquire_service (DBusConnection *connection, _dbus_return_val_if_fail (service_name != NULL, 0); _dbus_return_val_if_error_is_set (error, 0); - message = dbus_message_new (DBUS_MESSAGE_ACQUIRE_SERVICE, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_ACQUIRE_SERVICE, + DBUS_SERVICE_DBUS); if (message == NULL) @@ -590,8 +590,8 @@ dbus_bus_service_exists (DBusConnection *connection, _dbus_return_val_if_fail (service_name != NULL, FALSE); _dbus_return_val_if_error_is_set (error, FALSE); - message = dbus_message_new (DBUS_MESSAGE_SERVICE_EXISTS, - DBUS_SERVICE_DBUS); + message = dbus_message_new_method_call (DBUS_MESSAGE_SERVICE_EXISTS, + DBUS_SERVICE_DBUS); if (message == NULL) { _DBUS_SET_OOM (error); @@ -652,8 +652,8 @@ dbus_bus_activate_service (DBusConnection *connection, DBusMessage *msg; DBusMessage *reply; - msg = dbus_message_new (DBUS_MESSAGE_ACTIVATE_SERVICE, - DBUS_SERVICE_DBUS); + msg = dbus_message_new_method_call (DBUS_MESSAGE_ACTIVATE_SERVICE, + DBUS_SERVICE_DBUS); if (!dbus_message_append_args (msg, DBUS_TYPE_STRING, service_name, DBUS_TYPE_UINT32, flags, DBUS_TYPE_INVALID)) diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index 4b72d600..ced50bd1 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -722,7 +722,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport) if (io_path_cond == NULL) goto error; - disconnect_message = dbus_message_new (DBUS_MESSAGE_LOCAL_DISCONNECT, NULL); + disconnect_message = dbus_message_new_signal (DBUS_MESSAGE_LOCAL_DISCONNECT); if (disconnect_message == NULL) goto error; @@ -1615,8 +1615,8 @@ dbus_connection_send_with_reply (DBusConnection *connection, dbus_message_handler_ref (reply_handler); - reply = dbus_message_new_error_reply (message, DBUS_ERROR_NO_REPLY, - "No reply within specified time"); + reply = dbus_message_new_error (message, DBUS_ERROR_NO_REPLY, + "No reply within specified time"); if (!reply) { CONNECTION_UNLOCK (connection); diff --git a/dbus/dbus-message-builder.c b/dbus/dbus-message-builder.c index 390dda75..fc85fc32 100644 --- a/dbus/dbus-message-builder.c +++ b/dbus/dbus-message-builder.c @@ -393,8 +393,14 @@ _dbus_message_data_load (DBusString *dest, goto parse_failed; } + if (!_dbus_string_append_byte (dest, DBUS_MESSAGE_TYPE_METHOD_CALL)) + { + _dbus_warn ("could not append message type\n"); + goto parse_failed; + } + i = 0; - while (i < 3) + while (i < 2) { if (!_dbus_string_append_byte (dest, '\0')) { diff --git a/dbus/dbus-message.c b/dbus/dbus-message.c index 52226603..c39ca3b4 100644 --- a/dbus/dbus-message.c +++ b/dbus/dbus-message.c @@ -73,6 +73,11 @@ typedef struct */ } HeaderField; +#define BYTE_ORDER_OFFSET 0 +#define TYPE_OFFSET 1 +#define FLAGS_OFFSET 2 +#define VERSION_OFFSET 3 + /** * @brief Internals of DBusMessage * @@ -803,6 +808,7 @@ _dbus_message_remove_size_counter (DBusMessage *message, static dbus_bool_t dbus_message_create_header (DBusMessage *message, + int type, const char *name, const char *service) { @@ -811,6 +817,9 @@ dbus_message_create_header (DBusMessage *message, if (!_dbus_string_append_byte (&message->header, message->byte_order)) return FALSE; + if (!_dbus_string_append_byte (&message->header, type)) + return FALSE; + flags = 0; if (!_dbus_string_append_byte (&message->header, flags)) return FALSE; @@ -818,9 +827,6 @@ dbus_message_create_header (DBusMessage *message, if (!_dbus_string_append_byte (&message->header, DBUS_MAJOR_PROTOCOL_VERSION)) return FALSE; - if (!_dbus_string_append_byte (&message->header, 0)) - return FALSE; - message->header_fields[FIELD_HEADER_LENGTH].offset = 4; if (!_dbus_marshal_uint32 (&message->header, message->byte_order, 0)) return FALSE; @@ -944,10 +950,11 @@ dbus_message_new_empty_header (void) /** - * Constructs a new message. Returns #NULL if memory can't be - * allocated for the message. The service may be #NULL in which case - * no service is set; this is appropriate when using D-BUS in a - * peer-to-peer context (no message bus). + * Constructs a new message to invoke a method on a remote + * object. Returns #NULL if memory can't be allocated for the + * message. The service may be #NULL in which case no service is set; + * this is appropriate when using D-BUS in a peer-to-peer context (no + * message bus). * * @param name name of the message * @param destination_service service that the message should be sent to or #NULL @@ -955,8 +962,8 @@ dbus_message_new_empty_header (void) * @see dbus_message_unref() */ DBusMessage* -dbus_message_new (const char *name, - const char *destination_service) +dbus_message_new_method_call (const char *name, + const char *destination_service) { DBusMessage *message; @@ -966,7 +973,9 @@ dbus_message_new (const char *name, if (message == NULL) return NULL; - if (!dbus_message_create_header (message, name, destination_service)) + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_METHOD_CALL, + name, destination_service)) { dbus_message_unref (message); return NULL; @@ -976,37 +985,43 @@ dbus_message_new (const char *name, } /** - * Constructs a message that is a reply to some other - * message. Returns #NULL if memory can't be allocated - * for the message. + * Constructs a message that is a reply to a method call. Returns + * #NULL if memory can't be allocated for the message. * - * @param original_message the message which the created + * @param method_call the message which the created * message is a reply to. * @returns a new DBusMessage, free with dbus_message_unref() - * @see dbus_message_new(), dbus_message_unref() + * @see dbus_message_new_method_call(), dbus_message_unref() */ DBusMessage* -dbus_message_new_reply (DBusMessage *original_message) +dbus_message_new_method_return (DBusMessage *method_call) { DBusMessage *message; const char *sender, *name; - _dbus_return_val_if_fail (original_message != NULL, NULL); + _dbus_return_val_if_fail (method_call != NULL, NULL); - sender = get_string_field (original_message, + sender = get_string_field (method_call, FIELD_SENDER, NULL); - name = get_string_field (original_message, + name = get_string_field (method_call, FIELD_NAME, NULL); /* sender is allowed to be null here in peer-to-peer case */ - - message = dbus_message_new (name, sender); - + + message = dbus_message_new_empty_header (); if (message == NULL) return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_METHOD_RETURN, + name, sender)) + { + dbus_message_unref (message); + return NULL; + } if (!dbus_message_set_reply_serial (message, - dbus_message_get_serial (original_message))) + dbus_message_get_serial (method_call))) { dbus_message_unref (message); return NULL; @@ -1015,41 +1030,79 @@ dbus_message_new_reply (DBusMessage *original_message) return message; } +/** + * Constructs a new message representing a signal emission. Returns + * #NULL if memory can't be allocated for the message. The name + * passed in is the name of the signal. + * + * @param name name of the signal + * @returns a new DBusMessage, free with dbus_message_unref() + * @see dbus_message_unref() + */ +DBusMessage* +dbus_message_new_signal (const char *name) +{ + DBusMessage *message; + + _dbus_return_val_if_fail (name != NULL, NULL); + + message = dbus_message_new_empty_header (); + if (message == NULL) + return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_SIGNAL, + name, NULL)) + { + dbus_message_unref (message); + return NULL; + } + + return message; +} + /** * Creates a new message that is an error reply to a certain message. + * Error replies are possible in response to method calls primarily. * - * @param original_message the original message + * @param reply_to the original message * @param error_name the error name * @param error_message the error message string or #NULL for none * @returns a new error message */ DBusMessage* -dbus_message_new_error_reply (DBusMessage *original_message, - const char *error_name, - const char *error_message) +dbus_message_new_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message) { DBusMessage *message; const char *sender; DBusMessageIter iter; - _dbus_return_val_if_fail (original_message != NULL, NULL); + _dbus_return_val_if_fail (reply_to != NULL, NULL); _dbus_return_val_if_fail (error_name != NULL, NULL); - sender = get_string_field (original_message, + sender = get_string_field (reply_to, FIELD_SENDER, NULL); /* sender may be NULL for non-message-bus case or * when the message bus is dealing with an unregistered * connection. */ - - message = dbus_message_new (error_name, sender); - + message = dbus_message_new_empty_header (); if (message == NULL) return NULL; + + if (!dbus_message_create_header (message, + DBUS_MESSAGE_TYPE_ERROR, + error_name, sender)) + { + dbus_message_unref (message); + return NULL; + } if (!dbus_message_set_reply_serial (message, - dbus_message_get_serial (original_message))) + dbus_message_get_serial (reply_to))) { dbus_message_unref (message); return NULL; @@ -1200,6 +1253,28 @@ dbus_message_unref (DBusMessage *message) } } +/** + * Gets the type of a message. Types include + * DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_METHOD_RETURN, + * DBUS_MESSAGE_TYPE_ERROR, DBUS_MESSAGE_TYPE_SIGNAL, but other types + * are allowed and all code must silently ignore messages of unknown + * type. DBUS_MESSAGE_TYPE_INVALID will never be returned, however. + * + * + * @param message the message + * @returns the type of the message + */ +int +dbus_message_get_type (DBusMessage *message) +{ + int type; + + type = _dbus_string_get_byte (&message->header, 1); + _dbus_assert (type != DBUS_MESSAGE_TYPE_INVALID); + + return type; +} + /** * Gets the name of a message. * @@ -3704,7 +3779,7 @@ dbus_message_set_is_error (DBusMessage *message, _dbus_return_if_fail (message != NULL); _dbus_return_if_fail (!message->locked); - header = _dbus_string_get_data_len (&message->header, 1, 1); + header = _dbus_string_get_data_len (&message->header, FLAGS_OFFSET, 1); if (is_error_reply) *header |= DBUS_HEADER_FLAG_ERROR; @@ -3726,7 +3801,7 @@ dbus_message_get_is_error (DBusMessage *message) _dbus_return_val_if_fail (message != NULL, FALSE); - header = _dbus_string_get_const_data_len (&message->header, 1, 1); + header = _dbus_string_get_const_data_len (&message->header, FLAGS_OFFSET, 1); return (*header & DBUS_HEADER_FLAG_ERROR) != 0; } @@ -4298,6 +4373,9 @@ _dbus_message_loader_return_buffer (DBusMessageLoader *loader, /** * Converts buffered data into messages. * + * @todo we need to check that the proper named header fields exist + * for each message type. + * * @param loader the loader. * @returns #TRUE if we had enough memory to finish. */ @@ -4311,22 +4389,22 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) { DBusMessage *message; const char *header_data; - int byte_order, header_len, body_len, header_padding; + int byte_order, message_type, header_len, body_len, header_padding; dbus_uint32_t header_len_unsigned, body_len_unsigned; header_data = _dbus_string_get_const_data_len (&loader->data, 0, 16); _dbus_assert (_DBUS_ALIGN_ADDRESS (header_data, 4) == header_data); - if (header_data[2] != DBUS_MAJOR_PROTOCOL_VERSION) + if (header_data[VERSION_OFFSET] != DBUS_MAJOR_PROTOCOL_VERSION) { _dbus_verbose ("Message has protocol version %d ours is %d\n", - (int) header_data[2], DBUS_MAJOR_PROTOCOL_VERSION); + (int) header_data[VERSION_OFFSET], DBUS_MAJOR_PROTOCOL_VERSION); loader->corrupted = TRUE; return TRUE; } - byte_order = header_data[0]; + byte_order = header_data[BYTE_ORDER_OFFSET]; if (byte_order != DBUS_LITTLE_ENDIAN && byte_order != DBUS_BIG_ENDIAN) @@ -4337,6 +4415,18 @@ _dbus_message_loader_queue_messages (DBusMessageLoader *loader) return TRUE; } + /* Unknown types are ignored, but INVALID is + * disallowed + */ + message_type = header_data[TYPE_OFFSET]; + if (message_type == DBUS_MESSAGE_TYPE_INVALID) + { + _dbus_verbose ("Message with bad type '%d' received\n", + message_type); + loader->corrupted = TRUE; + return TRUE; + } + header_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 4); body_len_unsigned = _dbus_unpack_uint32 (byte_order, header_data + 8); @@ -5821,7 +5911,7 @@ _dbus_message_test (const char *test_data_dir) _dbus_assert (sizeof (DBusMessageRealIter) <= sizeof (DBusMessageIter)); - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _dbus_assert (dbus_message_has_destination (message, "org.freedesktop.DBus.Test")); _dbus_message_set_serial (message, 1234); dbus_message_set_sender (message, "org.foo.bar"); @@ -5840,7 +5930,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); /* Test the vararg functions */ - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _dbus_message_set_serial (message, 1); dbus_message_append_args (message, DBUS_TYPE_INT32, -0x12345678, @@ -5906,7 +5996,7 @@ _dbus_message_test (const char *test_data_dir) dbus_message_unref (message); dbus_message_unref (copy); - message = dbus_message_new ("test.Message", "org.freedesktop.DBus.Test"); + message = dbus_message_new_method_call ("test.Message", "org.freedesktop.DBus.Test"); _dbus_message_set_serial (message, 1); dbus_message_set_reply_serial (message, 0x12345678); diff --git a/dbus/dbus-message.h b/dbus/dbus-message.h index bd52bd1a..d2c14c78 100644 --- a/dbus/dbus-message.h +++ b/dbus/dbus-message.h @@ -57,17 +57,19 @@ struct DBusMessageIter void *pad3; }; +DBusMessage* dbus_message_new_method_call (const char *name, + const char *destination_service); +DBusMessage* dbus_message_new_method_return (DBusMessage *method_call); +DBusMessage* dbus_message_new_signal (const char *name); +DBusMessage* dbus_message_new_error (DBusMessage *reply_to, + const char *error_name, + const char *error_message); -DBusMessage* dbus_message_new (const char *name, - const char *destination_service); -DBusMessage* dbus_message_new_reply (DBusMessage *original_message); -DBusMessage* dbus_message_new_error_reply (DBusMessage *original_message, - const char *error_name, - const char *error_message); -DBusMessage *dbus_message_copy (const DBusMessage *message); +DBusMessage *dbus_message_copy (const DBusMessage *message); void dbus_message_ref (DBusMessage *message); void dbus_message_unref (DBusMessage *message); +int dbus_message_get_type (DBusMessage *message); const char* dbus_message_get_name (DBusMessage *message); const char* dbus_message_get_destination (DBusMessage *message); dbus_bool_t dbus_message_set_sender (DBusMessage *message, diff --git a/dbus/dbus-object-registry.c b/dbus/dbus-object-registry.c index a550f8e2..a4d92216 100644 --- a/dbus/dbus-object-registry.c +++ b/dbus/dbus-object-registry.c @@ -24,6 +24,7 @@ #include "dbus-connection-internal.h" #include "dbus-internals.h" #include "dbus-hash.h" +#include "dbus-protocol.h" #include /** @@ -599,12 +600,64 @@ _dbus_object_registry_remove_and_unlock (DBusObjectRegistry *registry, (* vtable->unregistered) (&info); } +/** + * Handle a message, passing it to any objects in the registry that + * should receive it. + * + * @todo handle messages to an object ID, not just those to + * an interface name. + * + * @param registry the object registry + * @param message the message to handle + * @returns what to do with the message next + */ DBusHandlerResult _dbus_object_registry_handle_and_unlock (DBusObjectRegistry *registry, DBusMessage *message) { - /* FIXME */ - return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + DBusInterfaceEntry *iface_entry; + DBusObjectEntry *object_entry; + DBusObjectInfo info; + const DBusObjectVTable *vtable; + + _dbus_assert (registry != NULL); + _dbus_assert (message != NULL); + + if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + + /* If the message isn't to a specific object ID, we send + * it to the first object that supports the given interface. + */ + iface_entry = lookup_interface (registry, + dbus_message_get_name (message), + FALSE); + + if (iface_entry == NULL) + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; + + _dbus_assert (iface_entry->n_objects > 0); + _dbus_assert (iface_entry->objects != NULL); + + object_entry = ®istry->entries[iface_entry->objects[0]]; + + + /* Once we have an object entry, pass message to the object */ + + _dbus_assert (object_entry->vtable != NULL); + + info_from_entry (registry, &info, object_entry); + vtable = object_entry->vtable; + + /* Drop lock and invoke application code */ +#ifdef DBUS_BUILD_TESTS + if (registry->connection) +#endif + _dbus_connection_unlock (registry->connection); + + (* vtable->message) (&info, message); + + return DBUS_HANDLER_RESULT_REMOVE_MESSAGE; } void @@ -665,6 +718,7 @@ add_and_remove_objects (DBusObjectRegistry *registry) "org.freedesktop.Test.Foo", NULL }; int i; + DBusMessage *message; i = 0; while (i < N_OBJECTS) @@ -761,6 +815,33 @@ add_and_remove_objects (DBusObjectRegistry *registry) ++i; } + message = dbus_message_new_method_call ("org.freedesktop.Test.Foo", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + _dbus_assert_not_reached ("message not handled\n"); + dbus_message_unref (message); + } + + message = dbus_message_new_method_call ("org.freedesktop.Test.Blah", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_REMOVE_MESSAGE) + _dbus_assert_not_reached ("message not handled\n"); + dbus_message_unref (message); + } + + message = dbus_message_new_method_call ("org.freedesktop.Test.NotRegisteredIface", NULL); + if (message != NULL) + { + if (_dbus_object_registry_handle_and_unlock (registry, message) != + DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS) + _dbus_assert_not_reached ("message handled but no handler was registered\n"); + dbus_message_unref (message); + } + i = 0; while (i < (N_OBJECTS - 30)) { diff --git a/dbus/dbus-object.c b/dbus/dbus-object.c index c3f1536d..5582f94a 100644 --- a/dbus/dbus-object.c +++ b/dbus/dbus-object.c @@ -273,6 +273,10 @@ dbus_callback_object_set_data (DBusCallbackObject *callback, * Sets the function to be used to handle messages to the * callback object. * + * @todo the thread locking on DBusCallbackObject is hosed; in this + * function in particular it's a joke since we don't take the same + * lock when _calling_ the callback function. + * * @param callback the callback * @param function the function */ @@ -287,7 +291,6 @@ dbus_callback_object_set_function (DBusCallbackObject *callback, _DBUS_UNLOCK (callback_object); } - /** @} */ #ifdef DBUS_BUILD_TESTS diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h index 04988862..dcb7a042 100644 --- a/dbus/dbus-protocol.h +++ b/dbus/dbus-protocol.h @@ -61,6 +61,7 @@ extern "C" { #define DBUS_MAXIMUM_NAME_LENGTH 256 /* Types of message */ +#define DBUS_MESSAGE_TYPE_INVALID 0 #define DBUS_MESSAGE_TYPE_METHOD_CALL 1 #define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 #define DBUS_MESSAGE_TYPE_ERROR 3 -- cgit