summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--common/dbus.c123
1 files changed, 81 insertions, 42 deletions
diff --git a/common/dbus.c b/common/dbus.c
index 17f340b6..1b5f7db8 100644
--- a/common/dbus.c
+++ b/common/dbus.c
@@ -80,19 +80,27 @@ struct name_callback {
};
struct name_data {
+ DBusConnection *connection;
char *name;
GSList *callbacks;
};
-static struct name_data *name_data_find(const char *name)
+static struct name_data *name_data_find(DBusConnection *connection,
+ const char *name)
{
GSList *current;
for (current = name_listeners;
current != NULL; current = current->next) {
struct name_data *data = current->data;
- if (strcmp(name, data->name) == 0)
- return data;
+
+ if (name == NULL && data->name == NULL) {
+ if (connection == data->connection)
+ return data;
+ } else {
+ if (strcmp(name, data->name) == 0)
+ return data;
+ }
}
return NULL;
@@ -112,6 +120,22 @@ static struct name_callback *name_callback_find(GSList *callbacks,
return NULL;
}
+static void name_data_call_and_free(struct name_data *data)
+{
+ GSList *l;
+
+ for (l = data->callbacks; l != NULL; l = l->next) {
+ struct name_callback *cb = l->data;
+ if (cb->func)
+ cb->func(data->name, cb->user_data);
+ g_free(cb);
+ }
+
+ g_slist_free(data->callbacks);
+ g_free(data->name);
+ g_free(data);
+}
+
static void name_data_free(struct name_data *data)
{
GSList *l;
@@ -124,7 +148,8 @@ static void name_data_free(struct name_data *data)
g_free(data);
}
-static int name_data_add(const char *name, name_cb_t func, void *user_data)
+static int name_data_add(DBusConnection *connection,
+ const char *name, name_cb_t func, void *user_data)
{
int first = 1;
struct name_data *data = NULL;
@@ -135,7 +160,7 @@ static int name_data_add(const char *name, name_cb_t func, void *user_data)
cb->func = func;
cb->user_data = user_data;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (data) {
first = 0;
goto done;
@@ -143,6 +168,7 @@ static int name_data_add(const char *name, name_cb_t func, void *user_data)
data = g_new0(struct name_data, 1);
+ data->connection = connection;
data->name = g_strdup(name);
name_listeners = g_slist_append(name_listeners, data);
@@ -152,12 +178,13 @@ done:
return first;
}
-static void name_data_remove(const char *name, name_cb_t func, void *user_data)
+static void name_data_remove(DBusConnection *connection,
+ const char *name, name_cb_t func, void *user_data)
{
struct name_data *data;
struct name_callback *cb = NULL;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data)
return;
@@ -197,7 +224,7 @@ static DBusHandlerResult name_exit_filter(DBusConnection *connection,
if (*new != '\0')
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data) {
error("Got NameOwnerChanged signal for %s which has no listeners", name);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
@@ -222,56 +249,51 @@ int name_listener_add(DBusConnection *connection, const char *name,
int first;
if (!name_listener_initialized) {
- if (!dbus_connection_add_filter(connection, name_exit_filter, NULL, NULL)) {
+ if (!dbus_connection_add_filter(connection,
+ name_exit_filter, NULL, NULL)) {
error("dbus_connection_add_filter() failed");
return -1;
}
name_listener_initialized = 1;
}
- if (!name)
- return -1;
-
- first = name_data_add(name, func, user_data);
+ first = name_data_add(connection, name, func, user_data);
/* The filter is already added if this is not the first callback
* registration for the name */
if (!first)
return 0;
- debug("name_listener_add(%s)", name);
+ if (name) {
+ debug("name_listener_add(%s)", name);
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
- dbus_error_init(&err);
- dbus_bus_add_match(connection, match_string, &err);
+ dbus_error_init(&err);
+ dbus_bus_add_match(connection, match_string, &err);
- if (dbus_error_is_set(&err)) {
- error("Adding match rule \"%s\" failed: %s", match_string,
- err.message);
- dbus_error_free(&err);
- name_data_remove(name, func, user_data);
- return -1;
+ if (dbus_error_is_set(&err)) {
+ error("Adding match rule \"%s\" failed: %s",
+ match_string, err.message);
+ dbus_error_free(&err);
+ name_data_remove(connection, name, func, user_data);
+ return -1;
+ }
}
return 0;
}
int name_listener_remove(DBusConnection *connection, const char *name,
- name_cb_t func, void *user_data)
+ name_cb_t func, void *user_data)
{
struct name_data *data;
struct name_callback *cb;
DBusError err;
char match_string[128];
- if (!name)
- return -1;
-
- debug("name_listener_remove(%s)", name);
-
- data = name_data_find(name);
+ data = name_data_find(connection, name);
if (!data) {
error("remove_name_listener: no listener for %s", name);
return -1;
@@ -290,27 +312,44 @@ int name_listener_remove(DBusConnection *connection, const char *name,
if (data->callbacks)
return 0;
- snprintf(match_string, sizeof(match_string),
- "interface=%s,member=NameOwnerChanged,arg0=%s",
- DBUS_INTERFACE_DBUS, name);
+ if (name) {
+ debug("name_listener_remove(%s)", name);
- dbus_error_init(&err);
- dbus_bus_remove_match(connection, match_string, &err);
+ snprintf(match_string, sizeof(match_string),
+ "interface=%s,member=NameOwnerChanged,arg0=%s",
+ DBUS_INTERFACE_DBUS, name);
- if (dbus_error_is_set(&err)) {
- error("Removing owner match rule for %s failed: %s",
+ dbus_error_init(&err);
+
+ dbus_bus_remove_match(connection, match_string, &err);
+
+ if (dbus_error_is_set(&err)) {
+ error("Removing owner match rule for %s failed: %s",
name, err.message);
- dbus_error_free(&err);
- return -1;
+ dbus_error_free(&err);
+ return -1;
+ }
}
- name_data_remove(name, func, user_data);
+ name_data_remove(connection, name, func, user_data);
return 0;
}
int name_listener_indicate_disconnect(DBusConnection *connection)
{
+ struct name_data *data;
+
+ data = name_data_find(connection, NULL);
+ if (!data) {
+ error("name_listener_indicate_disconnect: no listener found");
+ return -1;
+ }
+
+ debug("name_listener_indicate_disconnect");
+
+ name_data_call_and_free(data);
+
return 0;
}