Move _dbus_check_fdleaks_enter to dbus-message-internal.h
[platform/upstream/dbus.git] / bus / driver.c
index 4a6a324..574e0f3 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
  *
  * Licensed under the Academic Free License version 2.1
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
- * 
+ *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
 #include "activation.h"
 #include "connection.h"
 #include "driver.h"
 #include "services.h"
 #include "selinux.h"
 #include "signals.h"
+#include "stats.h"
 #include "utils.h"
 #include <dbus/dbus-string.h>
 #include <dbus/dbus-internals.h>
+#include <dbus/dbus-message.h>
 #include <dbus/dbus-marshal-recursive.h>
 #include <string.h>
 
@@ -55,20 +58,20 @@ bus_driver_send_service_owner_changed (const char     *service_name,
 
   null_service = "";
   _dbus_verbose ("sending name owner changed: %s [%s -> %s]\n",
-                 service_name, 
-                 old_owner ? old_owner : null_service, 
+                 service_name,
+                 old_owner ? old_owner : null_service,
                  new_owner ? new_owner : null_service);
 
   message = dbus_message_new_signal (DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "NameOwnerChanged");
-  
+
   if (message == NULL)
     {
       BUS_SET_OOM (error);
       return FALSE;
     }
-  
+
   if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
     goto oom;
 
@@ -80,7 +83,7 @@ bus_driver_send_service_owner_changed (const char     *service_name,
     goto oom;
 
   _dbus_assert (dbus_message_has_signature (message, "sss"));
-  
+
   retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
   dbus_message_unref (message);
 
@@ -101,17 +104,17 @@ bus_driver_send_service_lost (DBusConnection *connection,
   DBusMessage *message;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   message = dbus_message_new_signal (DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "NameLost");
-  
+
   if (message == NULL)
     {
       BUS_SET_OOM (error);
       return FALSE;
     }
-  
+
   if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
       !dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &service_name,
@@ -144,7 +147,7 @@ bus_driver_send_service_acquired (DBusConnection *connection,
   DBusMessage *message;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   message = dbus_message_new_signal (DBUS_PATH_DBUS,
                                      DBUS_INTERFACE_DBUS,
                                      "NameAcquired");
@@ -154,7 +157,7 @@ bus_driver_send_service_acquired (DBusConnection *connection,
       BUS_SET_OOM (error);
       return FALSE;
     }
-  
+
   if (!dbus_message_set_destination (message, bus_connection_get_name (connection)) ||
       !dbus_message_append_args (message,
                                  DBUS_TYPE_STRING, &service_name,
@@ -192,9 +195,9 @@ create_unique_client_name (BusRegistry *registry,
   static int next_major_number = 0;
   static int next_minor_number = 0;
   int len;
-  
+
   len = _dbus_string_get_length (str);
-  
+
   while (TRUE)
     {
       /* start out with 1-0, go to 1-1, 1-2, 1-3,
@@ -212,21 +215,21 @@ create_unique_client_name (BusRegistry *registry,
       _dbus_assert (next_minor_number >= 0);
 
       /* appname:MAJOR-MINOR */
-      
+
       if (!_dbus_string_append (str, ":"))
         return FALSE;
-      
+
       if (!_dbus_string_append_int (str, next_major_number))
         return FALSE;
 
       if (!_dbus_string_append (str, "."))
         return FALSE;
-      
+
       if (!_dbus_string_append_int (str, next_minor_number))
         return FALSE;
 
       next_minor_number += 1;
-      
+
       /* Check if a client with the name exists */
       if (bus_registry_lookup (registry, str) == NULL)
        break;
@@ -273,7 +276,7 @@ bus_driver_handle_hello (DBusConnection *connection,
       _DBUS_ASSERT_ERROR_IS_SET (error);
       return FALSE;
     }
-  
+
   if (!_dbus_string_init (&unique_name))
     {
       BUS_SET_OOM (error);
@@ -283,7 +286,7 @@ bus_driver_handle_hello (DBusConnection *connection,
   retval = FALSE;
 
   registry = bus_connection_get_registry (connection);
-  
+
   if (!create_unique_client_name (registry, &unique_name))
     {
       BUS_SET_OOM (error);
@@ -295,14 +298,14 @@ bus_driver_handle_hello (DBusConnection *connection,
       _DBUS_ASSERT_ERROR_IS_SET (error);
       goto out_0;
     }
-  
+
   if (!dbus_message_set_sender (message,
                                 bus_connection_get_name (connection)))
     {
       BUS_SET_OOM (error);
       goto out_0;
     }
-  
+
   if (!bus_driver_send_welcome_message (connection, message, transaction, error))
     goto out_0;
 
@@ -311,10 +314,10 @@ bus_driver_handle_hello (DBusConnection *connection,
                                  &unique_name, connection, 0, transaction, error);
   if (service == NULL)
     goto out_0;
-  
+
   _dbus_assert (bus_connection_is_active (connection));
   retval = TRUE;
-  
+
  out_0:
   _dbus_string_free (&unique_name);
   return retval;
@@ -330,17 +333,17 @@ bus_driver_send_welcome_message (DBusConnection *connection,
   const char *name;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   name = bus_connection_get_name (connection);
   _dbus_assert (name != NULL);
-  
+
   welcome = dbus_message_new_method_return (hello_message);
   if (welcome == NULL)
     {
       BUS_SET_OOM (error);
       return FALSE;
     }
-  
+
   if (!dbus_message_append_args (welcome,
                                  DBUS_TYPE_STRING, &name,
                                  DBUS_TYPE_INVALID))
@@ -351,7 +354,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
     }
 
   _dbus_assert (dbus_message_has_signature (welcome, DBUS_TYPE_STRING_AS_STRING));
-  
+
   if (!bus_transaction_send_from_driver (transaction, connection, welcome))
     {
       dbus_message_unref (welcome);
@@ -380,9 +383,9 @@ bus_driver_handle_list_services (DBusConnection *connection,
   DBusMessageIter sub;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   registry = bus_connection_get_registry (connection);
-  
+
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     {
@@ -398,7 +401,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
     }
 
   dbus_message_iter_init_append (reply, &iter);
-  
+
   if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY,
                                          DBUS_TYPE_STRING_AS_STRING,
                                          &sub))
@@ -421,7 +424,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
         return FALSE;
       }
   }
-  
+
   i = 0;
   while (i < len)
     {
@@ -444,7 +447,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
       BUS_SET_OOM (error);
       return FALSE;
     }
-  
+
   if (!bus_transaction_send_from_driver (transaction, connection, reply))
     {
       dbus_message_unref (reply);
@@ -566,17 +569,17 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
   BusRegistry *registry;
 
   _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,
                               DBUS_TYPE_INVALID))
     return FALSE;
-  
+
   _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
-  
+
   retval = FALSE;
   reply = NULL;
 
@@ -587,7 +590,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
                                      &service_reply, transaction,
                                      error))
     goto out;
-  
+
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     {
@@ -608,12 +611,12 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
     }
 
   retval = TRUE;
-  
+
  out:
   if (reply)
     dbus_message_unref (reply);
   return retval;
-} 
+}
 
 static dbus_bool_t
 bus_driver_handle_release_service (DBusConnection *connection,
@@ -691,9 +694,9 @@ bus_driver_handle_service_exists (DBusConnection *connection,
   BusRegistry *registry;
 
   _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_INVALID))
@@ -711,7 +714,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
       service = bus_registry_lookup (registry, &service_name);
       service_exists = service != NULL;
     }
-  
+
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     {
@@ -734,7 +737,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
     }
 
   retval = TRUE;
-  
+
  out:
   if (reply)
     dbus_message_unref (reply);
@@ -754,9 +757,9 @@ bus_driver_handle_activate_service (DBusConnection *connection,
   BusActivation *activation;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   activation = bus_connection_get_activation (connection);
-  
+
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &name,
                               DBUS_TYPE_UINT32, &flags,
@@ -778,7 +781,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
     }
 
   retval = TRUE;
-  
+
  out:
   return retval;
 }
@@ -791,6 +794,9 @@ send_ack_reply (DBusConnection *connection,
 {
   DBusMessage *reply;
 
+  if (dbus_message_get_no_reply (message))
+    return TRUE;
+
   reply = dbus_message_new_method_return (message);
   if (reply == NULL)
     {
@@ -806,7 +812,7 @@ send_ack_reply (DBusConnection *connection,
     }
 
   dbus_message_unref (reply);
-  
+
   return TRUE;
 }
 
@@ -821,7 +827,6 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
   DBusMessageIter iter;
   DBusMessageIter dict_iter;
   DBusMessageIter dict_entry_iter;
-  int msg_type;
   int array_type;
   int key_type;
   DBusList *keys, *key_link;
@@ -836,9 +841,13 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
   /* The message signature has already been checked for us,
    * so let's just assert it's right.
    */
-  msg_type = dbus_message_iter_get_arg_type (&iter);
+#ifndef DBUS_DISABLE_ASSERT
+    {
+      int msg_type = dbus_message_iter_get_arg_type (&iter);
 
-  _dbus_assert (msg_type == DBUS_TYPE_ARRAY);
+      _dbus_assert (msg_type == DBUS_TYPE_ARRAY);
+    }
+#endif
 
   dbus_message_iter_recurse (&iter, &dict_iter);
 
@@ -947,7 +956,7 @@ bus_driver_handle_add_match (DBusConnection *connection,
   const char *text;
   DBusString str;
   BusMatchmaker *matchmaker;
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   text = NULL;
@@ -964,7 +973,7 @@ bus_driver_handle_add_match (DBusConnection *connection,
                       "(inactive)");
       goto failed;
     }
-  
+
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &text,
                               DBUS_TYPE_INVALID))
@@ -993,9 +1002,9 @@ bus_driver_handle_add_match (DBusConnection *connection,
       bus_matchmaker_remove_rule (matchmaker, rule);
       goto failed;
     }
-  
+
   bus_match_rule_unref (rule);
-  
+
   return TRUE;
 
  failed:
@@ -1015,12 +1024,12 @@ bus_driver_handle_remove_match (DBusConnection *connection,
   const char *text;
   DBusString str;
   BusMatchmaker *matchmaker;
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   text = NULL;
   rule = NULL;
-  
+
   if (!dbus_message_get_args (message, error,
                               DBUS_TYPE_STRING, &text,
                               DBUS_TYPE_INVALID))
@@ -1041,14 +1050,14 @@ bus_driver_handle_remove_match (DBusConnection *connection,
   if (!send_ack_reply (connection, transaction,
                        message, error))
     goto failed;
-  
+
   matchmaker = bus_connection_get_matchmaker (connection);
 
   if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
     goto failed;
 
   bus_match_rule_unref (rule);
-  
+
   return TRUE;
 
  failed:
@@ -1070,7 +1079,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
   BusRegistry *registry;
   BusService *service;
   DBusMessage *reply;
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   registry = bus_connection_get_registry (connection);
@@ -1093,7 +1102,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
     }
   else if (service == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                       DBUS_ERROR_NAME_HAS_NO_OWNER,
                       "Could not get owner of name '%s': no such name", text);
       goto failed;
@@ -1109,7 +1118,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
                           "Could not determine unique name for '%s'", text);
           goto failed;
         }
-      _dbus_assert (*base_name == ':');      
+      _dbus_assert (*base_name == ':');
     }
 
   _dbus_assert (base_name != NULL);
