*/
} HeaderField;
+#define BYTE_ORDER_OFFSET 0
+#define TYPE_OFFSET 1
+#define FLAGS_OFFSET 2
+#define VERSION_OFFSET 3
+
/**
* @brief Internals of DBusMessage
*
static dbus_bool_t
dbus_message_create_header (DBusMessage *message,
+ int type,
const char *name,
const char *service)
{
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;
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;
/**
- * 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
* @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;
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;
}
/**
- * 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;
}
/**
+ * 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;
}
/**
+ * 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.
*
* @param message the 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;
_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;
}
/**
* 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.
*/
{
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)
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);
_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");
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,
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);
#include "dbus-connection-internal.h"
#include "dbus-internals.h"
#include "dbus-hash.h"
+#include "dbus-protocol.h"
#include <string.h>
/**
(* 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
"org.freedesktop.Test.Foo",
NULL };
int i;
+ DBusMessage *message;
i = 0;
while (i < N_OBJECTS)
++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))
{