PA_MODULE_AUTHOR("Tanu Kaskinen");
PA_MODULE_VERSION(PACKAGE_VERSION);
-#define CLEANUP_INTERVAL 10 /* seconds */
-
enum server_type {
SERVER_TYPE_LOCAL,
SERVER_TYPE_TCP
pa_idxset *connections;
- pa_time_event *cleanup_event;
+ pa_defer_event *cleanup_event;
pa_dbus_protocol *dbus_protocol;
pa_dbusiface_core *core_iface;
return TRUE;
}
+static DBusHandlerResult disconnection_filter_cb(DBusConnection *connection, DBusMessage *message, void *user_data) {
+ struct connection *c = user_data;
+
+ pa_assert(connection);
+ pa_assert(message);
+ pa_assert(c);
+
+ if (dbus_message_is_signal(message, "org.freedesktop.DBus.Local", "Disconnected")) {
+ /* The connection died. Now we want to free the connection object, but
+ * let's wait until this message is fully processed, in case someone
+ * else is interested in this signal too. */
+ c->server->userdata->module->core->mainloop->defer_enable(c->server->userdata->cleanup_event, 1);
+ }
+
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
/* Called by D-Bus when a new client connection is received. */
static void connection_new_cb(DBusServer *dbus_server, DBusConnection *new_connection, void *data) {
struct server *s = data;
c->client->send_event = client_send_event_cb;
c->client->userdata = c;
+ pa_assert_se(dbus_connection_add_filter(new_connection, disconnection_filter_cb, c, NULL));
+
pa_idxset_put(s->userdata->connections, c, NULL);
pa_assert_se(pa_dbus_protocol_register_connection(s->userdata->dbus_protocol, new_connection, c->client) >= 0);
return 0;
}
-/* Frees dead client connections. Called every CLEANUP_INTERVAL seconds. */
-static void cleanup_cb(pa_mainloop_api *a, pa_time_event *e, const struct timeval *tv, void *userdata) {
+/* Frees dead client connections. */
+static void cleanup_cb(pa_mainloop_api *a, pa_defer_event *e, void *userdata) {
struct userdata *u = userdata;
struct connection *conn = NULL;
uint32_t idx;
- struct timeval cleanup_timeval;
- unsigned free_count = 0;
- for (conn = pa_idxset_first(u->connections, &idx); conn; conn = pa_idxset_next(u->connections, &idx)) {
- if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn->wrap_conn))) {
+ PA_IDXSET_FOREACH(conn, u->connections, idx) {
+ if (!dbus_connection_get_is_connected(pa_dbus_wrap_connection_get(conn->wrap_conn)))
connection_free(conn);
- ++free_count;
- }
}
- if (free_count > 0)
- pa_log_debug("Freed %u dead D-Bus client connections.", free_count);
-
- pa_gettimeofday(&cleanup_timeval);
- cleanup_timeval.tv_sec += CLEANUP_INTERVAL;
- u->module->core->mainloop->time_restart(e, &cleanup_timeval);
+ u->module->core->mainloop->defer_enable(e, 0);
}
int pa__init(pa_module *m) {
struct userdata *u = NULL;
pa_modargs *ma = NULL;
- struct timeval cleanup_timeval;
pa_assert(m);
u->connections = pa_idxset_new(pa_idxset_trivial_hash_func, pa_idxset_trivial_compare_func);
- pa_gettimeofday(&cleanup_timeval);
- cleanup_timeval.tv_sec += CLEANUP_INTERVAL;
- u->cleanup_event = m->core->mainloop->time_new(m->core->mainloop, &cleanup_timeval, cleanup_cb, u);
+ u->cleanup_event = m->core->mainloop->defer_new(m->core->mainloop, cleanup_cb, u);
+ m->core->mainloop->defer_enable(u->cleanup_event, 0);
u->dbus_protocol = pa_dbus_protocol_get(m->core);
u->core_iface = pa_dbusiface_core_new(m->core);
pa_dbusiface_core_free(u->core_iface);
if (u->cleanup_event)
- m->core->mainloop->time_free(u->cleanup_event);
+ m->core->mainloop->defer_free(u->cleanup_event);
if (u->connections)
pa_idxset_free(u->connections, connection_free_cb, NULL);