@@ -1118,11 +1127,11 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
   if (reply == NULL)
     goto oom;
 
-  if (! dbus_message_append_args (reply, 
+  if (! dbus_message_append_args (reply,
                                  DBUS_TYPE_STRING, &base_name,
                                  DBUS_TYPE_INVALID))
     goto oom;
-  
+
   if (! bus_transaction_send_from_driver (transaction, connection, reply))
     goto oom;
 
@@ -1155,7 +1164,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
   DBusMessage *reply;
   DBusMessageIter iter, array_iter;
   char *dbus_service_name = DBUS_SERVICE_DBUS;
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   registry = bus_connection_get_registry (connection);
@@ -1180,14 +1189,14 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
     }
   else if (service == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                       DBUS_ERROR_NAME_HAS_NO_OWNER,
                       "Could not get owners of name '%s': no such name", text);
       goto failed;
     }
   else
     {
-      if (!bus_service_list_queued_owners (service, 
+      if (!bus_service_list_queued_owners (service,
                                            &base_names,
                                            error))
         goto failed;
@@ -1205,7 +1214,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
                                          DBUS_TYPE_STRING_AS_STRING,
                                          &array_iter))
     goto oom;
-  
+
   link = _dbus_list_get_first_link (&base_names);
   while (link != NULL)
     {
@@ -1213,8 +1222,8 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
 
       _dbus_assert (link->data != NULL);
       uname = (char *)link->data;
-    
-      if (!dbus_message_iter_append_basic (&array_iter, 
+
+      if (!dbus_message_iter_append_basic (&array_iter,
                                            DBUS_TYPE_STRING,
                                            &uname))
         goto oom;
@@ -1224,8 +1233,8 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
 
   if (! dbus_message_iter_close_container (&iter, &array_iter))
     goto oom;
-                                    
+
+
   if (! bus_transaction_send_from_driver (transaction, connection, reply))
     goto oom;
 
@@ -1280,7 +1289,7 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
   serv = bus_registry_lookup (registry, &str);
   if (serv == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                      DBUS_ERROR_NAME_HAS_NO_OWNER,
                      "Could not get UID of name '%s': no such name", service);
       goto failed;
@@ -1356,7 +1365,7 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
   serv = bus_registry_lookup (registry, &str);
   if (serv == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                      DBUS_ERROR_NAME_HAS_NO_OWNER,
                      "Could not get PID of name '%s': no such name", service);
       goto failed;
@@ -1432,7 +1441,7 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
   serv = bus_registry_lookup (registry, &str);
   if (serv == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                      DBUS_ERROR_NAME_HAS_NO_OWNER,
                      "Could not get audit session data for name '%s': no such name", service);
       goto failed;
@@ -1506,7 +1515,7 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
   serv = bus_registry_lookup (registry, &str);
   if (serv == NULL)
     {
-      dbus_set_error (error, 
+      dbus_set_error (error,
                      DBUS_ERROR_NAME_HAS_NO_OWNER,
                      "Could not get security context of name '%s': no such name", service);
       goto failed;
@@ -1559,7 +1568,7 @@ bus_driver_handle_reload_config (DBusConnection *connection,
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
-  
+
   context = bus_connection_get_context (connection);
   if (!bus_context_reload_config (context, error))
     goto failed;
@@ -1604,7 +1613,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
     }
 
   reply = NULL;
-  
+
   context = bus_connection_get_context (connection);
   if (!bus_context_get_id (context, &uuid))
     goto oom;
@@ -1618,32 +1627,28 @@ bus_driver_handle_get_id (DBusConnection *connection,
                                  DBUS_TYPE_STRING, &v_STRING,
                                  DBUS_TYPE_INVALID))
     goto oom;
-  
+
   _dbus_assert (dbus_message_has_signature (reply, "s"));
-  
+
   if (! bus_transaction_send_from_driver (transaction, connection, reply))
     goto oom;
 
-  _dbus_string_free (&uuid);  
+  _dbus_string_free (&uuid);
   dbus_message_unref (reply);
   return TRUE;
 
  oom:
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
-  
+
   BUS_SET_OOM (error);
 
   if (reply)
     dbus_message_unref (reply);
-  _dbus_string_free (&uuid);  
+  _dbus_string_free (&uuid);
   return FALSE;
 }
 
-/* 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)
- */
-static struct
+typedef struct
 {
   const char *name;
   const char *in_args;
@@ -1652,11 +1657,17 @@ static struct
                            BusTransaction *transaction,
                            DBusMessage    *message,
                            DBusError      *error);
-} message_handlers[] = {
+} MessageHandler;
+
+/* 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)
+ */
+static const MessageHandler dbus_message_handlers[] = {
   { "Hello",
     "",
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_hello },  
+    bus_driver_handle_hello },
   { "RequestName",
     DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_UINT32_AS_STRING,
     DBUS_TYPE_UINT32_AS_STRING,
@@ -1724,7 +1735,52 @@ static struct
   { "GetId",
     "",
     DBUS_TYPE_STRING_AS_STRING,
-    bus_driver_handle_get_id }
+    bus_driver_handle_get_id },
+  { NULL, NULL, NULL, NULL }
+};
+
+static dbus_bool_t bus_driver_handle_introspect (DBusConnection *,
+    BusTransaction *, DBusMessage *, DBusError *);
+
+static const MessageHandler introspectable_message_handlers[] = {
+  { "Introspect", "", DBUS_TYPE_STRING_AS_STRING, bus_driver_handle_introspect },
+  { NULL, NULL, NULL, NULL }
+};
+
+#ifdef DBUS_ENABLE_STATS
+static const MessageHandler stats_message_handlers[] = {
+  { "GetStats", "", "a{sv}", bus_stats_handle_get_stats },
+  { "GetConnectionStats", "s", "a{sv}", bus_stats_handle_get_connection_stats },
+  { NULL, NULL, NULL, NULL }
+};
+#endif
+
+typedef struct {
+  const char *name;
+  const MessageHandler *message_handlers;
+  const char *extra_introspection;
+} InterfaceHandler;
+
+/* These should ideally be sorted by frequency of use, although it
+ * probably doesn't matter with this few items */
+static InterfaceHandler interface_handlers[] = {
+  { DBUS_INTERFACE_DBUS, dbus_message_handlers,
+    "    <signal name=\"NameOwnerChanged\">\n"
+    "      <arg type=\"s\"/>\n"
+    "      <arg type=\"s\"/>\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n"
+    "    <signal name=\"NameLost\">\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n"
+    "    <signal name=\"NameAcquired\">\n"
+    "      <arg type=\"s\"/>\n"
+    "    </signal>\n" },
+  { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
+#ifdef DBUS_ENABLE_STATS
+  { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
+#endif
+  { NULL, NULL, NULL }
 };
 
 static dbus_bool_t
@@ -1735,10 +1791,10 @@ write_args_for_direction (DBusString *xml,
   DBusTypeReader typereader;
   DBusString sigstr;
   int current_type;
-  
+
   _dbus_string_init_const (&sigstr, signature);
   _dbus_type_reader_init_types_only (&typereader, &sigstr, 0);
-      
+
   while ((current_type = _dbus_type_reader_get_current_type (&typereader)) != DBUS_TYPE_INVALID)
     {
       const DBusString *subsig;
@@ -1765,87 +1821,44 @@ write_args_for_direction (DBusString *xml,
 dbus_bool_t
 bus_driver_generate_introspect_string (DBusString *xml)
 {
-  int i;
+  const InterfaceHandler *ih;
+  const MessageHandler *mh;
 
   if (!_dbus_string_append (xml, DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE))
     return FALSE;
   if (!_dbus_string_append (xml, "<node>\n"))
     return FALSE;
-  if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n", DBUS_INTERFACE_INTROSPECTABLE))
-    return FALSE;
-  if (!_dbus_string_append (xml, "    <method name=\"Introspect\">\n"))
-    return FALSE;
-  if (!_dbus_string_append_printf (xml, "      <arg name=\"data\" direction=\"out\" type=\"%s\"/>\n", DBUS_TYPE_STRING_AS_STRING))
-    return FALSE;
-  if (!_dbus_string_append (xml, "    </method>\n"))
-    return FALSE;
-  if (!_dbus_string_append (xml, "  </interface>\n"))
-    return FALSE;
 
-  if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n",
-                                   DBUS_INTERFACE_DBUS))
-    return FALSE;
-
-  i = 0;
-  while (i < _DBUS_N_ELEMENTS (message_handlers))
+  for (ih = interface_handlers; ih->name != NULL; ih++)
     {
-         
-      if (!_dbus_string_append_printf (xml, "    <method name=\"%s\">\n",
-                                       message_handlers[i].name))
+      if (!_dbus_string_append_printf (xml, "  <interface name=\"%s\">\n",
+                                       ih->name))
         return FALSE;
 
-      if (!write_args_for_direction (xml, message_handlers[i].in_args, TRUE))
-       return FALSE;
-
-      if (!write_args_for_direction (xml, message_handlers[i].out_args, FALSE))
-       return FALSE;
-
-      if (!_dbus_string_append (xml, "    </method>\n"))
-       return FALSE;
-      
-      ++i;
-    }
-
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameOwnerChanged\">\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
-
+      for (mh = ih->message_handlers; mh->name != NULL; mh++)
+        {
+          if (!_dbus_string_append_printf (xml, "    <method name=\"%s\">\n",
+                                           mh->name))
+            return FALSE;
 
+          if (!write_args_for_direction (xml, mh->in_args, TRUE))
+            return FALSE;
 
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameLost\">\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
+          if (!write_args_for_direction (xml, mh->out_args, FALSE))
+            return FALSE;
 
+          if (!_dbus_string_append (xml, "    </method>\n"))
+            return FALSE;
+        }
 
+      if (ih->extra_introspection != NULL &&
+          !_dbus_string_append (xml, ih->extra_introspection))
+        return FALSE;
 
-  if (!_dbus_string_append_printf (xml, "    <signal name=\"NameAcquired\">\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "      <arg type=\"s\"/>\n"))
-    return FALSE;
-  
-  if (!_dbus_string_append_printf (xml, "    </signal>\n"))
-    return FALSE;
+      if (!_dbus_string_append (xml, "  </interface>\n"))
+        return FALSE;
+    }
 
-  if (!_dbus_string_append (xml, "  </interface>\n"))
-    return FALSE;
-  
   if (!_dbus_string_append (xml, "</node>\n"))
     return FALSE;
 
@@ -1863,7 +1876,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
   const char *v_STRING;
 
   _dbus_verbose ("Introspect() on bus driver\n");
-  
+
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
   reply = NULL;
@@ -1910,7 +1923,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
     dbus_message_unref (reply);
 
   _dbus_string_free (&xml);
-  
+
   return FALSE;
 }
 
@@ -1920,68 +1933,75 @@ bus_driver_handle_message (DBusConnection *connection,
                           DBusMessage    *message,
                            DBusError      *error)
 {
-  const char *name, *sender, *interface;
-  int i;
+  const char *name, *interface;
+  const InterfaceHandler *ih;
+  const MessageHandler *mh;
+  dbus_bool_t found_interface = FALSE;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
+  if (dbus_message_is_signal (message, "org.freedesktop.systemd1.Activator", "ActivationFailure"))
+    {
+      BusContext *context;
+
+      context = bus_connection_get_context (connection);
+      return dbus_activation_systemd_failure(bus_context_get_activation(context), message);
+    }
+
   if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
     {
       _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
       return TRUE; /* we just ignore this */
     }
 
-  if (dbus_message_is_method_call (message,
-                                   DBUS_INTERFACE_INTROSPECTABLE,
-                                   "Introspect"))
-    return bus_driver_handle_introspect (connection, transaction, message, error);
-  
+  /* may be NULL, which means "any interface will do" */
   interface = dbus_message_get_interface (message);
-  if (interface == NULL)
-    interface = DBUS_INTERFACE_DBUS;
-  
+
   _dbus_assert (dbus_message_get_member (message) != NULL);
-  
+
   name = dbus_message_get_member (message);
-  sender = dbus_message_get_sender (message);
-  
-  if (strcmp (interface,
-              DBUS_INTERFACE_DBUS) != 0)
-    {
-      _dbus_verbose ("Driver got message to unknown interface \"%s\"\n",
-                     interface);
-      goto unknown;
-    }
-  
-  _dbus_verbose ("Driver got a method call: %s\n",
-                dbus_message_get_member (message));
-  
+
+  _dbus_verbose ("Driver got a method call: %s\n", name);
+
   /* security checks should have kept this from getting here */
-  _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
-  
-  i = 0;
-  while (i < _DBUS_N_ELEMENTS (message_handlers))
+#ifndef DBUS_DISABLE_ASSERT
     {
-      if (strcmp (message_handlers[i].name, name) == 0)
+      const char *sender = dbus_message_get_sender (message);
+
+      _dbus_assert (sender != NULL || strcmp (name, "Hello") == 0);
+    }
+#endif
+
+  for (ih = interface_handlers; ih->name != NULL; ih++)
+    {
+      if (interface != NULL && strcmp (interface, ih->name) != 0)
+        continue;
+
+      found_interface = TRUE;
+
+      for (mh = ih->message_handlers; mh->name != NULL; mh++)
         {
+          if (strcmp (mh->name, name) != 0)
+            continue;
+
           _dbus_verbose ("Found driver handler for %s\n", name);
 
-          if (!dbus_message_has_signature (message, message_handlers[i].in_args))
+          if (!dbus_message_has_signature (message, mh->in_args))
             {
               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
               _dbus_verbose ("Call to %s has wrong args (%s, expected %s)\n",
                              name, dbus_message_get_signature (message),
-                             message_handlers[i].in_args);
-              
+                             mh->in_args);
+
               dbus_set_error (error, DBUS_ERROR_INVALID_ARGS,
                               "Call to %s has wrong args (%s, expected %s)\n",
                               name, dbus_message_get_signature (message),
-                              message_handlers[i].in_args);
+                              mh->in_args);
               _DBUS_ASSERT_ERROR_IS_SET (error);
               return FALSE;
             }
-          
-          if ((* message_handlers[i].handler) (connection, transaction, message, error))
+
+          if ((* mh->handler) (connection, transaction, message, error))
             {
               _DBUS_ASSERT_ERROR_IS_CLEAR (error);
               _dbus_verbose ("Driver handler succeeded\n");
@@ -1994,18 +2014,15 @@ bus_driver_handle_message (DBusConnection *connection,
               return FALSE;
             }
         }
-      
-      ++i;
     }
 
- unknown:
   _dbus_verbose ("No driver handler for message \"%s\"\n",
                  name);
 
-  dbus_set_error (error, DBUS_ERROR_UNKNOWN_METHOD,
+  dbus_set_error (error, found_interface ? DBUS_ERROR_UNKNOWN_METHOD : DBUS_ERROR_UNKNOWN_INTERFACE,
                   "%s does not understand message %s",
                   DBUS_SERVICE_DBUS, name);
-  
+
   return FALSE;
 }