Diff between abfc2b0dd5c3e33abfdf1a815b16d492c1751c06 and 5a6aa225496a33ba0f30568abed2b2d3cdad7b0d

Changed Files

File Additions Deletions Status
gdbus/watch.c +94 -21 modified

Full Patch

diff --git a/gdbus/watch.c b/gdbus/watch.c
index d749176..2661928 100644
--- a/gdbus/watch.c
+++ b/gdbus/watch.c
@@ -78,6 +78,47 @@ struct filter_data {
 	gboolean registered;
 };
 
+static struct filter_data *filter_data_find_match(DBusConnection *connection,
+							const char *name,
+							const char *owner,
+							const char *path,
+							const char *interface,
+							const char *member,
+							const char *argument)
+{
+	GSList *current;
+
+	for (current = listeners;
+			current != NULL; current = current->next) {
+		struct filter_data *data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		if (g_strcmp0(name, data->name) != 0)
+			continue;
+
+		if (g_strcmp0(owner, data->owner) != 0)
+			continue;
+
+		if (g_strcmp0(path, data->path) != 0)
+			continue;
+
+		if (g_strcmp0(interface, data->interface) != 0)
+			continue;
+
+		if (g_strcmp0(member, data->member) != 0)
+			continue;
+
+		if (g_strcmp0(argument, data->argument) != 0)
+			continue;
+
+		return data;
+	}
+
+	return NULL;
+}
+
 static struct filter_data *filter_data_find(DBusConnection *connection,
 							const char *name,
 							const char *owner,
@@ -221,8 +262,8 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
 		name = sender;
 
 proceed:
-	data = filter_data_find(connection, name, owner, path, interface,
-					member, argument);
+	data = filter_data_find_match(connection, name, owner, path,
+						interface, member, argument);
 	if (data)
 		return data;
 
@@ -501,6 +542,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 {
 	struct filter_data *data;
 	const char *sender, *path, *iface, *member, *arg = NULL;
+	GSList *current, *delete_listener = NULL;
 
 	/* Only filter signals */
 	if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
@@ -512,30 +554,63 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 	member = dbus_message_get_member(message);
 	dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-	/* Sender is always bus name */
-	data = filter_data_find(connection, NULL, sender, path, iface, member,
-					arg);
-	if (data == NULL) {
-		error("Got %s.%s signal which has no listeners", iface, member);
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-	}
+	/* Sender is always the owner */
+
+	for (current = listeners; current != NULL; current = current->next) {
+		data = current->data;
+
+		if (connection != data->connection)
+			continue;
+
+		if (data->owner && g_str_equal(sender, data->owner) == FALSE)
+			continue;
 
-	if (data->handle_func) {
-		data->lock = TRUE;
+		if (data->path && g_str_equal(path, data->path) == FALSE)
+			continue;
+
+		if (data->interface && g_str_equal(iface,
+						data->interface) == FALSE)
+			continue;
 
-		data->handle_func(connection, message, data);
+		if (data->member && g_str_equal(member, data->member) == FALSE)
+			continue;
 
-		data->callbacks = data->processed;
-		data->processed = NULL;
-		data->lock = FALSE;
+		if (data->argument && g_str_equal(arg,
+						data->argument) == FALSE)
+			continue;
+
+		if (data->handle_func) {
+			data->lock = TRUE;
+
+			data->handle_func(connection, message, data);
+
+			data->callbacks = data->processed;
+			data->processed = NULL;
+			data->lock = FALSE;
+		}
+
+		if (!data->callbacks)
+			delete_listener = g_slist_prepend(delete_listener,
+								current);
 	}
 
-	if (data->callbacks)
-		return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+	for (current = delete_listener; current != NULL;
+					current = delete_listener->next) {
+		GSList *l = current->data;
 
-	remove_match(data);
+		data = l->data;
 
-	listeners = g_slist_remove(listeners, data);
+		/* Has any other callback added callbacks back to this data? */
+		if (data->callbacks != NULL)
+			continue;
+
+		remove_match(data);
+		listeners = g_slist_remove_link(listeners, l);
+
+		filter_data_free(data);
+	}
+
+	g_slist_free(delete_listener);
 
 	/* Remove filter if there are no listeners left for the connection */
 	if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
@@ -543,8 +618,6 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 		dbus_connection_remove_filter(connection, message_filter,
 						NULL);
 
-	filter_data_free(data);
-
 	return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }