summaryrefslogtreecommitdiff
path: root/bus/connection.c
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2015-01-23 19:11:31 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2015-02-04 17:15:08 +0000
commit00af6389be46d65afcce8cdfd060f278aaaa9466 (patch)
treef5f32aadd98ef4e46b97453a01fa582600acba4b /bus/connection.c
parent4a0f1849be319b1b2b7a6d415b57e5544ec191d6 (diff)
downloaddbus-00af6389be46d65afcce8cdfd060f278aaaa9466.tar.gz
Add support for morphing a D-Bus connection into a "monitor"
This is a special connection that is not allowed to send anything, and loses all its well-known names. In future commits, it will get a new set of match rules and the ability to eavesdrop on messages before the rest of the bus daemon has had a chance to process them. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=46787 Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
Diffstat (limited to 'bus/connection.c')
-rw-r--r--bus/connection.c102
1 files changed, 101 insertions, 1 deletions
diff --git a/bus/connection.c b/bus/connection.c
index f278e619..1d9bfb2b 100644
--- a/bus/connection.c
+++ b/bus/connection.c
@@ -64,6 +64,10 @@ struct BusConnections
int stamp; /**< Incrementing number */
BusExpireList *pending_replies; /**< List of pending replies */
+ /** List of all monitoring connections, a subset of completed.
+ * Each member is a #DBusConnection. */
+ DBusList *monitors;
+
#ifdef DBUS_ENABLE_STATS
int total_match_rules;
int peak_match_rules;
@@ -105,6 +109,9 @@ typedef struct
#endif
int n_pending_unix_fds;
DBusTimeout *pending_unix_fds_timeout;
+
+ /** non-NULL if and only if this is a monitor */
+ DBusList *link_in_monitors;
} BusConnectionData;
static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
@@ -283,6 +290,12 @@ bus_connection_disconnected (DBusConnection *connection)
bus_connection_remove_transactions (connection);
+ if (d->link_in_monitors != NULL)
+ {
+ _dbus_list_remove_link (&d->connections->monitors, d->link_in_monitors);
+ d->link_in_monitors = NULL;
+ }
+
if (d->link_in_connection_list != NULL)
{
if (d->name != NULL)
@@ -513,7 +526,10 @@ bus_connections_unref (BusConnections *connections)
}
_dbus_assert (connections->n_incomplete == 0);
-
+
+ /* drop all monitors */
+ _dbus_list_clear (&connections->monitors);
+
/* drop all real connections */
while (connections->completed != NULL)
{
@@ -2493,3 +2509,87 @@ bus_connection_get_peak_bus_names (DBusConnection *connection)
return d->peak_bus_names;
}
#endif /* DBUS_ENABLE_STATS */
+
+dbus_bool_t
+bus_connection_is_monitor (DBusConnection *connection)
+{
+ BusConnectionData *d;
+
+ d = BUS_CONNECTION_DATA (connection);
+
+ return d != NULL && d->link_in_monitors != NULL;
+}
+
+dbus_bool_t
+bus_connection_be_monitor (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusError *error)
+{
+ BusConnectionData *d;
+ DBusList *link;
+ DBusList *tmp;
+ DBusList *iter;
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+
+ link = _dbus_list_alloc_link (connection);
+
+ if (link == NULL)
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ /* release all its names */
+ if (!_dbus_list_copy (&d->services_owned, &tmp))
+ {
+ _dbus_list_free_link (link);
+ BUS_SET_OOM (error);
+ return FALSE;
+ }
+
+ for (iter = _dbus_list_get_first_link (&tmp);
+ iter != NULL;
+ iter = _dbus_list_get_next_link (&tmp, iter))
+ {
+ BusService *service = iter->data;
+
+ /* This call is transactional: if there isn't enough memory to
+ * do everything, then the service gets all its names back when
+ * the transaction is cancelled due to OOM. */
+ if (!bus_service_remove_owner (service, connection, transaction, error))
+ {
+ _dbus_list_free_link (link);
+ _dbus_list_clear (&tmp);
+ return FALSE;
+ }
+ }
+
+ /* We have now done everything that can fail, so there is no problem
+ * with doing the irrevocable stuff. */
+
+ _dbus_list_clear (&tmp);
+
+ bus_context_log (transaction->context, DBUS_SYSTEM_LOG_INFO,
+ "Connection %s (%s) became a monitor.", d->name,
+ d->cached_loginfo_string);
+
+ if (d->n_match_rules > 0)
+ {
+ BusMatchmaker *mm;
+
+ mm = bus_context_get_matchmaker (d->connections->context);
+ bus_matchmaker_disconnected (mm, connection);
+ }
+
+ /* flag it as a monitor */
+ d->link_in_monitors = link;
+ _dbus_list_append_link (&d->connections->monitors, link);
+
+ /* it isn't allowed to reply, and it is no longer relevant whether it
+ * receives replies */
+ bus_connection_drop_pending_replies (d->connections, connection);
+
+ return TRUE;
+}