aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch3201
-rw-r--r--recipes-core-ivi/dbus/dbus_1.6.4.bbappend3
2 files changed, 3204 insertions, 0 deletions
diff --git a/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch b/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch
new file mode 100644
index 0000000..2e91507
--- /dev/null
+++ b/recipes-core-ivi/dbus/dbus/dbus_1.6-add-afbus-support.patch
@@ -0,0 +1,3201 @@
+diff --git a/bus/Makefile.am b/bus/Makefile.am
+index 6cbc09a..cf3a962 100644
+--- a/bus/Makefile.am
++++ b/bus/Makefile.am
+@@ -63,6 +63,15 @@ endif
+ endif
+ endif
+
++if HAVE_AFBUS
++AFBUS_SOURCE = \
++ driver-afbus.c \
++ driver-afbus.h \
++ $(NULL)
++else
++AFBUS_SOURCE =
++endif
++
+ BUS_SOURCES= \
+ activation.c \
+ activation.h \
+@@ -83,6 +92,7 @@ BUS_SOURCES= \
+ dispatch.h \
+ driver.c \
+ driver.h \
++ $(AFBUS_SOURCE) \
+ expirelist.c \
+ expirelist.h \
+ policy.c \
+diff --git a/bus/bus.c b/bus/bus.c
+index e80e708..5038958 100644
+--- a/bus/bus.c
++++ b/bus/bus.c
+@@ -52,11 +52,20 @@ struct BusContext
+ char *type;
+ char *servicehelper;
+ char *address;
++
++ /* if we are in AF_BUS compat mode, contains the AF_BUS address */
++ char *main_address;
++
+ char *pidfile;
+ char *user;
+ char *log_prefix;
+ DBusLoop *loop;
+ DBusList *servers;
++
++ /* One of the servers may be a AF_BUS server. We can have at most only one
++ * AF_BUS server. */
++ DBusServer *main_afbus_server;
++
+ BusConnections *connections;
+ BusActivation *activation;
+ BusRegistry *registry;
+@@ -207,6 +216,29 @@ free_server_data (void *data)
+ dbus_free (bd);
+ }
+
++static void
++shutdown_server (BusContext *context,
++ DBusServer *server)
++{
++ if (server == NULL ||
++ !dbus_server_get_is_connected (server))
++ return;
++
++ if (!dbus_server_set_watch_functions (server,
++ NULL, NULL, NULL,
++ context,
++ NULL))
++ _dbus_assert_not_reached ("setting watch functions to NULL failed");
++
++ if (!dbus_server_set_timeout_functions (server,
++ NULL, NULL, NULL,
++ context,
++ NULL))
++ _dbus_assert_not_reached ("setting timeout functions to NULL failed");
++
++ dbus_server_disconnect (server);
++}
++
+ static dbus_bool_t
+ setup_server (BusContext *context,
+ DBusServer *server,
+@@ -275,6 +307,7 @@ process_config_first_time_only (BusContext *context,
+ DBusString log_prefix;
+ DBusList *link;
+ DBusList **addresses;
++ DBusList **addresses_if_possible;
+ const char *user, *pidfile;
+ char **auth_mechanisms;
+ DBusList **auth_mechanisms_list;
+@@ -448,6 +481,7 @@ process_config_first_time_only (BusContext *context,
+ while (link != NULL)
+ {
+ DBusServer *server;
++ dbus_bool_t is_afbus;
+
+ server = dbus_server_listen (link->data, error);
+ if (server == NULL)
+@@ -455,17 +489,78 @@ process_config_first_time_only (BusContext *context,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
+- else if (!setup_server (context, server, auth_mechanisms, error))
++ is_afbus = dbus_server_is_afbus (server);
++
++ /* Only accept one AF_BUS server */
++ if (is_afbus && context->main_afbus_server != NULL)
+ {
++ dbus_server_disconnect (server);
++ dbus_server_unref (server);
++ dbus_set_error (error,
++ DBUS_ERROR_MULTIPLE_AFBUS,
++ "Cannot listen on multiple AF_BUS address");
++ goto failed;
++ }
++
++ if (!setup_server (context, server, auth_mechanisms, error))
++ {
++ shutdown_server (context, server);
++ dbus_server_unref (server);
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ goto failed;
+ }
++ if (is_afbus)
++ context->main_afbus_server = server;
+
+ if (!_dbus_list_append (&context->servers, server))
+ goto oom;
+
+ link = _dbus_list_get_next_link (addresses, link);
+ }
++
++ addresses_if_possible =
++ bus_config_parser_get_addresses_if_possible (parser);
++
++ link = _dbus_list_get_first_link (addresses_if_possible);
++ while (link != NULL)
++ {
++ DBusServer *server;
++ dbus_bool_t is_afbus;
++
++ server = dbus_server_listen (link->data, NULL);
++ if (server == NULL)
++ {
++ link = _dbus_list_get_next_link (addresses_if_possible, link);
++ continue;
++ }
++ is_afbus = dbus_server_is_afbus (server);
++
++ /* Only accept one AF_BUS server */
++ if (is_afbus && context->main_afbus_server != NULL)
++ {
++ dbus_server_disconnect (server);
++ dbus_server_unref (server);
++
++ link = _dbus_list_get_next_link (addresses_if_possible, link);
++ continue;
++ }
++
++ if (!setup_server (context, server, auth_mechanisms, NULL))
++ {
++ shutdown_server (context, server);
++ dbus_server_unref (server);
++
++ link = _dbus_list_get_next_link (addresses_if_possible, link);
++ continue;
++ }
++ if (is_afbus)
++ context->main_afbus_server = server;
++
++ if (!_dbus_list_append (&context->servers, server))
++ goto oom;
++
++ link = _dbus_list_get_next_link (addresses_if_possible, link);
++ }
+ }
+
+ context->fork = bus_config_parser_get_fork (parser);
+@@ -499,6 +594,7 @@ process_config_every_time (BusContext *context,
+ DBusError *error)
+ {
+ DBusString full_address;
++ DBusString main_address;
+ DBusList *link;
+ DBusList **dirs;
+ char *addr;
+@@ -518,6 +614,12 @@ process_config_every_time (BusContext *context,
+ return FALSE;
+ }
+
++ if (!_dbus_string_init (&main_address))
++ {
++ BUS_SET_OOM (error);
++ return FALSE;
++ }
++
+ /* get our limits and timeout lengths */
+ bus_config_parser_get_limits (parser, &context->limits);
+
+@@ -554,6 +656,18 @@ process_config_every_time (BusContext *context,
+ goto failed;
+ }
+
++ if (dbus_server_is_afbus (link->data))
++ {
++ /* There must be at most one AF_BUS server */
++ _dbus_assert (_dbus_string_get_length (&main_address) == 0);
++
++ if (!_dbus_string_append (&main_address, addr))
++ {
++ BUS_SET_OOM (error);
++ goto failed;
++ }
++ }
++
+ dbus_free (addr);
+ addr = NULL;
+
+@@ -561,7 +675,10 @@ process_config_every_time (BusContext *context,
+ }
+
+ if (is_reload)
+- dbus_free (context->address);
++ {
++ dbus_free (context->address);
++ dbus_free (context->main_address);
++ }
+
+ if (!_dbus_string_copy_data (&full_address, &context->address))
+ {
+@@ -569,6 +686,12 @@ process_config_every_time (BusContext *context,
+ goto failed;
+ }
+
++ if (!_dbus_string_copy_data (&main_address, &context->main_address))
++ {
++ BUS_SET_OOM (error);
++ goto failed;
++ }
++
+ /* get the service directories */
+ dirs = bus_config_parser_get_service_dirs (parser);
+
+@@ -609,6 +732,7 @@ process_config_every_time (BusContext *context,
+
+ failed:
+ _dbus_string_free (&full_address);
++ _dbus_string_free (&main_address);
+
+ if (addr)
+ dbus_free (addr);
+@@ -990,29 +1114,6 @@ bus_context_reload_config (BusContext *context,
+ return ret;
+ }
+
+-static void
+-shutdown_server (BusContext *context,
+- DBusServer *server)
+-{
+- if (server == NULL ||
+- !dbus_server_get_is_connected (server))
+- return;
+-
+- if (!dbus_server_set_watch_functions (server,
+- NULL, NULL, NULL,
+- context,
+- NULL))
+- _dbus_assert_not_reached ("setting watch functions to NULL failed");
+-
+- if (!dbus_server_set_timeout_functions (server,
+- NULL, NULL, NULL,
+- context,
+- NULL))
+- _dbus_assert_not_reached ("setting timeout functions to NULL failed");
+-
+- dbus_server_disconnect (server);
+-}
+-
+ void
+ bus_context_shutdown (BusContext *context)
+ {
+@@ -1099,6 +1200,7 @@ bus_context_unref (BusContext *context)
+ dbus_free (context->log_prefix);
+ dbus_free (context->type);
+ dbus_free (context->address);
++ dbus_free (context->main_address);
+ dbus_free (context->user);
+ dbus_free (context->servicehelper);
+
+@@ -1134,6 +1236,12 @@ bus_context_get_address (BusContext *context)
+ }
+
+ const char*
++bus_context_get_main_address (BusContext *context)
++{
++ return context->main_address;
++}
++
++const char*
+ bus_context_get_servicehelper (BusContext *context)
+ {
+ return context->servicehelper;
+diff --git a/bus/bus.h b/bus/bus.h
+index 3597884..f2a55f2 100644
+--- a/bus/bus.h
++++ b/bus/bus.h
+@@ -88,6 +88,7 @@ dbus_bool_t bus_context_get_id (BusContext
+ DBusString *uuid);
+ const char* bus_context_get_type (BusContext *context);
+ const char* bus_context_get_address (BusContext *context);
++const char* bus_context_get_main_address (BusContext *context);
+ const char* bus_context_get_servicehelper (BusContext *context);
+ dbus_bool_t bus_context_get_systemd_activation (BusContext *context);
+ BusRegistry* bus_context_get_registry (BusContext *context);
+diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
+index c522ff4..8747835 100644
+--- a/bus/config-parser-common.c
++++ b/bus/config-parser-common.c
+@@ -63,6 +63,10 @@ bus_config_parser_element_name_to_type (const char *name)
+ {
+ return ELEMENT_LISTEN;
+ }
++ else if (strcmp (name, "listen_if_possible") == 0)
++ {
++ return ELEMENT_LISTEN_IF_POSSIBLE;
++ }
+ else if (strcmp (name, "auth") == 0)
+ {
+ return ELEMENT_AUTH;
+@@ -145,6 +149,8 @@ bus_config_parser_element_type_to_name (ElementType type)
+ return "user";
+ case ELEMENT_LISTEN:
+ return "listen";
++ case ELEMENT_LISTEN_IF_POSSIBLE:
++ return "listen_if_possible";
+ case ELEMENT_AUTH:
+ return "auth";
+ case ELEMENT_POLICY:
+diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
+index 186bf4c..6ea509c 100644
+--- a/bus/config-parser-common.h
++++ b/bus/config-parser-common.h
+@@ -31,6 +31,7 @@ typedef enum
+ ELEMENT_INCLUDE,
+ ELEMENT_USER,
+ ELEMENT_LISTEN,
++ ELEMENT_LISTEN_IF_POSSIBLE,
+ ELEMENT_AUTH,
+ ELEMENT_POLICY,
+ ELEMENT_LIMIT,
+diff --git a/bus/config-parser.c b/bus/config-parser.c
+index 07e8fbb..fffc0e1 100644
+--- a/bus/config-parser.c
++++ b/bus/config-parser.c
+@@ -96,6 +96,8 @@ struct BusConfigParser
+
+ DBusList *listen_on; /**< List of addresses to listen to */
+
++ DBusList *listen_on_if_possible; /**< List of addresses to listen to, but continue on failure */
++
+ DBusList *mechanisms; /**< Auth mechanisms */
+
+ DBusList *service_dirs; /**< Directories to look for session services in */
+@@ -327,6 +329,9 @@ merge_included (BusConfigParser *parser,
+ while ((link = _dbus_list_pop_first_link (&included->listen_on)))
+ _dbus_list_append_link (&parser->listen_on, link);
+
++ while ((link = _dbus_list_pop_first_link (&included->listen_on_if_possible)))
++ _dbus_list_append_link (&parser->listen_on_if_possible, link);
++
+ while ((link = _dbus_list_pop_first_link (&included->mechanisms)))
+ _dbus_list_append_link (&parser->mechanisms, link);
+
+@@ -497,6 +502,12 @@ bus_config_parser_unref (BusConfigParser *parser)
+
+ _dbus_list_clear (&parser->listen_on);
+
++ _dbus_list_foreach (&parser->listen_on_if_possible,
++ (DBusForeachFunction) dbus_free,
++ NULL);
++
++ _dbus_list_clear (&parser->listen_on_if_possible);
++
+ _dbus_list_foreach (&parser->service_dirs,
+ (DBusForeachFunction) dbus_free,
+ NULL);
+@@ -774,6 +785,19 @@ start_busconfig_child (BusConfigParser *parser,
+
+ return TRUE;
+ }
++ else if (element_type == ELEMENT_LISTEN_IF_POSSIBLE)
++ {
++ if (!check_no_attributes (parser, "listen_if_possible", attribute_names, attribute_values, error))
++ return FALSE;
++
++ if (push_element (parser, ELEMENT_LISTEN_IF_POSSIBLE) == NULL)
++ {
++ BUS_SET_OOM (error);
++ return FALSE;
++ }
++
++ return TRUE;
++ }
+ else if (element_type == ELEMENT_AUTH)
+ {
+ if (!check_no_attributes (parser, "auth", attribute_names, attribute_values, error))
+@@ -2018,6 +2042,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
+ case ELEMENT_USER:
+ case ELEMENT_CONFIGTYPE:
+ case ELEMENT_LISTEN:
++ case ELEMENT_LISTEN_IF_POSSIBLE:
+ case ELEMENT_PIDFILE:
+ case ELEMENT_AUTH:
+ case ELEMENT_SERVICEDIR:
+@@ -2518,6 +2543,24 @@ bus_config_parser_content (BusConfigParser *parser,
+ }
+ break;
+
++ case ELEMENT_LISTEN_IF_POSSIBLE:
++ {
++ char *s;
++
++ e->had_content = TRUE;
++
++ if (!_dbus_string_copy_data (content, &s))
++ goto nomem;
++
++ if (!_dbus_list_append (&parser->listen_on_if_possible,
++ s))
++ {
++ dbus_free (s);
++ goto nomem;
++ }
++ }
++ break;
++
+ case ELEMENT_AUTH:
+ {
+ char *s;
+@@ -2646,6 +2689,12 @@ bus_config_parser_get_addresses (BusConfigParser *parser)
+ }
+
+ DBusList**
++bus_config_parser_get_addresses_if_possible (BusConfigParser *parser)
++{
++ return &parser->listen_on_if_possible;
++}
++
++DBusList**
+ bus_config_parser_get_mechanisms (BusConfigParser *parser)
+ {
+ return &parser->mechanisms;
+@@ -3123,6 +3172,9 @@ config_parsers_equal (const BusConfigParser *a,
+ if (!lists_of_c_strings_equal (a->listen_on, b->listen_on))
+ return FALSE;
+
++ if (!lists_of_c_strings_equal (a->listen_on_if_possible, b->listen_on_if_possible))
++ return FALSE;
++
+ if (!lists_of_c_strings_equal (a->mechanisms, b->mechanisms))
+ return FALSE;
+
+diff --git a/bus/config-parser.h b/bus/config-parser.h
+index ba5bf74..f8a3c07 100644
+--- a/bus/config-parser.h
++++ b/bus/config-parser.h
+@@ -61,6 +61,7 @@ dbus_bool_t bus_config_parser_finished (BusConfigParser *parser,
+ const char* bus_config_parser_get_user (BusConfigParser *parser);
+ const char* bus_config_parser_get_type (BusConfigParser *parser);
+ DBusList** bus_config_parser_get_addresses (BusConfigParser *parser);
++DBusList** bus_config_parser_get_addresses_if_possible (BusConfigParser *parser);
+ DBusList** bus_config_parser_get_mechanisms (BusConfigParser *parser);
+ dbus_bool_t bus_config_parser_get_fork (BusConfigParser *parser);
+ dbus_bool_t bus_config_parser_get_allow_anonymous (BusConfigParser *parser);
+diff --git a/bus/connection.c b/bus/connection.c
+index d69758c..2d68c84 100644
+--- a/bus/connection.c
++++ b/bus/connection.c
+@@ -30,9 +30,16 @@
+ #include "signals.h"
+ #include "expirelist.h"
+ #include "selinux.h"
++#include "driver-afbus.h"
+ #include <dbus/dbus-list.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-timeout.h>
++#ifdef HAVE_AFBUS
++#include <dbus/dbus-transport-afbus.h>
++#endif
++
++#include <sys/types.h> /* See NOTES */
++#include <sys/socket.h>
+
+ /* Trim executed commands to this length; we want to keep logs readable */
+ #define MAX_LOG_COMMAND_LEN 50
+@@ -94,6 +101,13 @@ typedef struct
+ char *cached_loginfo_string;
+ BusSELinuxID *selinux_id;
+
++ dbus_bool_t peer_address_set;
++ struct sockaddr_storage peer_address;
++ socklen_t peer_addrlen;
++ DBusConnection *proxy_connection; /**< If this is a compat connection,
++ proxy_connection is the proxy
++ connection to AF_BUS */
++
+ long connection_tv_sec; /**< Time when we connected (seconds component) */
+ long connection_tv_usec; /**< Time when we connected (microsec component) */
+ int stamp; /**< connections->stamp last time we were traversed */
+@@ -184,12 +198,33 @@ adjust_connections_for_uid (BusConnections *connections,
+ }
+ }
+
++static DBusHandlerResult
++proxy_connection_message_filter (DBusConnection *connection,
++ DBusMessage *message,
++ void *user_data)
++{
++ DBusConnection *source_connection = user_data;
++
++ if (dbus_message_get_destination (message) == NULL &&
++ dbus_message_is_signal (message,
++ DBUS_INTERFACE_LOCAL,
++ "Disconnected"))
++ {
++ dbus_connection_close (source_connection);
++ return DBUS_HANDLER_RESULT_HANDLED;
++ }
++
++ dbus_connection_send (source_connection, message, NULL);
++ return DBUS_HANDLER_RESULT_HANDLED;
++}
++
+ void
+ bus_connection_disconnected (DBusConnection *connection)
+ {
+ BusConnectionData *d;
+ BusService *service;
+ BusMatchmaker *matchmaker;
++ DBusError error;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+@@ -197,6 +232,20 @@ bus_connection_disconnected (DBusConnection *connection)
+ _dbus_verbose ("%s disconnected, dropping all service ownership and releasing\n",
+ d->name ? d->name : "(inactive)");
+
++ if (d->proxy_connection)
++ {
++ dbus_connection_remove_filter (d->proxy_connection,
++ proxy_connection_message_filter, connection);
++ dbus_connection_close (d->proxy_connection);
++ dbus_connection_unref (d->proxy_connection);
++ d->proxy_connection = NULL;
++ }
++
++ dbus_error_init (&error);
++
++ if (!bus_driver_afbus_disconnected(connection, &error))
++ dbus_error_free (&error);
++
+ /* Delete our match rules */
+ if (d->n_match_rules > 0)
+ {
+@@ -309,6 +358,18 @@ bus_connection_disconnected (DBusConnection *connection)
+ dbus_connection_unref (connection);
+ }
+
++DBusConnection *
++bus_connection_get_proxy_connection (DBusConnection *connection)
++{
++ BusConnectionData *d;
++
++ d = BUS_CONNECTION_DATA (connection);
++
++ _dbus_assert (d != NULL);
++
++ return d->proxy_connection;
++}
++
+ static dbus_bool_t
+ add_connection_watch (DBusWatch *watch,
+ void *data)
+@@ -588,6 +649,52 @@ oom:
+ return FALSE;
+ }
+
++#ifdef HAVE_AFBUS
++static dbus_bool_t
++bus_connections_setup_proxy_connection (BusConnections *connections,
++ DBusConnection *connection,
++ const char *main_address)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA (connection);
++ DBusError error;
++ dbus_bool_t retval = FALSE;
++
++ dbus_error_init (&error);
++
++ d->proxy_connection
++ = dbus_connection_open_private (main_address, &error);
++ if (dbus_error_is_set (&error))
++ {
++ dbus_error_free (&error);
++ goto out;
++ }
++
++ dbus_connection_set_route_peer_messages (d->proxy_connection, TRUE);
++
++ dbus_connection_set_dispatch_status_function (d->proxy_connection,
++ dispatch_status_function,
++ bus_context_get_loop (connections->context), NULL);
++
++ if (!dbus_connection_add_filter(d->proxy_connection,
++ proxy_connection_message_filter, connection, NULL))
++ goto out;
++
++
++ if (!dbus_connection_set_watch_functions (d->proxy_connection,
++ add_connection_watch,
++ remove_connection_watch,
++ toggle_connection_watch,
++ connection,
++ NULL))
++ goto out;
++
++ return TRUE;
++
++out:
++ return retval;
++}
++#endif
++
+ dbus_bool_t
+ bus_connections_setup_connection (BusConnections *connections,
+ DBusConnection *connection)
+@@ -596,7 +703,6 @@ bus_connections_setup_connection (BusConnections *connections,
+ BusConnectionData *d;
+ dbus_bool_t retval;
+ DBusError error;
+-
+
+ d = dbus_new0 (BusConnectionData, 1);
+
+@@ -622,8 +728,32 @@ bus_connections_setup_connection (BusConnections *connections,
+ dbus_connection_set_route_peer_messages (connection, TRUE);
+
+ retval = FALSE;
+-
+ dbus_error_init (&error);
++
++#ifdef HAVE_AFBUS
++ d->peer_addrlen = sizeof(d->peer_address);
++ d->peer_address_set = dbus_connection_get_peer_address (connection,
++ &d->peer_address, (long int *)&d->peer_addrlen);
++
++ /* If this connection is not AF_BUS, and we have a AF_BUS
++ * server, we are in compat mode and we need to setup a
++ * new connection */
++ if (d->peer_address_set &&
++ ((struct sockaddr *)&d->peer_address)->sa_family != AF_BUS)
++ {
++ const char *main_address;
++ main_address = bus_context_get_main_address (connections->context);
++ if (main_address && main_address[0] != '\0')
++ {
++ if (!bus_connections_setup_proxy_connection (connections, connection,
++ main_address))
++ {
++ goto out;
++ }
++ }
++ }
++#endif
++
+ d->selinux_id = bus_selinux_init_connection_id (connection,
+ &error);
+ if (dbus_error_is_set (&error))
+@@ -2383,3 +2513,21 @@ bus_connection_get_peak_bus_names (DBusConnection *connection)
+ return d->peak_bus_names;
+ }
+ #endif /* DBUS_ENABLE_STATS */
++
++int
++bus_connection_get_peer_address (DBusConnection *connection,
++ struct sockaddr **peer_address,
++ socklen_t *peer_addrlen)
++{
++ BusConnectionData *d;
++
++ d = BUS_CONNECTION_DATA (connection);
++
++ if (!d->peer_address_set)
++ return FALSE;
++
++ *peer_address = (struct sockaddr *) &d->peer_address;
++ *peer_addrlen = d->peer_addrlen;
++
++ return TRUE;
++}
+diff --git a/bus/connection.h b/bus/connection.h
+index c936021..95856f3 100644
+--- a/bus/connection.h
++++ b/bus/connection.h
+@@ -24,6 +24,8 @@
+ #ifndef BUS_CONNECTION_H
+ #define BUS_CONNECTION_H
+
++#include <sys/types.h>
++#include <sys/socket.h>
+ #include <dbus/dbus.h>
+ #include <dbus/dbus-list.h>
+ #include "bus.h"
+@@ -103,8 +105,9 @@ dbus_bool_t bus_connection_complete (DBusConnection *connection,
+ const DBusString *name,
+ DBusError *error);
+
+-/* called by dispatch.c when the connection is dropped */
+-void bus_connection_disconnected (DBusConnection *connection);
++/* called by dispatch.c */
++void bus_connection_disconnected (DBusConnection *connection);
++DBusConnection *bus_connection_get_proxy_connection (DBusConnection *connection);
+
+ dbus_bool_t bus_connection_is_in_unix_group (DBusConnection *connection,
+ unsigned long gid);
+@@ -151,4 +154,9 @@ int bus_connections_get_peak_bus_names_per_conn (BusConnections *connections);
+ int bus_connection_get_peak_match_rules (DBusConnection *connection);
+ int bus_connection_get_peak_bus_names (DBusConnection *connection);
+
++/* called by driver-afbus.c */
++int bus_connection_get_peer_address (DBusConnection *connection,
++ struct sockaddr **peer_address,
++ socklen_t *peer_addrlen);
++
+ #endif /* BUS_CONNECTION_H */
+diff --git a/bus/dispatch.c b/bus/dispatch.c
+index 7a96f9d..4feae05 100644
+--- a/bus/dispatch.c
++++ b/bus/dispatch.c
+@@ -27,6 +27,7 @@
+ #include "dispatch.h"
+ #include "connection.h"
+ #include "driver.h"
++#include "driver-afbus.h"
+ #include "services.h"
+ #include "activation.h"
+ #include "utils.h"
+@@ -129,6 +130,18 @@ bus_dispatch_matches (BusTransaction *transaction,
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
++
++ /* If using AF_BUS and the message came to the daemon, the client sending
++ * the message doesn't yet know the address for this service, so notify
++ * it of the address associated with the service. */
++ if (!bus_driver_afbus_emit_forwarded (transaction,
++ sender,
++ addressed_recipient,
++ dbus_message_get_destination (message)))
++ {
++ _dbus_verbose ("bus_driver_afbus_emit_forwarded() failed\n");
++ return FALSE;
++ }
+ }
+
+ /* Now dispatch to others who look interested in this message */
+@@ -180,6 +193,7 @@ bus_dispatch (DBusConnection *connection,
+ BusContext *context;
+ DBusHandlerResult result;
+ DBusConnection *addressed_recipient;
++ DBusConnection *proxy_connection;
+
+ result = DBUS_HANDLER_RESULT_HANDLED;
+
+@@ -241,6 +255,15 @@ bus_dispatch (DBusConnection *connection,
+ }
+ }
+
++ /* Directly send the message to the proxy without analysing it */
++ proxy_connection = bus_connection_get_proxy_connection (connection);
++ if (proxy_connection)
++ {
++ if (!dbus_connection_send (proxy_connection, message, NULL))
++ BUS_SET_OOM (&error);
++ goto out;
++ }
++
+ /* Create our transaction */
+ transaction = bus_transaction_new (context);
+ if (transaction == NULL)
+diff --git a/bus/driver-afbus.c b/bus/driver-afbus.c
+new file mode 100644
+index 0000000..70edafb
+--- /dev/null
++++ b/bus/driver-afbus.c
+@@ -0,0 +1,345 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* driver.c Bus client, AF_BUS bits (driver)
++ *
++ * Copyright (C) 2012 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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 "driver-afbus.h"
++
++#include <unistd.h>
++#include <sys/types.h>
++#include <sys/socket.h>
++#include <asm/types.h>
++#include <errno.h>
++#include <linux/netlink.h>
++#include <linux/rtnetlink.h>
++#include <linux/connector.h>
++#include <dbus/dbus-transport-afbus.h>
++
++#define CN_IDX_NFDBUS 0xA /* netfilter D-Bus */
++#define CN_VAL_NFDBUS 0x1
++
++#define NFDBUS_CMD_ADDMATCH 0x01
++#define NFDBUS_CMD_REMOVEMATCH 0x02
++#define NFDBUS_CMD_REMOVEALLMATCH 0x03
++
++struct nfdbus_nl_cfg_req {
++ __u32 cmd;
++ __u32 len;
++ struct sockaddr_bus addr;
++ __u64 pad;
++ unsigned char data[0];
++};
++
++struct nfdbus_nl_cfg_reply {
++ __u32 ret_code;
++};
++
++static int
++ensure_nl_sock(DBusError *error)
++{
++ static int nlsock = 0;
++
++ struct sockaddr_nl l_local;
++ int fd;
++ int ret;
++
++ if (nlsock > 0)
++ return nlsock;
++
++ fd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_CONNECTOR);
++ if (fd == -1) {
++ dbus_set_error (error, DBUS_ERROR_NETLINK,
++ "Couldn't use the netlink socket: %s",
++ strerror(errno));
++ return -1;
++ }
++
++ if (!_dbus_set_fd_nonblocking (fd, error))
++ {
++ _dbus_close_socket (fd, NULL);
++ return -1;
++ }
++
++ l_local.nl_family = AF_NETLINK;
++ l_local.nl_groups = 0;
++ l_local.nl_pid = 0;
++ ret = bind(fd, (struct sockaddr *)&l_local, sizeof(struct sockaddr_nl));
++ if (ret == -1) {
++ close(fd);
++ dbus_set_error (error, DBUS_ERROR_NETLINK,
++ "Couldn't bind the netlink socket: %s",
++ strerror(errno));
++ return -1;
++ }
++
++ nlsock = fd;
++ return nlsock;
++}
++
++static int netlink_send(int nlsock, struct cn_msg *msg, int seq)
++{
++ struct nlmsghdr *nlh;
++ unsigned int size;
++ char buf[4096];
++ struct cn_msg *m;
++
++ size = NLMSG_SPACE(sizeof(struct cn_msg) + msg->len);
++
++ nlh = (struct nlmsghdr *)buf;
++ nlh->nlmsg_seq = seq;
++ nlh->nlmsg_pid = getpid();
++ nlh->nlmsg_type = NLMSG_DONE;
++ nlh->nlmsg_len = NLMSG_LENGTH(size - sizeof(*nlh));
++ nlh->nlmsg_flags = 0;
++
++ m = NLMSG_DATA(nlh);
++ memcpy(m, msg, sizeof(*m) + msg->len);
++
++ return send(nlsock, nlh, size, 0);
++}
++
++static dbus_bool_t
++bus_driver_afbus_upload_match_rule (DBusConnection *connection,
++ const char *rule,
++ int cmd,
++ DBusError *error)
++{
++ static int seq;
++
++ int nlsock;
++ int ret;
++
++ char buf[sizeof(struct cn_msg) + sizeof(struct nfdbus_nl_cfg_req) + 1024];
++
++ struct cn_msg *data;
++ struct nlmsghdr *reply;
++ struct nfdbus_nl_cfg_req *req;
++ //struct nfdbus_nl_cfg_reply *req_reply;
++
++ struct sockaddr_storage *address;
++ socklen_t addrlen = sizeof(address);
++
++ if (!bus_connection_get_peer_address(connection,
++ (struct sockaddr **) &address, &addrlen))
++ return TRUE;
++
++ if (((struct sockaddr*)address)->sa_family != AF_BUS)
++ return TRUE;
++
++ nlsock = ensure_nl_sock (error);
++ if (nlsock == -1)
++ return FALSE;
++
++ memset(buf, 0, sizeof(buf));
++
++ data = (struct cn_msg *)buf;
++
++ data->id.idx = CN_IDX_NFDBUS;
++ data->id.val = CN_VAL_NFDBUS;
++ data->seq = seq++;
++ data->ack = 0;
++ data->len = sizeof(struct nfdbus_nl_cfg_req) + strlen(rule) + 1;
++ req = (struct nfdbus_nl_cfg_req *) data->data;
++
++ req->cmd = cmd;
++ req->len = strlen(rule) + 1;
++ req->addr = *(struct sockaddr_bus *)address;
++ strcpy((char *)req->data, rule);
++
++ ret = netlink_send(nlsock, data, seq++);
++ if (ret <= 0)
++ {
++ }
++
++ memset(buf, 0, sizeof(buf));
++ ret = recv(nlsock, buf, sizeof(buf), 0);
++ if (ret <= 0)
++ {
++ }
++
++ reply = (struct nlmsghdr *)buf;
++ if (reply->nlmsg_type != NLMSG_DONE)
++ {
++ }
++
++ return TRUE;
++}
++
++dbus_bool_t
++bus_driver_afbus_add_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error)
++{
++ if (bus_driver_afbus_upload_match_rule (connection, rule, NFDBUS_CMD_ADDMATCH, error))
++ {
++ /* Check if the match rule is for eavesdropping, and set the socket
++ * to allow receiving all messages if so */
++ if (strstr (rule, "eavesdrop=true"))
++ {
++ int fd;
++
++ if (dbus_connection_get_socket (connection, &fd))
++ {
++ if (setsockopt (fd, SOL_BUS, BUS_SET_EAVESDROP, NULL, 0) == 0)
++ return TRUE;
++ else
++ {
++ dbus_set_error (error,
++ _dbus_error_from_errno (errno),
++ "Failed to setsockopt on socket %d: %s",
++ fd, _dbus_strerror (errno));
++ }
++ }
++ else
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ }
++ else
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++dbus_bool_t
++bus_driver_afbus_remove_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error)
++{
++ return bus_driver_afbus_upload_match_rule (connection, rule, NFDBUS_CMD_REMOVEMATCH, error);
++}
++
++dbus_bool_t
++bus_driver_afbus_append_unique_name (DBusConnection *connection,
++ DBusString *str)
++{
++ struct sockaddr_bus address;
++ long len = sizeof(address);
++
++ memset (&address, 0, sizeof (address));
++ if (!dbus_connection_get_peer_address(connection, &address, &len) ||
++ address.sbus_family != AF_BUS)
++ return FALSE;
++
++ if (!_dbus_string_append (str, "AF-BUS."))
++ return FALSE;
++
++ if (!_dbus_string_append_uint (str, address.sbus_addr.s_addr))
++ return FALSE;
++
++ return TRUE;
++}
++
++dbus_bool_t
++bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
++ DBusConnection *connection,
++ DBusConnection *addressed_recipient,
++ const char *service_name)
++{
++ struct sockaddr_bus address;
++ long len = sizeof (address);
++ DBusMessage *message;
++ dbus_bool_t result = FALSE;
++
++ memset (&address, 0, sizeof (address));
++ if (!dbus_connection_get_peer_address (addressed_recipient, &address, &len) ||
++ address.sbus_family != AF_BUS)
++ {
++ /* Don't return an error if it is not a AF_BUS socket */
++ return TRUE;
++ }
++
++ /* Prepare the message to be sent */
++ message = dbus_message_new_signal (DBUS_PATH_AFBUS,
++ DBUS_INTERFACE_AFBUS,
++ "Forwarded");
++ if (message == NULL)
++ {
++ _dbus_verbose ("Could not allocate AF_BUS.Forwarded signal message\n");
++ return FALSE;
++ }
++
++ if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
++ {
++ _dbus_verbose ("Could not set sender for AF_BUS.Forwarded signal message\n");
++ goto out;
++ }
++
++ if (!dbus_message_append_args (message,
++ DBUS_TYPE_STRING, &service_name,
++ DBUS_TYPE_UINT64, &address.sbus_addr.s_addr,
++ DBUS_TYPE_INVALID))
++ {
++ _dbus_verbose ("Could not append arguments for AF_BUS.Forwarded signal message\n");
++ goto out;
++ }
++
++ if (bus_transaction_send (transaction, connection, message))
++ result = TRUE;
++ else
++ _dbus_verbose ("Could not send AF_BUS.Forwarded signal message\n");
++
++ out:
++ dbus_message_unref (message);
++
++ return result;
++}
++
++dbus_bool_t
++bus_driver_afbus_assign_address (DBusConnection *connection)
++{
++ struct sockaddr_bus address;
++ long len = sizeof (address);
++ int fd;
++ static dbus_uint64_t next_address = 0x1111000000000001ULL;
++
++ memset (&address, 0, sizeof (address));
++ if (!dbus_connection_get_peer_address (connection, &address, &len) ||
++ ((struct sockaddr *) &address)->sa_family != AF_BUS)
++ {
++ /* Don't return an error if it is not a AF_BUS socket */
++ return TRUE;
++ }
++
++ if (!dbus_connection_get_unix_fd (connection, &fd))
++ {
++ return FALSE;
++ }
++
++ address.sbus_addr.s_addr = next_address;
++ if (setsockopt (fd, SOL_BUS, BUS_ADD_ADDR, &address, sizeof (address)) != 0)
++ {
++ return FALSE;
++ }
++
++ next_address++;
++
++ return TRUE;
++}
++
++dbus_bool_t
++bus_driver_afbus_disconnected (DBusConnection *connection,
++ DBusError *error)
++{
++ return bus_driver_afbus_upload_match_rule (connection, "",
++ NFDBUS_CMD_REMOVEALLMATCH, error);
++}
+diff --git a/bus/driver-afbus.h b/bus/driver-afbus.h
+new file mode 100644
+index 0000000..9c40111
+--- /dev/null
++++ b/bus/driver-afbus.h
+@@ -0,0 +1,96 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* driver-afbus.h Bus client, AF_BUS bits (driver)
++ *
++ * Copyright (C) 2012 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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
++ *
++ */
++
++#ifndef BUS_DRIVER_AFBUS_H
++#define BUS_DRIVER_AFBUS_H
++
++#include <config.h>
++#include <sys/socket.h>
++#include <dbus/dbus.h>
++#include "connection.h"
++
++#if HAVE_AFBUS
++dbus_bool_t bus_driver_afbus_add_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error);
++dbus_bool_t bus_driver_afbus_remove_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error);
++dbus_bool_t bus_driver_afbus_append_unique_name (DBusConnection *connection,
++ DBusString *str);
++dbus_bool_t bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
++ DBusConnection *connection,
++ DBusConnection *addressed_recipient,
++ const char *service_name);
++dbus_bool_t bus_driver_afbus_assign_address (DBusConnection *connection);
++dbus_bool_t bus_driver_afbus_disconnected (DBusConnection *connection,
++ DBusError *error);
++#else
++static inline
++dbus_bool_t bus_driver_afbus_add_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error)
++{
++ return TRUE;
++}
++
++static inline
++dbus_bool_t bus_driver_afbus_remove_match_rule (DBusConnection *connection,
++ const char *rule,
++ DBusError *error)
++{
++ return TRUE;
++}
++
++static inline
++dbus_bool_t bus_driver_afbus_append_unique_name (DBusConnection *connection,
++ DBusString *str)
++{
++ return TRUE;
++}
++
++static inline
++dbus_bool_t bus_driver_afbus_emit_forwarded (BusTransaction *transaction,
++ DBusConnection *connection,
++ DBusConnection *addressed_recipient,
++ const char *service_name)
++{
++ return TRUE;
++}
++
++static inline
++dbus_bool_t bus_driver_afbus_assign_address (DBusConnection *connection)
++{
++ return TRUE;
++}
++
++static inline
++dbus_bool_t bus_driver_afbus_disconnected (DBusConnection *connection,
++ DBusError *error)
++{
++ return TRUE;
++}
++
++#endif
++
++#endif /* BUS_DRIVER_AFBUS_H */
+diff --git a/bus/driver.c b/bus/driver.c
+index 574e0f3..11767c8 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -26,6 +26,7 @@
+ #include "activation.h"
+ #include "connection.h"
+ #include "driver.h"
++#include "driver-afbus.h"
+ #include "dispatch.h"
+ #include "services.h"
+ #include "selinux.h"
+@@ -182,8 +183,9 @@ bus_driver_send_service_acquired (DBusConnection *connection,
+ }
+
+ static dbus_bool_t
+-create_unique_client_name (BusRegistry *registry,
+- DBusString *str)
++create_unique_client_name (DBusConnection *connection,
++ 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
+@@ -214,19 +216,23 @@ create_unique_client_name (BusRegistry *registry,
+ _dbus_assert (next_major_number > 0);
+ _dbus_assert (next_minor_number >= 0);
+
+- /* appname:MAJOR-MINOR */
++ /* unique name:
++ * :[AF-BUS.BUS-ADDRESS.]MAJOR.MINOR */
+
+ if (!_dbus_string_append (str, ":"))
+ return FALSE;
+
+- if (!_dbus_string_append_int (str, next_major_number))
+- return FALSE;
++ if (!bus_driver_afbus_append_unique_name (connection, str))
++ {
++ if (!_dbus_string_append_int (str, next_major_number))
++ return FALSE;
+
+- if (!_dbus_string_append (str, "."))
+- return FALSE;
++ if (!_dbus_string_append (str, "."))
++ return FALSE;
+
+- if (!_dbus_string_append_int (str, next_minor_number))
+- return FALSE;
++ if (!_dbus_string_append_int (str, next_minor_number))
++ return FALSE;
++ }
+
+ next_minor_number += 1;
+
+@@ -287,7 +293,7 @@ bus_driver_handle_hello (DBusConnection *connection,
+
+ registry = bus_connection_get_registry (connection);
+
+- if (!create_unique_client_name (registry, &unique_name))
++ if (!create_unique_client_name (connection, registry, &unique_name))
+ {
+ BUS_SET_OOM (error);
+ goto out_0;
+@@ -610,6 +616,13 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
+ goto out;
+ }
+
++ /* If using AF_BUS, assign an address to this peer */
++ if (!bus_driver_afbus_assign_address (connection))
++ {
++ BUS_SET_OOM (error);
++ goto out;
++ }
++
+ retval = TRUE;
+
+ out:
+@@ -988,6 +1001,9 @@ bus_driver_handle_add_match (DBusConnection *connection,
+ if (rule == NULL)
+ goto failed;
+
++ if (!bus_driver_afbus_add_match_rule (connection, text, error))
++ goto failed;
++
+ matchmaker = bus_connection_get_matchmaker (connection);
+
+ if (!bus_matchmaker_add_rule (matchmaker, rule))
+@@ -1051,6 +1067,9 @@ bus_driver_handle_remove_match (DBusConnection *connection,
+ message, error))
+ goto failed;
+
++ if (!bus_driver_afbus_remove_match_rule (connection, text, error))
++ goto failed;
++
+ matchmaker = bus_connection_get_matchmaker (connection);
+
+ if (!bus_matchmaker_remove_rule_by_value (matchmaker, rule, error))
+@@ -1779,6 +1798,13 @@ static InterfaceHandler interface_handlers[] = {
+ { DBUS_INTERFACE_INTROSPECTABLE, introspectable_message_handlers, NULL },
+ #ifdef DBUS_ENABLE_STATS
+ { BUS_INTERFACE_STATS, stats_message_handlers, NULL },
++#ifdef HAVE_AFBUS
++ { DBUS_INTERFACE_AFBUS, NULL,
++ " <signal name=\"AF_BUS.Forwarded\">\n"
++ " <arg type=\"s\"/>\n"
++ " <arg type=\"t\"/>\n"
++ " </signal>\n" },
++#endif
+ #endif
+ { NULL, NULL, NULL }
+ };
+diff --git a/bus/session.conf.in b/bus/session.conf.in
+index e121ff9..09a7ecf 100644
+--- a/bus/session.conf.in
++++ b/bus/session.conf.in
+@@ -12,7 +12,8 @@
+ the behavior of child processes. -->
+ <keep_umask/>
+
+- <listen>@DBUS_SESSION_BUS_DEFAULT_ADDRESS@</listen>
++ <listen_if_possible>afbus:tmpdir=/tmp</listen_if_possible>
++ <listen>unix:tmpdir=/tmp</listen>
+
+ <standard_session_servicedirs />
+
+diff --git a/bus/system.conf.in b/bus/system.conf.in
+index 92f4cc4..515509f 100644
+--- a/bus/system.conf.in
++++ b/bus/system.conf.in
+@@ -39,6 +39,7 @@
+ means use abstract namespace, don't really create filesystem
+ file; only Linux supports this. Use path=/whatever on other
+ systems.) -->
++ <listen_if_possible>afbus:@DBUS_SYSTEM_SOCKET@.afbus</listen_if_possible>
+ <listen>@DBUS_SYSTEM_BUS_DEFAULT_ADDRESS@</listen>
+
+ <policy context="default">
+diff --git a/configure.ac b/configure.ac
+index 4f86e9d..51a48fd 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1509,6 +1509,20 @@ if test "x$with_systemdsystemunitdir" != xno; then
+ fi
+ AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
+
++## Check for AF_DBUS
++AC_MSG_CHECKING([for AF_BUS socket family])
++AC_COMPILE_IFELSE(
++ [AC_LANG_PROGRAM(
++ [[#include <sys/socket.h>]],
++ [[return socket (PF_BUS, SOCK_STREAM, 0);]])],
++ [have_afbus=yes],
++ [have_afbus=no])
++AC_MSG_RESULT([$have_afbus])
++if test "x$have_afbus" = "xyes"; then
++ AC_DEFINE(HAVE_AFBUS, 1, [Define if AF_BUS is available])
++fi
++AM_CONDITIONAL(HAVE_AFBUS, test "x$have_afbus" = "xyes")
++
+ ##### Set up location for system bus socket
+ if ! test -z "$with_system_socket"; then
+ DBUS_SYSTEM_SOCKET=$with_system_socket
+@@ -1648,7 +1662,11 @@ AC_SUBST(TEST_SOCKET_DIR)
+ AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets])
+
+ if test "x$dbus_unix" = xyes; then
+- TEST_LISTEN="unix:tmpdir=$TEST_SOCKET_DIR"
++ if test "x$have_afbus" = "xyes"; then
++ TEST_LISTEN="afbus:tmpdir=$TEST_SOCKET_DIR"
++ else
++ TEST_LISTEN="unix:tmpdir=$TEST_SOCKET_DIR"
++ fi
+ else
+ TEST_LISTEN="tcp:host=localhost"
+ fi
+@@ -1668,6 +1686,8 @@ if test x$dbus_win = xyes; then
+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="$with_dbus_session_bus_default_address"
+ elif test x$have_launchd = xyes; then
+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="launchd:env=DBUS_LAUNCHD_SESSION_BUS_SOCKET"
++elif test x$have_afbus = xyes; then
++ DBUS_SESSION_BUS_DEFAULT_ADDRESS="afbus:tmpdir=$DBUS_SESSION_SOCKET_DIR"
+ else
+ DBUS_SESSION_BUS_DEFAULT_ADDRESS="unix:tmpdir=$DBUS_SESSION_SOCKET_DIR"
+ fi
+diff --git a/dbus/Makefile.am b/dbus/Makefile.am
+index bb5ccca..b925419 100644
+--- a/dbus/Makefile.am
++++ b/dbus/Makefile.am
+@@ -87,6 +87,16 @@ else
+ launchd_source =
+ endif
+
++if HAVE_AFBUS
++afbus_source = \
++ dbus-server-afbus.c \
++ dbus-server-afbus.h \
++ dbus-transport-afbus.c \
++ dbus-transport-afbus.h
++else
++afbus_source =
++endif
++
+ DBUS_LIB_arch_sources = \
+ dbus-uuidgen.c \
+ dbus-uuidgen.h \
+@@ -95,6 +105,7 @@ DBUS_LIB_arch_sources = \
+
+ DBUS_SHARED_arch_sources = \
+ $(launchd_source) \
++ $(afbus_source) \
+ dbus-file-unix.c \
+ dbus-pipe-unix.c \
+ dbus-sysdeps-unix.c \
+diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
+index ee33b6c..5f3a459 100644
+--- a/dbus/dbus-connection.c
++++ b/dbus/dbus-connection.c
+@@ -45,6 +45,8 @@
+ #include "dbus-bus.h"
+ #include "dbus-marshal-basic.h"
+
++#include <sys/socket.h>
++
+ #ifdef DBUS_DISABLE_CHECKS
+ #define TOOK_LOCK_CHECK(connection)
+ #define RELEASING_LOCK_CHECK(connection)
+@@ -2054,9 +2056,15 @@ _dbus_connection_send_preallocated_and_unlock (DBusConnection *connection,
+ dbus_uint32_t *client_serial)
+ {
+ DBusDispatchStatus status;
++ const char *sender;
+
+ HAVE_LOCK_CHECK (connection);
+-
++
++ /* Set the sender field */
++ sender = dbus_bus_get_unique_name (connection);
++ if (sender)
++ dbus_message_set_sender (message, sender);
++
+ _dbus_connection_send_preallocated_unlocked_no_update (connection,
+ preallocated,
+ message, client_serial);
+@@ -3359,6 +3367,7 @@ dbus_connection_send_with_reply (DBusConnection *connection,
+ DBusPendingCall *pending;
+ dbus_int32_t serial = -1;
+ DBusDispatchStatus status;
++ const char *sender;
+
+ _dbus_return_val_if_fail (connection != NULL, FALSE);
+ _dbus_return_val_if_fail (message != NULL, FALSE);
+@@ -3401,6 +3410,11 @@ dbus_connection_send_with_reply (DBusConnection *connection,
+ return FALSE;
+ }
+
++ /* Set the sender field */
++ sender = dbus_bus_get_unique_name (connection);
++ if (sender)
++ dbus_message_set_sender (message, sender);
++
+ /* Assign a serial to the message */
+ serial = dbus_message_get_serial (message);
+ if (serial == 0)
+@@ -5439,6 +5453,27 @@ dbus_connection_set_route_peer_messages (DBusConnection *connection,
+ CONNECTION_UNLOCK (connection);
+ }
+
++dbus_bool_t
++dbus_connection_get_peer_address (DBusConnection *connection,
++ void *addr,
++ long *len)
++{
++ dbus_bool_t res;
++ int fd;
++ socklen_t _len = *len;
++
++ _dbus_return_val_if_fail (connection != NULL, FALSE);
++
++ res = _dbus_transport_get_socket_fd (connection->transport, &fd);
++ if (!res)
++ return res;
++
++ res = getpeername(fd, (struct sockaddr *) addr, &_len) == 0;
++ if (res)
++ *len = _len;
++ return res;
++}
++
+ /**
+ * Adds a message filter. Filters are handlers that are run on all
+ * incoming messages, prior to the objects registered with
+diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h
+index fe4d04e..81fe9f1 100644
+--- a/dbus/dbus-connection.h
++++ b/dbus/dbus-connection.h
+@@ -287,6 +287,10 @@ void dbus_connection_set_allow_anonymous (DBusConnection
+ DBUS_EXPORT
+ void dbus_connection_set_route_peer_messages (DBusConnection *connection,
+ dbus_bool_t value);
++DBUS_EXPORT
++dbus_bool_t dbus_connection_get_peer_address (DBusConnection *connection,
++ void *addr,
++ long *len);
+
+
+ /* Filters */
+diff --git a/dbus/dbus-protocol.h b/dbus/dbus-protocol.h
+index 60605ab..71c2870 100644
+--- a/dbus/dbus-protocol.h
++++ b/dbus/dbus-protocol.h
+@@ -458,6 +458,12 @@ extern "C" {
+ /** XML document type declaration of the introspection format version 1.0 */
+ #define DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<!DOCTYPE node PUBLIC \"" DBUS_INTROSPECT_1_0_XML_PUBLIC_IDENTIFIER "\"\n\"" DBUS_INTROSPECT_1_0_XML_SYSTEM_IDENTIFIER "\">\n"
+
++/* AF_BUS errors */
++
++/** Tried to use a netlink socket and it failed. */
++#define DBUS_ERROR_NETLINK "org.freedesktop.DBus.Error.NetLink"
++#define DBUS_ERROR_MULTIPLE_AFBUS "org.freedesktop.DBus.Error.MultipleAFBUS"
++
+ /** @} */
+
+ #ifdef __cplusplus
+diff --git a/dbus/dbus-server-afbus.c b/dbus/dbus-server-afbus.c
+new file mode 100644
+index 0000000..1d8e9bd
+--- /dev/null
++++ b/dbus/dbus-server-afbus.c
+@@ -0,0 +1,397 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* dbus-server-unix.c Server implementation for Unix network protocols.
++ *
++ * Copyright (C) 2012 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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 <errno.h>
++#include <sys/socket.h>
++#include "dbus-connection-internal.h"
++#include "dbus-server-afbus.h"
++#include "dbus-server-protected.h"
++#include "dbus-string.h"
++#include "dbus-sysdeps.h"
++#include "dbus-transport.h"
++#include "dbus-transport-afbus.h"
++
++/**
++ * @defgroup DBusServerAfbus DBusServer implementation for AF_BUS sockets
++ * @ingroup DBusInternals
++ * @brief Implementation details of DBusServer for AF_BUS sockets
++ *
++ * @{
++ */
++/**
++ * Opaque object representing a AF_BUS-based server implementation.
++ */
++typedef struct DBusServerAfbus DBusServerAfbus;
++
++/**
++ * Implementation details of DBusServerAfbus. All members
++ * are private.
++ */
++struct DBusServerAfbus
++{
++ DBusServer base; /**< Parent class members. */
++ int fd; /**< File descriptor. */
++ DBusWatch *watch; /**< File descriptor watch. */
++ DBusString address; /**< The server address */
++};
++
++static void
++afbus_finalize (DBusServer *server)
++{
++ DBusServerAfbus *afbus_server = (DBusServerAfbus *) server;
++
++ _dbus_server_finalize_base (server);
++
++ if (afbus_server->watch != NULL)
++ {
++ _dbus_watch_unref (afbus_server->watch);
++ afbus_server->watch = NULL;
++ }
++
++ dbus_free (server);
++}
++
++static void
++afbus_disconnect (DBusServer *server)
++{
++ DBusServerAfbus *afbus_server = (DBusServerAfbus *) server;
++
++ HAVE_LOCK_CHECK (server);
++
++ if (afbus_server->watch)
++ {
++ _dbus_server_remove_watch (server, afbus_server->watch);
++ _dbus_watch_invalidate (afbus_server->watch);
++ _dbus_watch_unref (afbus_server->watch);
++ afbus_server->watch = NULL;
++ }
++
++ _dbus_close_socket (afbus_server->fd, NULL);
++ afbus_server->fd = -1;
++
++ HAVE_LOCK_CHECK (server);
++}
++
++static const DBusServerVTable afbus_vtable = {
++ afbus_finalize,
++ afbus_disconnect
++};
++
++static dbus_bool_t
++handle_new_client (DBusServer *server,
++ int client_fd)
++{
++ DBusTransport *transport;
++ DBusConnection *connection;
++ DBusNewConnectionFunction new_connection_function;
++ void *new_connection_data;
++
++ _dbus_verbose ("Creating new client connection with fd %d\n", client_fd);
++
++ if (!_dbus_set_fd_nonblocking (client_fd, NULL))
++ {
++ SERVER_UNLOCK (server);
++ return TRUE;
++ }
++
++ transport = _dbus_transport_new_for_afbus (client_fd, &server->guid_hex, NULL);
++ if (transport == NULL)
++ {
++ _dbus_close_socket (client_fd, NULL);
++ SERVER_UNLOCK (server);
++ return FALSE;
++ }
++
++ if (!_dbus_transport_set_auth_mechanisms (transport,
++ (const char **) server->auth_mechanisms))
++ {
++ _dbus_transport_unref (transport);
++ SERVER_UNLOCK (server);
++ return FALSE;
++ }
++
++ /* note that client_fd is now owned by the transport, and will be
++ * closed on transport disconnection/finalization
++ */
++ connection = _dbus_connection_new_for_transport (transport);
++ _dbus_transport_unref (transport);
++ transport = NULL; /* now under the connection lock */
++
++ if (connection == NULL)
++ {
++ SERVER_UNLOCK (server);
++ return FALSE;
++ }
++
++ /* See if someone wants to handle this new connection, self-referencing
++ * for paranoia.
++ */
++ new_connection_function = server->new_connection_function;
++ new_connection_data = server->new_connection_data;
++
++ _dbus_server_ref_unlocked (server);
++ SERVER_UNLOCK (server);
++
++ if (new_connection_function)
++ {
++ (* new_connection_function) (server, connection,
++ new_connection_data);
++ }
++ dbus_server_unref (server);
++
++ /* If no one grabbed a reference, the connection will die. */
++ _dbus_connection_close_if_only_one_ref (connection);
++ dbus_connection_unref (connection);
++
++ return TRUE;
++}
++
++static dbus_bool_t
++afbus_handle_watch (DBusWatch *watch,
++ unsigned int flags,
++ void *data)
++{
++ DBusServerAfbus *afbus_server = (DBusServerAfbus *) data;
++ DBusServer *server = (DBusServer *) data;
++
++ SERVER_LOCK (server);
++
++#ifndef DBUS_DISABLE_ASSERT
++ _dbus_assert (afbus_server->watch == watch);
++#endif
++
++ _dbus_verbose ("Handling client connection, flags 0x%x\n", flags);
++
++ if (flags & DBUS_WATCH_READABLE)
++ {
++ int client_fd;
++
++ client_fd = _dbus_accept (afbus_server->fd);
++ if (client_fd < 0)
++ {
++ /* EINTR handled for us */
++
++ if (_dbus_get_is_errno_eagain_or_ewouldblock ())
++ _dbus_verbose ("No client available to accept after all\n");
++ else
++ _dbus_verbose ("Failed to accept a client connection: %s\n",
++ _dbus_strerror_from_errno ());
++
++ SERVER_UNLOCK (server);
++ }
++ else
++ {
++ if (!handle_new_client (server, client_fd))
++ _dbus_verbose ("Rejected client connection due to lack of memory\n");
++ }
++ }
++
++ if (flags & DBUS_WATCH_ERROR)
++ _dbus_verbose ("Error on server listening socket\n");
++
++ if (flags & DBUS_WATCH_HANGUP)
++ _dbus_verbose ("Hangup on server listening socket\n");
++
++ return TRUE;
++}
++
++static DBusServer *
++_dbus_server_new_for_afbus (int fd, const char *path, DBusError *error)
++{
++ DBusServerAfbus *afbus_server;
++ DBusServer *server;
++ struct sockaddr_bus sock_address;
++
++ afbus_server = dbus_new0 (DBusServerAfbus, 1);
++ if (afbus_server == NULL)
++ return NULL;
++
++ if (!_dbus_string_init (&afbus_server->address) ||
++ !_dbus_string_append (&afbus_server->address, "afbus:path=") ||
++ !_dbus_string_append (&afbus_server->address, path))
++ {
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ goto failed_1;
++ }
++
++ afbus_server->fd = fd;
++
++ sock_address.sbus_family = AF_BUS;
++ strcpy (sock_address.sbus_path, path);
++ if (bind (afbus_server->fd, (struct sockaddr *) &sock_address, sizeof (sock_address)) < 0)
++ {
++ dbus_set_error (error, _dbus_error_from_errno (errno),
++ "Failed to bind socket \"%s\": %s",
++ path, _dbus_strerror (errno));
++ goto failed_1;
++ }
++
++ if (listen (afbus_server->fd, 30 /* backlog */) < 0)
++ {
++ dbus_set_error (error, _dbus_error_from_errno (errno),
++ "Failed to listen on AF_BUS socket: %s",
++ _dbus_strerror (errno));
++ goto failed_1;
++ }
++
++ afbus_server->watch = _dbus_watch_new (fd,
++ DBUS_WATCH_READABLE,
++ TRUE,
++ afbus_handle_watch, afbus_server,
++ NULL);
++ if (afbus_server->watch == NULL)
++ goto failed_1;
++
++ if (!_dbus_server_init_base (&afbus_server->base,
++ &afbus_vtable, &afbus_server->address))
++ goto failed_2;
++
++ server = (DBusServer *) afbus_server;
++ server->is_afbus = TRUE;
++
++
++ SERVER_LOCK (server);
++
++ if (!_dbus_server_add_watch (&afbus_server->base,
++ afbus_server->watch))
++ {
++ SERVER_UNLOCK (server);
++ _dbus_server_finalize_base (&afbus_server->base);
++
++ goto failed_2;
++ }
++
++ SERVER_UNLOCK (server);
++
++ _dbus_server_trace_ref (&afbus_server->base, 0, 1, "new_for_afbus");
++ return (DBusServer *) afbus_server;
++
++ failed_2:
++ _dbus_watch_unref (afbus_server->watch);
++
++ failed_1:
++ _dbus_close_socket (afbus_server->fd, NULL);
++ dbus_free (afbus_server);
++
++ return NULL;
++}
++
++/**
++ * Starts a DBusServer listening on AF_BUS socket.
++ * Sets error if the result is not OK.
++ *
++ * @param entry an address entry
++ * @param server_p location to store a new DBusServer, or #NULL on failure.
++ * @param error location to store rationale for failure on bad address
++ * @returns the outcome
++ *
++ */
++DBusServerListenResult
++_dbus_server_listen_afbus (DBusAddressEntry *entry,
++ DBusServer **server_p,
++ DBusError *error)
++{
++ const char *method, *path, *tmpdir;
++ int listen_fd;
++
++ *server_p = NULL;
++
++ method = dbus_address_entry_get_method (entry);
++ if (strcmp (method, "afbus") != 0)
++ {
++ /* If we don't handle the method, we return NULL with the
++ * error unset
++ */
++ _DBUS_ASSERT_ERROR_IS_CLEAR(error);
++ return DBUS_SERVER_LISTEN_NOT_HANDLED;
++ }
++
++ path = dbus_address_entry_get_value (entry, "path");
++ tmpdir = dbus_address_entry_get_value (entry, "tmpdir");
++
++ if (path == NULL && tmpdir == NULL)
++ {
++ _dbus_set_bad_address(error, "unix",
++ "path or tmpdir",
++ NULL);
++ return DBUS_SERVER_LISTEN_BAD_ADDRESS;
++ }
++
++ if (path && tmpdir)
++ {
++ _dbus_set_bad_address(error, NULL, NULL,
++ "cannot specify both \"path\" and \"tmpdir\" at the same time");
++ return DBUS_SERVER_LISTEN_BAD_ADDRESS;
++ }
++
++ if (!_dbus_open_socket (&listen_fd, PF_BUS, SOCK_SEQPACKET, BUS_PROTO_DBUS, error))
++ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++
++ if (!_dbus_set_fd_nonblocking (listen_fd, error))
++ goto failed_1;
++
++ if (tmpdir != NULL)
++ {
++ DBusString full_path;
++ DBusString filename;
++
++ if (!_dbus_string_init (&full_path))
++ {
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++ }
++
++ if (!_dbus_string_init (&filename))
++ {
++ _dbus_string_free (&full_path);
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++ }
++
++ if (!_dbus_string_append (&filename,
++ "dbus-") ||
++ !_dbus_generate_random_ascii (&filename, 10) ||
++ !_dbus_string_append (&full_path, tmpdir) ||
++ !_dbus_concat_dir_and_file (&full_path, &filename))
++ {
++ _dbus_string_free (&full_path);
++ _dbus_string_free (&filename);
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++ }
++
++ path = _dbus_string_get_const_data (&full_path);
++ }
++
++ *server_p = _dbus_server_new_for_afbus (listen_fd, path, error);
++ if (*server_p == NULL)
++ goto failed_1;
++
++ return DBUS_SERVER_LISTEN_OK;
++
++ failed_1:
++ _dbus_close_socket (listen_fd, NULL);
++
++ return DBUS_SERVER_LISTEN_DID_NOT_CONNECT;
++}
+diff --git a/dbus/dbus-server-afbus.h b/dbus/dbus-server-afbus.h
+new file mode 100644
+index 0000000..8e5ad31
+--- /dev/null
++++ b/dbus/dbus-server-afbus.h
+@@ -0,0 +1,36 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* dbus-server-unix.h Server implementation for Unix network protocols.
++ *
++ * Copyright (C) 2012 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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
++ *
++ */
++#ifndef DBUS_SERVER_AFBUS_H
++#define DBUS_SERVER_AFBUS_H
++
++#include "dbus-server-protected.h"
++
++DBUS_BEGIN_DECLS
++
++DBusServerListenResult _dbus_server_listen_afbus (DBusAddressEntry *entry,
++ DBusServer **server_p,
++ DBusError *error);
++
++DBUS_END_DECLS
++
++#endif
+diff --git a/dbus/dbus-server-protected.h b/dbus/dbus-server-protected.h
+index dd5234b..b423cb9 100644
+--- a/dbus/dbus-server-protected.h
++++ b/dbus/dbus-server-protected.h
+@@ -89,6 +89,9 @@ struct DBusServer
+ #ifndef DBUS_DISABLE_CHECKS
+ unsigned int have_server_lock : 1; /**< Does someone have the server mutex locked */
+ #endif
++#ifdef HAVE_AFBUS
++ unsigned int is_afbus : 1; /**< TRUE if this server listen on a AF_BUS socket */
++#endif
+ };
+
+ dbus_bool_t _dbus_server_init_base (DBusServer *server,
+diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c
+index b62c2b4..2a23252 100644
+--- a/dbus/dbus-server.c
++++ b/dbus/dbus-server.c
+@@ -25,6 +25,9 @@
+ #include "dbus-server.h"
+ #include "dbus-server-unix.h"
+ #include "dbus-server-socket.h"
++#ifdef HAVE_AFBUS
++#include "dbus-server-afbus.h"
++#endif
+ #include "dbus-string.h"
+ #ifdef DBUS_BUILD_TESTS
+ #include "dbus-server-debug-pipe.h"
+@@ -529,6 +532,9 @@ static const struct {
+ } listen_funcs[] = {
+ { _dbus_server_listen_socket }
+ , { _dbus_server_listen_platform_specific }
++#ifdef HAVE_AFBUS
++ , { _dbus_server_listen_afbus }
++#endif
+ #ifdef DBUS_BUILD_TESTS
+ , { _dbus_server_listen_debug_pipe }
+ #endif
+@@ -844,6 +850,30 @@ dbus_server_get_address (DBusServer *server)
+ }
+
+ /**
++ * Returns TRUE if the server listens on an AF_BUS address
++ *
++ * @param server the server
++ * @returns TRUE if the server listens on an AF_BUS address
++ */
++dbus_bool_t
++dbus_server_is_afbus (DBusServer *server)
++{
++ dbus_bool_t retval;
++
++ _dbus_return_val_if_fail (server != NULL, FALSE);
++
++#ifdef HAVE_AFBUS
++ SERVER_LOCK (server);
++ retval = server->is_afbus;
++ SERVER_UNLOCK (server);
++#else
++ retval = FALSE;
++#endif
++
++ return retval;
++}
++
++/**
+ * Returns the unique ID of the server, as a newly-allocated
+ * string which must be freed by the caller. This ID is
+ * normally used by clients to tell when two #DBusConnection
+diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h
+index bdbefa0..49cb9cf 100644
+--- a/dbus/dbus-server.h
++++ b/dbus/dbus-server.h
+@@ -62,6 +62,8 @@ dbus_bool_t dbus_server_get_is_connected (DBusServer *server);
+ DBUS_EXPORT
+ char* dbus_server_get_address (DBusServer *server);
+ DBUS_EXPORT
++dbus_bool_t dbus_server_is_afbus (DBusServer *server);
++DBUS_EXPORT
+ char* dbus_server_get_id (DBusServer *server);
+ DBUS_EXPORT
+ void dbus_server_set_new_connection_function (DBusServer *server,
+diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
+index 6a57670..b6b29b3 100644
+--- a/dbus/dbus-shared.h
++++ b/dbus/dbus-shared.h
+@@ -80,6 +80,10 @@ typedef enum
+ #define DBUS_PATH_DBUS "/org/freedesktop/DBus"
+ /** The object path used in local/in-process-generated messages. */
+ #define DBUS_PATH_LOCAL "/org/freedesktop/DBus/Local"
++#ifdef HAVE_AFBUS
++/** The object path used for AF_BUS sockets. */
++#define DBUS_PATH_AFBUS "/org/freedesktop/DBus/AF_BUS"
++#endif
+
+ /* Interfaces, these #define don't do much other than
+ * catch typos at compile time
+@@ -92,6 +96,10 @@ typedef enum
+ #define DBUS_INTERFACE_PROPERTIES "org.freedesktop.DBus.Properties"
+ /** The interface supported by most dbus peers */
+ #define DBUS_INTERFACE_PEER "org.freedesktop.DBus.Peer"
++#ifdef HAVE_AFBUS
++/** The interface supported by AF_BUS transport */
++#define DBUS_INTERFACE_AFBUS "org.freedesktop.DBus.AF_BUS"
++#endif
+
+ /** This is a special interface whose methods can only be invoked
+ * by the local implementation (messages from remote apps aren't
+diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
+index cef8bd3..26e3d00 100644
+--- a/dbus/dbus-sysdeps-unix.c
++++ b/dbus/dbus-sysdeps-unix.c
+@@ -122,7 +122,7 @@
+
+ #endif /* Solaris */
+
+-static dbus_bool_t
++dbus_bool_t
+ _dbus_open_socket (int *fd_p,
+ int domain,
+ int type,
+diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h
+index 4052cda..a589486 100644
+--- a/dbus/dbus-sysdeps.h
++++ b/dbus/dbus-sysdeps.h
+@@ -125,6 +125,11 @@ typedef unsigned long dbus_gid_t;
+ *
+ */
+
++dbus_bool_t _dbus_open_socket (int *fd_p,
++ int domain,
++ int type,
++ int protocol,
++ DBusError *error);
+ dbus_bool_t _dbus_close_socket (int fd,
+ DBusError *error);
+ int _dbus_read_socket (int fd,
+diff --git a/dbus/dbus-transport-afbus.c b/dbus/dbus-transport-afbus.c
+new file mode 100644
+index 0000000..9574bca
+--- /dev/null
++++ b/dbus/dbus-transport-afbus.c
+@@ -0,0 +1,394 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* dbus-transport-socket.h Socket subclasses of DBusTransport
++ *
++ * Copyright (C) 212 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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 <errno.h>
++#include <sys/socket.h>
++#include "dbus-connection-internal.h"
++#include "dbus-hash.h"
++#include "dbus-transport-afbus.h"
++#include "dbus-transport-socket.h"
++#include "dbus-watch.h"
++
++static DBusHashTable *wkn_addresses_cache = NULL;
++
++/**
++ * @defgroup DBusTransportAfbus AF_BUS-based DBusTransport implementation
++ * @ingroup DBusInternals
++ * @brief Implementation details of DBusTransport on AF_BUS sockets
++ *
++ * @{
++ */
++
++/**
++ * Opaque object representing a AF_BUS-based transport.
++ */
++typedef struct DBusTransportAfbus DBusTransportAfbus;
++
++/**
++ * Implementation details of DBusTransportAfbus. All members are private.
++ */
++struct DBusTransportAfbus
++{
++ DBusTransportSocket base; /**< Parent instance */
++};
++
++static dbus_bool_t
++get_write_destination (int fd,
++ DBusMessage *message,
++ struct sockaddr_bus *sock)
++{
++ socklen_t addrlen;
++ const char *destination;
++ const char *sender;
++
++ /* if the sender is the bus driver, don't set the sockaddr, just let the
++ * message be delivered to the peer socket
++ */
++ sender = dbus_message_get_sender (message);
++ if (sender && strcmp (sender, DBUS_SERVICE_DBUS) == 0)
++ {
++ return FALSE;
++ }
++
++ addrlen = sizeof(struct sockaddr_bus);
++ if (getsockname (fd, (struct sockaddr *) sock, &addrlen) != 0)
++ return FALSE;
++ if (addrlen != sizeof(struct sockaddr_bus))
++ return FALSE;
++ if (sock->sbus_family != AF_BUS)
++ return FALSE;
++
++ destination = dbus_message_get_destination (message);
++ if (destination && strcmp (destination, DBUS_SERVICE_DBUS) == 0)
++ {
++ /* a message for the bus driver */
++ sock->sbus_addr.s_addr = 0;
++ return TRUE;
++ }
++
++ if (destination != NULL && strlen (destination) > 0)
++ {
++ dbus_uint64_t peer = 0x0000000000000000ULL;
++
++ /* If destination is a unique name, just retrieve the peer address from it */
++ if (strncmp (destination, ":AF-BUS.", 8) == 0)
++ {
++ DBusString tmp;
++
++ _dbus_string_init_const (&tmp, &destination[8]);
++ if (!_dbus_string_parse_uint (&tmp, 0, (unsigned long *) &peer, NULL))
++ peer = 0x0000000000000000ULL;
++ _dbus_string_free (&tmp);
++ }
++ else
++ {
++ /* a message for a well known name */
++ if (wkn_addresses_cache != NULL)
++ {
++ dbus_uint64_t *peer_pointer;
++
++ peer_pointer = (dbus_uint64_t *) _dbus_hash_table_lookup_string (wkn_addresses_cache, destination);
++ if (peer_pointer != NULL)
++ peer = *peer_pointer;
++ }
++ }
++
++ sock->sbus_addr.s_addr = peer;
++
++ return TRUE;
++ }
++ else
++ {
++ /* a multicast message */
++ sock->sbus_addr.s_addr = 0x0000ffffffffffffULL;
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++static int
++afbus_write_socket (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *buffer,
++ int start,
++ int len)
++{
++ int fd, bytes_written;
++ struct sockaddr_bus sock;
++
++ if (!_dbus_transport_get_socket_fd ((DBusTransport *) socket_transport, &fd))
++ {
++ _dbus_verbose ("Couldn't get socket's file descriptor\n");
++ return -1;
++ }
++
++ if (get_write_destination (fd, message, &sock))
++ {
++ const char *data;
++
++ /* Send the data to specific address */
++ data = _dbus_string_get_const_data_len (buffer, start, len);
++
++ bytes_written = sendto (fd, data, len, MSG_NOSIGNAL,
++ (struct sockaddr *) &sock, sizeof (struct sockaddr_bus));
++ }
++ else
++ bytes_written = _dbus_write_socket (fd, buffer, start, len);
++
++ return bytes_written;
++}
++
++static int
++afbus_write_socket_two (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *header,
++ int header_start,
++ int header_len,
++ const DBusString *body,
++ int body_start,
++ int body_len)
++{
++ int fd, bytes_written;
++ struct sockaddr_bus sock;
++
++ if (!_dbus_transport_get_socket_fd ((DBusTransport *) socket_transport, &fd))
++ {
++ _dbus_verbose ("Couldn't get socket's file descriptor\n");
++ return -1;
++ }
++
++ if (get_write_destination (fd, message, &sock))
++ {
++ struct iovec vectors[2];
++ const char *data1, *data2;
++ struct msghdr m;
++
++ data1 = _dbus_string_get_const_data_len (header, header_start, header_len);
++ if (body != NULL)
++ data2 = _dbus_string_get_const_data_len (body, body_start, body_len);
++ else
++ {
++ data2 = NULL;
++ body_start = body_len = 0;
++ }
++
++ vectors[0].iov_base = (char *) data1;
++ vectors[0].iov_len = header_len;
++ vectors[1].iov_base = (char *) data2;
++ vectors[1].iov_len = body_len;
++
++ _DBUS_ZERO(m);
++ m.msg_iov = vectors;
++ m.msg_iovlen = data2 ? 2 : 1;
++ m.msg_name = &sock;
++ m.msg_namelen = sizeof (sock);
++
++ again:
++ bytes_written = sendmsg (fd, &m, MSG_NOSIGNAL);
++ if (bytes_written < 0 && errno == EINTR)
++ goto again;
++ }
++ else
++ bytes_written = _dbus_write_socket_two (fd, header, header_start, header_len, body, body_start, body_len);
++
++ return bytes_written;
++}
++
++static void
++afbus_authenticated (DBusTransportSocket *socket_transport)
++{
++ if (socket_transport->base.is_server)
++ {
++ /* Make the client join the bus when authenticated, so that it can send
++ * unicast messages to peers other than the daemon */
++ if (setsockopt (socket_transport->fd, SOL_BUS, BUS_JOIN_BUS, NULL, 0) != 0)
++ {
++ _dbus_verbose ("Could not join client to the bus\n");
++ }
++ }
++}
++
++static void
++afbus_message_received (DBusTransportSocket *socket_transport,
++ DBusMessage *message)
++{
++ if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL)
++ {
++ const char *path, *interface, *member;
++
++ path = dbus_message_get_path (message);
++ interface = dbus_message_get_interface (message);
++ member = dbus_message_get_member (message);
++
++ if (strcmp (path, DBUS_PATH_AFBUS) == 0
++ && strcmp (interface, DBUS_INTERFACE_AFBUS) == 0
++ && strcmp (member, "Forwarded") == 0)
++ {
++ char *wkn;
++ dbus_uint64_t peer;
++ dbus_uint64_t *peer_pointer;
++
++ /* Update the cache */
++ if (wkn_addresses_cache == NULL)
++ {
++ wkn_addresses_cache = _dbus_hash_table_new (DBUS_HASH_STRING,
++ dbus_free,
++ dbus_free);
++ if (wkn_addresses_cache == NULL)
++ return;
++ }
++
++ dbus_message_get_args (message, NULL,
++ DBUS_TYPE_STRING, &wkn,
++ DBUS_TYPE_UINT64, &peer,
++ DBUS_TYPE_INVALID);
++
++ peer_pointer = dbus_new (dbus_uint64_t, 1);
++ *peer_pointer = peer;
++ _dbus_hash_table_insert_string (wkn_addresses_cache,
++ _dbus_strdup (wkn),
++ (void *) peer_pointer);
++ }
++ }
++}
++
++static const DBusTransportSocketVTable afbus_vtable = {
++ afbus_write_socket,
++ afbus_write_socket_two,
++ afbus_authenticated,
++ afbus_message_received
++};
++
++/**
++ * Creates a new AF_BUS-based transport for the given socket descriptor.
++ *
++ * @param fd the file descriptor.
++ * @param server_guid non-#NULL if this transport is on the server side of a connection
++ * @param address the transport's address
++ * @returns the new transport, or #NULL if no memory.
++ */
++DBusTransport*
++_dbus_transport_new_for_afbus (int fd,
++ const DBusString *server_guid,
++ const DBusString *address)
++{
++ DBusTransportAfbus *afbus_transport;
++
++ afbus_transport = dbus_new0 (DBusTransportAfbus, 1);
++ if (afbus_transport == NULL)
++ return NULL;
++
++ if (!_dbus_transport_socket_init_base (&afbus_transport->base,
++ fd,
++ &afbus_vtable,
++ server_guid, address))
++ goto failed_1;
++
++ return (DBusTransport *) afbus_transport;
++
++ failed_1:
++ dbus_free (afbus_transport);
++
++ return NULL;
++}
++
++/**
++ * Opens a AF_BUS-based transport.
++ *
++ * @param entry the address entry to try opening as a tcp transport.
++ * @param transport_p return location for the opened transport
++ * @param error error to be set
++ * @returns result of the attempt
++ */
++DBusTransportOpenResult
++_dbus_transport_open_afbus (DBusAddressEntry *entry,
++ DBusTransport **transport_p,
++ DBusError *error)
++{
++ const char *method, *path;
++ DBusString address;
++ int fd;
++ struct sockaddr_bus sock_address;
++
++ method = dbus_address_entry_get_method (entry);
++ if (strcmp (method, "afbus") != 0)
++ {
++ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
++ return DBUS_TRANSPORT_OPEN_NOT_HANDLED;
++ }
++
++ path = dbus_address_entry_get_value (entry, "path");
++ if (path == NULL)
++ {
++ _dbus_set_bad_address (error, "afbus",
++ "path or tmpdir",
++ NULL);
++ return DBUS_TRANSPORT_OPEN_BAD_ADDRESS;
++ }
++
++ if (!_dbus_string_init (&address) ||
++ !_dbus_string_append (&address, "afbus:path=") ||
++ !_dbus_string_append (&address, path))
++ {
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
++ }
++
++ if (!_dbus_open_socket (&fd, PF_BUS, SOCK_SEQPACKET, BUS_PROTO_DBUS, error))
++ goto failed_1;
++
++ if (!_dbus_set_fd_nonblocking (fd, error))
++ goto failed_2;
++
++ sock_address.sbus_family = AF_BUS;
++ strcpy (sock_address.sbus_path, path);
++ if (connect (fd, (struct sockaddr *) &sock_address, sizeof (sock_address)) < 0)
++ {
++ dbus_set_error (error,
++ _dbus_error_from_errno (errno),
++ "Failed to connect to socket %s: %s",
++ path, _dbus_strerror (errno));
++ goto failed_2;
++ }
++
++ *transport_p = _dbus_transport_new_for_afbus (fd, NULL, &address);
++ if (*transport_p == NULL)
++ {
++ dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
++ goto failed_2;
++ }
++
++ _dbus_string_free (&address);
++
++ return DBUS_TRANSPORT_OPEN_OK;
++
++ failed_2:
++ _dbus_close_socket (fd, NULL);
++
++ failed_1:
++ _dbus_string_free (&address);
++
++ return DBUS_TRANSPORT_OPEN_DID_NOT_CONNECT;
++}
+diff --git a/dbus/dbus-transport-afbus.h b/dbus/dbus-transport-afbus.h
+new file mode 100644
+index 0000000..c94e32d
+--- /dev/null
++++ b/dbus/dbus-transport-afbus.h
+@@ -0,0 +1,41 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* dbus-transport-socket.h Socket subclasses of DBusTransport
++ *
++ * Copyright (C) 212 Collabora Ltd
++ *
++ * 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
++ * (at your option) any later version.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * 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
++ *
++ */
++#ifndef DBUS_TRANSPORT_AFBUS_H
++#define DBUS_TRANSPORT_AFBUS_H
++
++#include <sys/socket.h>
++#include <sys/bus.h>
++#include <dbus/dbus-transport-protected.h>
++
++DBUS_BEGIN_DECLS
++
++DBusTransport *_dbus_transport_new_for_afbus (int fd,
++ const DBusString *server_guid,
++ const DBusString *address);
++DBusTransportOpenResult _dbus_transport_open_afbus (DBusAddressEntry *entry,
++ DBusTransport **transport_p,
++ DBusError *error);
++
++DBUS_END_DECLS
++
++#endif
+diff --git a/dbus/dbus-transport-protected.h b/dbus/dbus-transport-protected.h
+index 44b9d78..9becbdb 100644
+--- a/dbus/dbus-transport-protected.h
++++ b/dbus/dbus-transport-protected.h
+@@ -69,6 +69,10 @@ struct DBusTransportVTable
+ dbus_bool_t (* get_socket_fd) (DBusTransport *transport,
+ int *fd_p);
+ /**< Get socket file descriptor */
++
++ void (* process_incoming_message) (DBusTransport *transport,
++ DBusMessage *message);
++ /**> Method to allow transport to filter messages */
+ };
+
+ /**
+diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c
+index 544d00a..a3951ef 100644
+--- a/dbus/dbus-transport-socket.c
++++ b/dbus/dbus-transport-socket.c
+@@ -22,6 +22,7 @@
+ */
+
+ #include <config.h>
++#include <sys/ioctl.h>
+ #include "dbus-internals.h"
+ #include "dbus-connection-internal.h"
+ #include "dbus-nonce.h"
+@@ -38,43 +39,13 @@
+ * @{
+ */
+
+-/**
+- * Opaque object representing a socket file descriptor transport.
+- */
+-typedef struct DBusTransportSocket DBusTransportSocket;
+-
+-/**
+- * Implementation details of DBusTransportSocket. All members are private.
+- */
+-struct DBusTransportSocket
+-{
+- DBusTransport base; /**< Parent instance */
+- int fd; /**< File descriptor. */
+- DBusWatch *read_watch; /**< Watch for readability. */
+- DBusWatch *write_watch; /**< Watch for writability. */
+-
+- int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
+- int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
+-
+- int message_bytes_written; /**< Number of bytes of current
+- * outgoing message that have
+- * been written.
+- */
+- DBusString encoded_outgoing; /**< Encoded version of current
+- * outgoing message.
+- */
+- DBusString encoded_incoming; /**< Encoded version of current
+- * incoming data.
+- */
+-};
+-
+ static void
+ free_watches (DBusTransport *transport)
+ {
+ DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
+
+ _dbus_verbose ("start\n");
+-
++
+ if (socket_transport->read_watch)
+ {
+ if (transport->connection)
+@@ -104,7 +75,7 @@ socket_finalize (DBusTransport *transport)
+ DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
+
+ _dbus_verbose ("\n");
+-
++
+ free_watches (transport);
+
+ _dbus_string_free (&socket_transport->encoded_outgoing);
+@@ -136,7 +107,16 @@ check_write_watch (DBusTransport *transport)
+ _dbus_transport_ref (transport);
+
+ if (_dbus_transport_get_is_authenticated (transport))
+- needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
++ {
++ if (!socket_transport->auth_notified &&
++ socket_transport->vtable->authenticated != NULL)
++ {
++ socket_transport->auth_notified = TRUE;
++ socket_transport->vtable->authenticated (socket_transport);
++ }
++
++ needed = _dbus_connection_has_messages_to_send_unlocked (transport->connection);
++ }
+ else
+ {
+ if (transport->send_credentials_pending)
+@@ -146,7 +126,7 @@ check_write_watch (DBusTransport *transport)
+ DBusAuthState auth_state;
+
+ auth_state = _dbus_auth_do_work (transport->auth);
+-
++
+ /* If we need memory we install the write watch just in case,
+ * if there's no need for it, it will get de-installed
+ * next time we try reading.
+@@ -191,9 +171,18 @@ check_read_watch (DBusTransport *transport)
+ _dbus_transport_ref (transport);
+
+ if (_dbus_transport_get_is_authenticated (transport))
+- need_read_watch =
+- (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
+- (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
++ {
++ if (!socket_transport->auth_notified &&
++ socket_transport->vtable->authenticated != NULL)
++ {
++ socket_transport->auth_notified = TRUE;
++ socket_transport->vtable->authenticated (socket_transport);
++ }
++
++ need_read_watch =
++ (_dbus_counter_get_size_value (transport->live_messages) < transport->max_live_messages_size) &&
++ (_dbus_counter_get_unix_fd_value (transport->live_messages) < transport->max_live_messages_unix_fds);
++ }
+ else
+ {
+ if (transport->receive_credentials_pending)
+@@ -489,6 +478,59 @@ do_authentication (DBusTransport *transport,
+ return TRUE;
+ }
+
++static int
++_write_socket (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *buffer,
++ int start,
++ int len)
++{
++ int bytes_written;
++
++ if (socket_transport->vtable->write_socket != NULL)
++ {
++ bytes_written = socket_transport->vtable->write_socket (socket_transport,
++ message,
++ buffer, start, len);
++ }
++ else
++ {
++ bytes_written = _dbus_write_socket (socket_transport->fd,
++ buffer,
++ start, len);
++ }
++
++ return bytes_written;
++}
++
++static int
++_write_socket_two (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *header,
++ int header_start,
++ int header_len,
++ const DBusString *body,
++ int body_start,
++ int body_len)
++{
++ int bytes_written;
++
++ if (socket_transport->vtable->write_socket_two != NULL)
++ {
++ bytes_written = socket_transport->vtable->write_socket_two (socket_transport, message,
++ header, header_start, header_len,
++ body, body_start, body_len);
++ }
++ else
++ {
++ bytes_written = _dbus_write_socket_two (socket_transport->fd,
++ header, header_start, header_len,
++ body, body_start, body_len);
++ }
++
++ return bytes_written;
++}
++
+ /* returns false on oom */
+ static dbus_bool_t
+ do_writing (DBusTransport *transport)
+@@ -579,12 +621,13 @@ do_writing (DBusTransport *transport)
+ _dbus_verbose ("encoded message is %d bytes\n",
+ total_bytes_to_write);
+ #endif
+-
++
+ bytes_written =
+- _dbus_write_socket (socket_transport->fd,
+- &socket_transport->encoded_outgoing,
+- socket_transport->message_bytes_written,
+- total_bytes_to_write - socket_transport->message_bytes_written);
++ _write_socket (socket_transport,
++ message,
++ &socket_transport->encoded_outgoing,
++ socket_transport->message_bytes_written,
++ total_bytes_to_write - socket_transport->message_bytes_written);
+ }
+ else
+ {
+@@ -623,21 +666,23 @@ do_writing (DBusTransport *transport)
+ if (socket_transport->message_bytes_written < header_len)
+ {
+ bytes_written =
+- _dbus_write_socket_two (socket_transport->fd,
+- header,
+- socket_transport->message_bytes_written,
+- header_len - socket_transport->message_bytes_written,
+- body,
+- 0, body_len);
++ _write_socket_two (socket_transport,
++ message,
++ header,
++ socket_transport->message_bytes_written,
++ header_len - socket_transport->message_bytes_written,
++ body,
++ 0, body_len);
+ }
+ else
+ {
+ bytes_written =
+- _dbus_write_socket (socket_transport->fd,
+- body,
+- (socket_transport->message_bytes_written - header_len),
+- body_len -
+- (socket_transport->message_bytes_written - header_len));
++ _write_socket (socket_transport,
++ message,
++ body,
++ (socket_transport->message_bytes_written - header_len),
++ body_len -
++ (socket_transport->message_bytes_written - header_len));
+ }
+ }
+ }
+@@ -696,7 +741,7 @@ do_reading (DBusTransport *transport)
+ {
+ DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
+ DBusString *buffer;
+- int bytes_read;
++ int bytes_read, bytes_available;
+ int total;
+ dbus_bool_t oom;
+
+@@ -730,7 +775,12 @@ do_reading (DBusTransport *transport)
+
+ if (!dbus_watch_get_enabled (socket_transport->read_watch))
+ return TRUE;
+-
++
++ if (ioctl (socket_transport->fd, FIONREAD, &bytes_available) < 0)
++ bytes_available = socket_transport->max_bytes_read_per_iteration;
++ else if (bytes_available < socket_transport->max_bytes_read_per_iteration)
++ bytes_available = socket_transport->max_bytes_read_per_iteration;
++
+ if (_dbus_auth_needs_decoding (transport->auth))
+ {
+ /* Does fd passing even make sense with encoded data? */
+@@ -741,7 +791,7 @@ do_reading (DBusTransport *transport)
+ else
+ bytes_read = _dbus_read_socket (socket_transport->fd,
+ &socket_transport->encoded_incoming,
+- socket_transport->max_bytes_read_per_iteration);
++ bytes_available);
+
+ _dbus_assert (_dbus_string_get_length (&socket_transport->encoded_incoming) ==
+ bytes_read);
+@@ -796,7 +846,7 @@ do_reading (DBusTransport *transport)
+
+ bytes_read = _dbus_read_socket_with_unix_fds(socket_transport->fd,
+ buffer,
+- socket_transport->max_bytes_read_per_iteration,
++ bytes_available,
+ fds, &n_fds);
+
+ if (bytes_read >= 0 && n_fds > 0)
+@@ -808,7 +858,7 @@ do_reading (DBusTransport *transport)
+ #endif
+ {
+ bytes_read = _dbus_read_socket (socket_transport->fd,
+- buffer, socket_transport->max_bytes_read_per_iteration);
++ buffer, bytes_available);
+ }
+
+ _dbus_message_loader_return_buffer (transport->loader,
+@@ -1207,6 +1257,19 @@ socket_get_socket_fd (DBusTransport *transport,
+ return TRUE;
+ }
+
++static void
++socket_process_incoming_message (DBusTransport *transport,
++ DBusMessage *message)
++{
++ DBusTransportSocket *socket_transport = (DBusTransportSocket*) transport;
++
++ if (socket_transport->vtable->message_received != NULL)
++ {
++ (* socket_transport->vtable->message_received) (socket_transport,
++ message);
++ }
++}
++
+ static const DBusTransportVTable socket_vtable = {
+ socket_finalize,
+ socket_handle_watch,
+@@ -1214,37 +1277,40 @@ static const DBusTransportVTable socket_vtable = {
+ socket_connection_set,
+ socket_do_iteration,
+ socket_live_messages_changed,
+- socket_get_socket_fd
++ socket_get_socket_fd,
++ socket_process_incoming_message
+ };
+
+ /**
+- * Creates a new transport for the given socket file descriptor. The file
+- * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
+- * make it so). This function is shared by various transports that
+- * boil down to a full duplex file descriptor.
++ * Initializes the base class members of DBusTransportSocket. Chained up to
++ * by subclasses in their constructor. The server GUID is the
++ * globally unique ID for the server creating this connection
++ * and will be #NULL for the client side of a connection. The GUID
++ * is in hex format.
+ *
+- * @param fd the file descriptor.
++ * @param socket_transport the transport being created.
++ * @param fd The socket for this transport
++ * @param vtable the subclass vtable.
+ * @param server_guid non-#NULL if this transport is on the server side of a connection
+- * @param address the transport's address
+- * @returns the new transport, or #NULL if no memory.
++ * @param address the address of the transport
++ * @returns #TRUE on success.
+ */
+-DBusTransport*
+-_dbus_transport_new_for_socket (int fd,
+- const DBusString *server_guid,
+- const DBusString *address)
++dbus_bool_t
++_dbus_transport_socket_init_base (DBusTransportSocket *socket_transport,
++ int fd,
++ const DBusTransportSocketVTable *vtable,
++ const DBusString *server_guid,
++ const DBusString *address)
+ {
+- DBusTransportSocket *socket_transport;
+-
+- socket_transport = dbus_new0 (DBusTransportSocket, 1);
+- if (socket_transport == NULL)
+- return NULL;
+-
+ if (!_dbus_string_init (&socket_transport->encoded_outgoing))
+ goto failed_0;
+
+ if (!_dbus_string_init (&socket_transport->encoded_incoming))
+ goto failed_1;
+-
++
++ socket_transport->auth_notified = FALSE;
++ socket_transport->vtable = vtable;
++
+ socket_transport->write_watch = _dbus_watch_new (fd,
+ DBUS_WATCH_WRITABLE,
+ FALSE,
+@@ -1275,7 +1341,7 @@ _dbus_transport_new_for_socket (int fd,
+ socket_transport->max_bytes_read_per_iteration = 2048;
+ socket_transport->max_bytes_written_per_iteration = 2048;
+
+- return (DBusTransport*) socket_transport;
++ return TRUE;
+
+ failed_4:
+ _dbus_watch_invalidate (socket_transport->read_watch);
+@@ -1288,8 +1354,46 @@ _dbus_transport_new_for_socket (int fd,
+ failed_1:
+ _dbus_string_free (&socket_transport->encoded_outgoing);
+ failed_0:
+- dbus_free (socket_transport);
+- return NULL;
++
++ return FALSE;
++}
++
++/**
++ * Creates a new transport for the given socket file descriptor. The file
++ * descriptor must be nonblocking (use _dbus_set_fd_nonblocking() to
++ * make it so). This function is shared by various transports that
++ * boil down to a full duplex file descriptor.
++ *
++ * @param fd the file descriptor.
++ * @param server_guid non-#NULL if this transport is on the server side of a connection
++ * @param address the transport's address
++ * @returns the new transport, or #NULL if no memory.
++ */
++DBusTransport*
++_dbus_transport_new_for_socket (int fd,
++ const DBusString *server_guid,
++ const DBusString *address)
++{
++ DBusTransportSocket *socket_transport;
++ static const DBusTransportSocketVTable vtable = {
++ NULL
++ };
++
++ socket_transport = dbus_new0 (DBusTransportSocket, 1);
++ if (socket_transport == NULL)
++ return NULL;
++
++ if (!_dbus_transport_socket_init_base (socket_transport,
++ fd,
++ &vtable,
++ server_guid,
++ address))
++ {
++ dbus_free (socket_transport);
++ return NULL;
++ }
++
++ return (DBusTransport *) socket_transport;
+ }
+
+ /**
+diff --git a/dbus/dbus-transport-socket.h b/dbus/dbus-transport-socket.h
+index 8aefae3..ed7fdcc 100644
+--- a/dbus/dbus-transport-socket.h
++++ b/dbus/dbus-transport-socket.h
+@@ -27,6 +27,80 @@
+
+ DBUS_BEGIN_DECLS
+
++/**
++ * Opaque object representing a socket file descriptor transport.
++ */
++typedef struct DBusTransportSocket DBusTransportSocket;
++
++/**
++ * The virtual table that must be implemented to
++ * create a socket-based transport.
++ */
++typedef struct DBusTransportSocketVTable DBusTransportSocketVTable;
++
++struct DBusTransportSocketVTable
++{
++ int (* write_socket) (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *buffer,
++ int start,
++ int len);
++ /**< Write part of a message to the transport */
++
++ int (* write_socket_two) (DBusTransportSocket *socket_transport,
++ DBusMessage *message,
++ const DBusString *header,
++ int header_start,
++ int header_len,
++ const DBusString *body,
++ int body_start,
++ int body_len);
++ /**< Write header and body to the transport */
++
++ void (* authenticated) (DBusTransportSocket *socket_transport);
++ /**< Notification of authentication successful */
++
++ void (* message_received) (DBusTransportSocket *socket_transport,
++ DBusMessage *message);
++ /**< Notification of a message received */
++};
++
++/**
++ * Implementation details of DBusTransportSocket. All members are private.
++ */
++struct DBusTransportSocket
++{
++ DBusTransport base; /**< Parent instance */
++ int fd; /**< File descriptor. */
++ DBusWatch *read_watch; /**< Watch for readability. */
++ DBusWatch *write_watch; /**< Watch for writability. */
++
++ int max_bytes_read_per_iteration; /**< To avoid blocking too long. */
++ int max_bytes_written_per_iteration; /**< To avoid blocking too long. */
++
++ int message_bytes_written; /**< Number of bytes of current
++ * outgoing message that have
++ * been written.
++ */
++ DBusString encoded_outgoing; /**< Encoded version of current
++ * outgoing message.
++ */
++ DBusString encoded_incoming; /**< Encoded version of current
++ * incoming data.
++ */
++ dbus_bool_t auth_notified; /**< Have we notified subclasses
++ * we are authenticated?
++ */
++ const DBusTransportSocketVTable *vtable; /**< Virtual table of transport methods. */
++};
++
++dbus_bool_t _dbus_transport_socket_init_base (DBusTransportSocket *socket_transport,
++ int fd,
++ const DBusTransportSocketVTable *vtable,
++ const DBusString *server_guid,
++ const DBusString *address);
++void _dbus_transport_socket_finalize_base (DBusTransportSocket *socket_transport);
++
+ DBusTransport* _dbus_transport_new_for_socket (int fd,
+ const DBusString *server_guid,
+ const DBusString *address);
+diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
+index 6b58fda..44923da 100644
+--- a/dbus/dbus-transport.c
++++ b/dbus/dbus-transport.c
+@@ -25,6 +25,9 @@
+ #include "dbus-transport-protected.h"
+ #include "dbus-transport-unix.h"
+ #include "dbus-transport-socket.h"
++#ifdef HAVE_AFBUS
++#include "dbus-transport-afbus.h"
++#endif
+ #include "dbus-connection-internal.h"
+ #include "dbus-watch.h"
+ #include "dbus-auth.h"
+@@ -348,6 +351,9 @@ static const struct {
+ { _dbus_transport_open_socket },
+ { _dbus_transport_open_platform_specific },
+ { _dbus_transport_open_autolaunch }
++#ifdef HAVE_AFBUS
++ , { _dbus_transport_open_afbus }
++#endif
+ #ifdef DBUS_BUILD_TESTS
+ , { _dbus_transport_open_debug_pipe }
+ #endif
+@@ -980,6 +986,28 @@ _dbus_transport_do_iteration (DBusTransport *transport,
+ _dbus_verbose ("end\n");
+ }
+
++/**
++ * Allows transports to process incoming messages
++ *
++ * @param transport the transport.
++ * @param message the message to be filtered
++ */
++void
++_dbus_transport_process_incoming_message (DBusTransport *transport,
++ DBusMessage *message)
++{
++ _dbus_verbose ("Transport message filtering\n");
++
++ if (transport->vtable->process_incoming_message != NULL)
++ {
++ _dbus_transport_ref (transport);
++ (* transport->vtable->process_incoming_message) (transport, message);
++ _dbus_transport_unref (transport);
++ }
++
++ _dbus_verbose ("end\n");
++}
++
+ static dbus_bool_t
+ recover_unused_bytes (DBusTransport *transport)
+ {
+@@ -1134,6 +1162,7 @@ _dbus_transport_queue_messages (DBusTransport *transport)
+ _dbus_assert (link != NULL);
+
+ message = link->data;
++ _dbus_transport_process_incoming_message (transport, message);
+
+ _dbus_verbose ("queueing received message %p\n", message);
+
+diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
+index 4b82151..194b2c6 100644
+--- a/dbus/dbus-transport.h
++++ b/dbus/dbus-transport.h
+@@ -52,6 +52,8 @@ dbus_bool_t _dbus_transport_set_connection (DBusTransport
+ void _dbus_transport_do_iteration (DBusTransport *transport,
+ unsigned int flags,
+ int timeout_milliseconds);
++void _dbus_transport_process_incoming_message (DBusTransport *transport,
++ DBusMessage *message);
+ DBusDispatchStatus _dbus_transport_get_dispatch_status (DBusTransport *transport);
+ dbus_bool_t _dbus_transport_queue_messages (DBusTransport *transport);
+
+diff --git a/test/data/valid-config-files/basic.conf b/test/data/valid-config-files/basic.conf
+index 5297097..af46d8b 100644
+--- a/test/data/valid-config-files/basic.conf
++++ b/test/data/valid-config-files/basic.conf
+@@ -4,6 +4,8 @@
+ <user>mybususer</user>
+ <listen>unix:path=/foo/bar</listen>
+ <listen>tcp:port=1234</listen>
++ <listen_if_possible>tcp:port=1235</listen_if_possible>
++ <listen_if_possible>pigeon:port=carrier,speed=110mph</listen_if_possible>
+ <includedir>basic.d</includedir>
+ <servicedir>/usr/share/foo</servicedir>
+ <include ignore_missing="yes">nonexistent.conf</include>
diff --git a/recipes-core-ivi/dbus/dbus_1.6.4.bbappend b/recipes-core-ivi/dbus/dbus_1.6.4.bbappend
index b4929f3..42bae26 100644
--- a/recipes-core-ivi/dbus/dbus_1.6.4.bbappend
+++ b/recipes-core-ivi/dbus/dbus_1.6.4.bbappend
@@ -1,5 +1,8 @@
+FILESEXTRAPATHS := "${THISDIR}/${PN}"
PRINC = "1"
+SRC_URI += "file://dbus_1.6-add-afbus-support.patch"
+
# Don't register init scripts
INITSCRIPT_NAME = ""
INITSCRIPT_PARAMS = ""