*
*/
+#include "activation.h"
#include "connection.h"
#include "driver.h"
+#include "dispatch.h"
#include "services.h"
-#include <dbus/dbus-message-internal.h>
-#include <dbus/dbus-internals.h>
+#include "utils.h"
#include <dbus/dbus-string.h>
+#include <dbus/dbus-internals.h>
#include <string.h>
-#define BUS_DRIVER_SERVICE_NAME "org.freedesktop.DBus"
-#define BUS_DRIVER_HELLO_NAME "org.freedesktop.DBus.Hello"
-#define BUS_DRIVER_WELCOME_NAME "org.freedesktop.DBus.Welcome"
-#define BUS_DRIVER_LIST_SERVICES_NAME "org.freedesktop.DBus.ListServices"
-#define BUS_DRIVER_SERVICES_NAME "org.freedesktop.DBus.Services"
+static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
+ DBusMessage *hello_message,
+ BusTransaction *transaction,
+ DBusError *error);
-#define BUS_DRIVER_SERVICE_CREATED_NAME "org.freedesktop.DBus.ServiceCreated"
-#define BUS_DRIVER_SERVICE_DELETED_NAME "org.freedesktop.DBus.ServiceDeleted"
+dbus_bool_t
+bus_driver_send_service_deleted (const char *service_name,
+ BusTransaction *transaction,
+ DBusError *error)
+{
+ DBusMessage *message;
+ dbus_bool_t retval;
-static dbus_bool_t bus_driver_send_welcome_message (DBusConnection *connection,
- DBusMessage *hello_message);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ _dbus_verbose ("sending service deleted: %s\n", service_name);
-static void
-send_one_message (DBusConnection *connection, void *data)
-{
- dbus_connection_send_message (connection, data, NULL, NULL);
+ message = dbus_message_new (DBUS_SERVICE_BROADCAST,
+ DBUS_MESSAGE_SERVICE_DELETED);
+ if (message == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
+ !dbus_message_append_args (message,
+ DBUS_TYPE_STRING, service_name,
+ 0))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ retval = bus_dispatch_broadcast_message (transaction, message, error);
+ dbus_message_unref (message);
+
+ return retval;
}
-static void
-bus_driver_broadcast_message (DBusMessage *message)
+dbus_bool_t
+bus_driver_send_service_created (const char *service_name,
+ BusTransaction *transaction,
+ DBusError *error)
{
- bus_connection_foreach (send_one_message, message);
+ DBusMessage *message;
+ dbus_bool_t retval;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ message = dbus_message_new (DBUS_SERVICE_BROADCAST,
+ DBUS_MESSAGE_SERVICE_CREATED);
+ if (message == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, service_name,
+ 0))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ retval = bus_dispatch_broadcast_message (transaction, message, error);
+ dbus_message_unref (message);
+
+ return retval;
}
-static dbus_bool_t
-bus_driver_send_service_created (DBusConnection *connection, const char *name)
+dbus_bool_t
+bus_driver_send_service_lost (DBusConnection *connection,
+ const char *service_name,
+ BusTransaction *transaction,
+ DBusError *error)
{
DBusMessage *message;
- message = dbus_message_new (NULL, BUS_DRIVER_SERVICE_CREATED_NAME);
-
- if (!message)
- return FALSE;
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ message = dbus_message_new (bus_connection_get_name (connection),
+ DBUS_MESSAGE_SERVICE_LOST);
+ if (message == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, service_name,
+ 0))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- if (!dbus_message_append_fields (message,
- DBUS_TYPE_STRING, name,
- 0))
+ if (!bus_transaction_send_message (transaction, connection, message))
{
dbus_message_unref (message);
+ BUS_SET_OOM (error);
return FALSE;
}
+ else
+ {
+ dbus_message_unref (message);
+ return TRUE;
+ }
+}
+
+dbus_bool_t
+bus_driver_send_service_acquired (DBusConnection *connection,
+ const char *service_name,
+ BusTransaction *transaction,
+ DBusError *error)
+{
+ DBusMessage *message;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- dbus_message_set_sender (message, BUS_DRIVER_SERVICE_NAME);
- bus_driver_broadcast_message (message);
- dbus_message_unref (message);
+ message = dbus_message_new (bus_connection_get_name (connection),
+ DBUS_MESSAGE_SERVICE_ACQUIRED);
+ if (message == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- return TRUE;
+ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, service_name,
+ 0))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!bus_transaction_send_message (transaction, connection, message))
+ {
+ dbus_message_unref (message);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+ else
+ {
+ dbus_message_unref (message);
+ return TRUE;
+ }
}
static dbus_bool_t
-create_unique_client_name (const char *name,
- DBusString *str)
+create_unique_client_name (BusRegistry *registry,
+ DBusString *str)
{
/* We never want to use the same unique client name twice, because
* we want to guarantee that if you send a message to a given unique
static int next_minor_number = 0;
int len;
- if (!_dbus_string_append (str, name))
- return FALSE;
-
len = _dbus_string_get_length (str);
while (TRUE)
next_minor_number += 1;
/* Check if a client with the name exists */
- if (bus_service_lookup (str, FALSE) == NULL)
+ if (bus_registry_lookup (registry, str) == NULL)
break;
/* drop the number again, try the next one. */
static dbus_bool_t
bus_driver_handle_hello (DBusConnection *connection,
- DBusMessage *message)
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
{
- DBusResultCode result;
- char *name;
DBusString unique_name;
BusService *service;
dbus_bool_t retval;
-
- result = dbus_message_get_fields (message,
- DBUS_TYPE_STRING, &name,
- 0);
-
- /* FIXME: Handle this in a better way */
- if (result != DBUS_RESULT_SUCCESS)
- return FALSE;
+ BusRegistry *registry;
- if (!_dbus_string_init (&unique_name, _DBUS_INT_MAX))
- return FALSE;
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- if (!create_unique_client_name (name, &unique_name))
+ if (!_dbus_string_init (&unique_name))
{
- _dbus_string_free (&unique_name);
+ BUS_SET_OOM (error);
return FALSE;
}
- /* Create the service */
- service = bus_service_lookup (&unique_name, TRUE);
- if (!service)
+ retval = FALSE;
+
+ registry = bus_connection_get_registry (connection);
+
+ if (!create_unique_client_name (registry, &unique_name))
{
- _dbus_string_free (&unique_name);
- return FALSE;
+ BUS_SET_OOM (error);
+ goto out_0;
}
- /* FIXME: Error checks from this point */
+ if (!bus_connection_set_name (connection, &unique_name))
+ {
+ BUS_SET_OOM (error);
+ goto out_0;
+ }
- /* Add the connection as the owner */
- bus_service_add_owner (service, connection);
- bus_connection_set_name (connection, &unique_name);
-
- /* We need to assign the sender to the message here */
- dbus_message_set_sender (message,
- bus_connection_get_name (connection));
+ if (!dbus_message_set_sender (message,
+ bus_connection_get_name (connection)))
+ {
+ BUS_SET_OOM (error);
+ goto out_0;
+ }
- _dbus_string_free (&unique_name);
-
- retval = bus_driver_send_welcome_message (connection, message);
+ if (!bus_driver_send_welcome_message (connection, message, transaction, error))
+ goto out_0;
- if (!retval)
- return FALSE;
+ /* Create the service */
+ service = bus_registry_ensure (registry,
+ &unique_name, connection, transaction, error);
+ if (service == NULL)
+ goto out_0;
- /* Broadcast a ServiceCreated message */
- retval = bus_driver_send_service_created (connection, bus_connection_get_name (connection));
+ bus_service_set_prohibit_replacement (service, TRUE);
+
+ retval = TRUE;
+ out_0:
+ _dbus_string_free (&unique_name);
return retval;
}
static dbus_bool_t
bus_driver_send_welcome_message (DBusConnection *connection,
- DBusMessage *hello_message)
+ DBusMessage *hello_message,
+ BusTransaction *transaction,
+ DBusError *error)
{
DBusMessage *welcome;
const char *name;
- dbus_bool_t retval;
-
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
name = bus_connection_get_name (connection);
_dbus_assert (name != NULL);
- welcome = dbus_message_new_reply (BUS_DRIVER_WELCOME_NAME,
- hello_message);
+ welcome = dbus_message_new_reply (hello_message);
if (welcome == NULL)
- return FALSE;
-
- /* FIXME: Return value */
- dbus_message_set_sender (welcome, BUS_DRIVER_SERVICE_NAME);
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- if (!dbus_message_append_fields (welcome,
- DBUS_TYPE_STRING, name,
- NULL))
+ if (!dbus_message_set_sender (welcome, DBUS_SERVICE_DBUS))
{
dbus_message_unref (welcome);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ if (!dbus_message_append_args (welcome,
+ DBUS_TYPE_STRING, name,
+ NULL))
+ {
+ dbus_message_unref (welcome);
+ BUS_SET_OOM (error);
return FALSE;
}
- retval = dbus_connection_send_message (connection, welcome, NULL, NULL);
- dbus_message_unref (welcome);
-
- return retval;
+ if (!bus_transaction_send_message (transaction, connection, welcome))
+ {
+ dbus_message_unref (welcome);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+ else
+ {
+ dbus_message_unref (welcome);
+ return TRUE;
+ }
}
-static void
+static dbus_bool_t
bus_driver_handle_list_services (DBusConnection *connection,
- DBusMessage *message)
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
{
DBusMessage *reply;
- int len, i;
+ int len;
char **services;
+ BusRegistry *registry;
- reply = dbus_message_new_reply (BUS_DRIVER_SERVICES_NAME, message);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ registry = bus_connection_get_registry (connection);
+
+ reply = dbus_message_new_reply (message);
if (reply == NULL)
- return;
-
- services = bus_services_list (&len);
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- if (!services)
- goto error;
+ if (!bus_registry_list_services (registry, &services, &len))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- if (!dbus_message_append_fields (reply,
- DBUS_TYPE_STRING_ARRAY, services, len,
- 0))
- goto error;
+ if (!dbus_message_append_args (reply,
+ DBUS_TYPE_STRING_ARRAY, services, len,
+ 0))
+ {
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
- if (!dbus_connection_send_message (connection, reply, NULL, NULL))
- goto error;
+ dbus_free_string_array (services);
- error:
- dbus_message_unref (reply);
- if (services != NULL)
+ if (!bus_transaction_send_message (transaction, connection, reply))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+ else
{
- for (i = 0; i < len; i++)
- dbus_free (services[i]);
- dbus_free (services);
+ dbus_message_unref (reply);
+ return TRUE;
}
}
-/* This is where all the magic occurs */
-static DBusHandlerResult
-bus_driver_message_handler (DBusMessageHandler *handler,
- DBusConnection *connection,
- DBusMessage *message,
- void *user_data)
+static dbus_bool_t
+bus_driver_handle_acquire_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
{
- const char *service, *name;
+ DBusMessage *reply;
+ DBusString service_name;
+ BusService *service;
+ char *name;
+ int service_reply;
+ int flags;
+ dbus_bool_t retval;
+ DBusConnection *old_owner;
+ DBusConnection *current_owner;
+ BusRegistry *registry;
- service = dbus_message_get_service (message);
- name = dbus_message_get_name (message);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ registry = bus_connection_get_registry (connection);
+
+ if (!dbus_message_get_args (message,
+ error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT32, &flags,
+ 0))
+ return FALSE;
+
+ _dbus_verbose ("Trying to own service %s with flags 0x%x\n", name, flags);
+
+ retval = FALSE;
+ reply = NULL;
- dbus_message_set_sender (message,
- bus_connection_get_name (connection));
+ _dbus_string_init_const (&service_name, name);
- if (strcmp (service, BUS_DRIVER_SERVICE_NAME) == 0)
+ service = bus_registry_lookup (registry, &service_name);
+
+ if (service != NULL)
+ old_owner = bus_service_get_primary_owner (service);
+ else
+ old_owner = NULL;
+
+ reply = dbus_message_new_reply (message);
+ if (reply == NULL)
{
- if (strcmp (name, BUS_DRIVER_HELLO_NAME) == 0)
- bus_driver_handle_hello (connection, message);
- else if (strcmp (name, BUS_DRIVER_LIST_SERVICES_NAME) == 0)
- bus_driver_handle_list_services (connection, message);
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (service == NULL)
+ {
+ service = bus_registry_ensure (registry,
+ &service_name, connection, transaction, error);
+ if (service == NULL)
+ goto out;
+ }
+
+ current_owner = bus_service_get_primary_owner (service);
+
+ if (old_owner == NULL)
+ {
+ _dbus_assert (current_owner == connection);
+
+ bus_service_set_prohibit_replacement (service,
+ (flags & DBUS_SERVICE_FLAG_PROHIBIT_REPLACEMENT));
+
+ service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
+ }
+ else if (old_owner == connection)
+ service_reply = DBUS_SERVICE_REPLY_ALREADY_OWNER;
+ else if (!((flags & DBUS_SERVICE_FLAG_REPLACE_EXISTING)))
+ service_reply = DBUS_SERVICE_REPLY_SERVICE_EXISTS;
+ else if (bus_service_get_prohibit_replacement (service))
+ {
+ /* Queue the connection */
+ if (!bus_service_add_owner (service, connection,
+ transaction, error))
+ goto out;
+
+ service_reply = DBUS_SERVICE_REPLY_IN_QUEUE;
}
else
{
- /* FIXME: Dispatch the message :-) */
+ /* Replace the current owner */
+
+ /* We enqueue the new owner and remove the first one because
+ * that will cause ServiceAcquired and ServiceLost messages to
+ * be sent.
+ */
+
+ /* FIXME this is broken, if the remove_owner fails
+ * we don't undo the add_owner
+ * (easiest fix is probably to move all this to
+ * services.c and have a single routine for it)
+ */
+
+ if (!bus_service_add_owner (service, connection,
+ transaction, error))
+ goto out;
+
+ if (!bus_service_remove_owner (service, old_owner,
+ transaction, error))
+ goto out;
+
+ _dbus_assert (connection == bus_service_get_primary_owner (service));
+ service_reply = DBUS_SERVICE_REPLY_PRIMARY_OWNER;
}
- return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
-}
+ if (!dbus_message_append_args (reply, DBUS_TYPE_UINT32, service_reply, 0))
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
-dbus_bool_t
-bus_driver_add_connection (DBusConnection *connection)
+ if (!bus_transaction_send_message (transaction, connection, reply))
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ retval = TRUE;
+
+ out:
+ dbus_free (name);
+ if (reply)
+ dbus_message_unref (reply);
+ return retval;
+}
+
+static dbus_bool_t
+bus_driver_handle_service_exists (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
{
- DBusMessageHandler *handler;
+ DBusMessage *reply;
+ DBusString service_name;
+ BusService *service;
+ char *name;
+ dbus_bool_t retval;
+ BusRegistry *registry;
- handler = dbus_message_handler_new (bus_driver_message_handler, NULL, NULL);
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+ registry = bus_connection_get_registry (connection);
+
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &name,
+ 0))
+ return FALSE;
- if (!dbus_connection_add_filter (connection, handler))
+ retval = FALSE;
+
+ _dbus_string_init_const (&service_name, name);
+ service = bus_registry_lookup (registry, &service_name);
+
+ reply = dbus_message_new_reply (message);
+ if (reply == NULL)
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
{
- dbus_message_handler_unref (handler);
+ BUS_SET_OOM (error);
+ goto out;
+ }
- return FALSE;
+ if (!dbus_message_append_args (reply,
+ DBUS_TYPE_UINT32, service != NULL,
+ 0))
+ {
+ BUS_SET_OOM (error);
+ goto out;
+ }
+
+ if (!bus_transaction_send_message (transaction, connection, reply))
+ {
+ BUS_SET_OOM (error);
+ goto out;
}
- /* FIXME we are leaking the DBusMessageHandler */
+ retval = TRUE;
+
+ out:
+ if (reply)
+ dbus_message_unref (reply);
+ dbus_free (name);
+
+ return retval;
+}
+
+static dbus_bool_t
+bus_driver_handle_activate_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ dbus_uint32_t flags;
+ char *name;
+ dbus_bool_t retval;
+ BusActivation *activation;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- _dbus_verbose ("D-Bus driver on board...\n");
+ activation = bus_connection_get_activation (connection);
- return TRUE;
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT32, &flags,
+ 0))
+ return FALSE;
+
+ retval = FALSE;
+
+ if (!bus_activation_activate_service (activation, connection, transaction,
+ message, name, error))
+ goto out;
+
+ retval = TRUE;
+
+ out:
+ dbus_free (name);
+ return retval;
}
-void
-bus_driver_remove_connection (DBusConnection *connection)
+/* For speed it might be useful to sort this in order of
+ * frequency of use (but doesn't matter with only a few items
+ * anyhow)
+ */
+struct
{
- BusService *service;
- DBusString service_name;
const char *name;
+ dbus_bool_t (* handler) (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+} message_handlers[] = {
+ { DBUS_MESSAGE_ACQUIRE_SERVICE, bus_driver_handle_acquire_service },
+ { DBUS_MESSAGE_ACTIVATE_SERVICE, bus_driver_handle_activate_service },
+ { DBUS_MESSAGE_HELLO, bus_driver_handle_hello },
+ { DBUS_MESSAGE_SERVICE_EXISTS, bus_driver_handle_service_exists },
+ { DBUS_MESSAGE_LIST_SERVICES, bus_driver_handle_list_services }
+};
- name = bus_connection_get_name (connection);
+dbus_bool_t
+bus_driver_handle_message (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+{
+ const char *name, *sender;
+ int i;
- if (name == NULL)
- return;
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
- _dbus_string_init_const (&service_name, name);
+ _dbus_verbose ("Driver got a message: %s\n",
+ dbus_message_get_name (message));
- service = bus_service_lookup (&service_name, FALSE);
+ name = dbus_message_get_name (message);
+ sender = dbus_message_get_sender (message);
+
+ if (sender == NULL && (strcmp (name, DBUS_MESSAGE_HELLO) != 0))
+ {
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Client tried to send a message other than %s without being registered",
+ DBUS_MESSAGE_HELLO);
- if (service)
- bus_service_free (service);
+ dbus_connection_disconnect (connection);
+ return FALSE;
+ }
+
+ i = 0;
+ while (i < _DBUS_N_ELEMENTS (message_handlers))
+ {
+ if (strcmp (message_handlers[i].name, name) == 0)
+ {
+ if ((* message_handlers[i].handler) (connection, transaction, message, error))
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ ++i;
+ }
+
+ dbus_set_error (error, DBUS_ERROR_UNKNOWN_MESSAGE,
+ "%s does not understand message %s",
+ DBUS_SERVICE_DBUS, name);
+
+ return FALSE;
+}
+
+void
+bus_driver_remove_connection (DBusConnection *connection)
+{
+ /* FIXME Does nothing for now, should unregister the connection
+ * with the bus driver.
+ */
}