summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Brewer <benbrewer@codethink.co.uk>2012-11-26 15:52:12 +0000
committerBen Brewer <benbrewer@codethink.co.uk>2012-11-26 15:52:12 +0000
commita9baebcf982ecb9be018bea519e5d187b0808610 (patch)
tree805bfa34e0314e93a2305b5deb4e941ec8c98d51
parent9b04b927ee61da9639f20410d6f535aaccd76e0d (diff)
downloaddbus-baserock/genivi/dbus-1.6-af-bus.tar.gz
Patched dbus-1.6 for af-bus and added morphbaserock/genivi/dbus-1.6-af-busbaserock/af-bus
-rw-r--r--bus/Makefile.am10
-rw-r--r--bus/bus.c158
-rw-r--r--bus/bus.h1
-rw-r--r--bus/config-parser-common.c6
-rw-r--r--bus/config-parser-common.h1
-rw-r--r--bus/config-parser.c52
-rw-r--r--bus/config-parser.h1
-rw-r--r--bus/connection.c152
-rw-r--r--bus/connection.h12
-rw-r--r--bus/dispatch.c23
-rw-r--r--bus/driver-afbus.c345
-rw-r--r--bus/driver-afbus.h96
-rw-r--r--bus/driver.c46
-rw-r--r--bus/session.conf.in3
-rw-r--r--bus/system.conf.in1
-rw-r--r--configure.ac22
-rw-r--r--dbus.morph15
-rw-r--r--dbus/Makefile.am11
-rw-r--r--dbus/dbus-connection.c37
-rw-r--r--dbus/dbus-connection.h4
-rw-r--r--dbus/dbus-protocol.h6
-rw-r--r--dbus/dbus-server-afbus.c397
-rw-r--r--dbus/dbus-server-afbus.h36
-rw-r--r--dbus/dbus-server-protected.h3
-rw-r--r--dbus/dbus-server.c30
-rw-r--r--dbus/dbus-server.h2
-rw-r--r--dbus/dbus-shared.h8
-rw-r--r--dbus/dbus-sysdeps-unix.c2
-rw-r--r--dbus/dbus-sysdeps.h5
-rw-r--r--dbus/dbus-transport-afbus.c394
-rw-r--r--dbus/dbus-transport-afbus.h41
-rw-r--r--dbus/dbus-transport-protected.h4
-rw-r--r--dbus/dbus-transport-socket.c264
-rw-r--r--dbus/dbus-transport-socket.h74
-rw-r--r--dbus/dbus-transport.c29
-rw-r--r--dbus/dbus-transport.h2
-rw-r--r--test/data/valid-config-files/basic.conf2
37 files changed, 2172 insertions, 123 deletions
diff --git a/bus/Makefile.am b/bus/Makefile.am
index 6cbc09a6..cf3a9627 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 e80e7080..5038958c 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 35978841..f2a55f2c 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 c522ff49..8747835c 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 186bf4cf..6ea509ce 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 07e8fbb6..fffc0e11 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 ba5bf749..f8a3c07e 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 d69758c9..2d68c84e 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 c9360212..95856f30 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 7a96f9dc..4feae056 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 00000000..70edafb8
--- /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 00000000..9c401119
--- /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 574e0f3d..11767c8c 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 e121ff93..09a7ecff 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 92f4cc42..515509f4 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 5490cf02..8b48e909 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1513,6 +1513,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
@@ -1652,7 +1666,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
@@ -1672,6 +1690,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.morph b/dbus.morph
new file mode 100644
index 00000000..a4666514
--- /dev/null
+++ b/dbus.morph
@@ -0,0 +1,15 @@
+{
+ "name": "dbus",
+ "kind": "chunk",
+ "build-system": "autotools",
+ "configure-commands": [
+ "sh autogen.sh --no-configure",
+ "./configure --prefix=\"$PREFIX\" --localstatedir=/var --sysconfdir=/etc"
+ ],
+ "build-commands": [
+ "make XMLTO_OUTPUT="
+ ],
+ "install-commands": [
+ "make XMLTO_OUTPUT= DESTDIR=\"$DESTDIR\" install"
+ ]
+}
diff --git a/dbus/Makefile.am b/dbus/Makefile.am
index bb5cccaf..b925419c 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 ee33b6cc..5f3a459f 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 fe4d04ef..81fe9f1e 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 60605ab2..71c28700 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 00000000..1d8e9bd2
--- /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 00000000..8e5ad319
--- /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 dd5234b9..b423cb97 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 b62c2b40..2a232527 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 bdbefa0f..49cb9cfb 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 6a576704..b6b29b32 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 b4ecc96e..e3025ac3 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 eee91608..58981f48 100644
--- a/dbus/dbus-sysdeps.h
+++ b/dbus/dbus-sysdeps.h
@@ -126,6 +126,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 00000000..9574bcaf
--- /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 00000000..c94e32d1
--- /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 44b9d785..9becbdb3 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 544d00a9..a3951ef4 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 8aefae37..ed7fdcc3 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 6b58fda2..44923daf 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 4b821517..194b2c6c 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 5297097d..af46d8b2 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>