2009-04-26 18:51:36 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* D-Bus helper library
|
|
|
|
*
|
2011-01-02 01:31:09 +00:00
|
|
|
* Copyright (C) 2004-2011 Marcel Holtmann <marcel@holtmann.org>
|
2009-04-26 18:51:36 +00:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* 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 St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include <config.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
#include <dbus/dbus.h>
|
|
|
|
|
|
|
|
#include "gdbus.h"
|
|
|
|
|
|
|
|
#define info(fmt...)
|
|
|
|
#define error(fmt...)
|
|
|
|
#define debug(fmt...)
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static DBusHandlerResult message_filter(DBusConnection *connection,
|
2009-04-26 18:51:36 +00:00
|
|
|
DBusMessage *message, void *user_data);
|
|
|
|
|
|
|
|
static guint listener_id = 0;
|
2009-12-29 08:53:21 +00:00
|
|
|
static GSList *listeners = NULL;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
struct service_data {
|
|
|
|
DBusConnection *conn;
|
|
|
|
DBusPendingCall *call;
|
|
|
|
char *name;
|
|
|
|
const char *owner;
|
|
|
|
guint id;
|
|
|
|
struct filter_callback *callback;
|
|
|
|
};
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_callback {
|
2009-04-26 18:51:36 +00:00
|
|
|
GDBusWatchFunction conn_func;
|
|
|
|
GDBusWatchFunction disc_func;
|
2009-12-29 08:53:21 +00:00
|
|
|
GDBusSignalFunction signal_func;
|
|
|
|
GDBusDestroyFunction destroy_func;
|
2010-09-06 13:39:41 +00:00
|
|
|
struct service_data *data;
|
2009-04-26 18:51:36 +00:00
|
|
|
void *user_data;
|
|
|
|
guint id;
|
|
|
|
};
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data {
|
2009-04-26 18:51:36 +00:00
|
|
|
DBusConnection *connection;
|
2009-12-29 08:53:21 +00:00
|
|
|
DBusHandleMessageFunction handle_func;
|
2010-09-06 10:26:20 +00:00
|
|
|
char *name;
|
|
|
|
char *owner;
|
2009-12-29 08:53:21 +00:00
|
|
|
char *path;
|
|
|
|
char *interface;
|
|
|
|
char *member;
|
|
|
|
char *argument;
|
2009-04-26 18:51:36 +00:00
|
|
|
GSList *callbacks;
|
2009-05-06 20:15:27 +00:00
|
|
|
GSList *processed;
|
2010-09-06 10:26:20 +00:00
|
|
|
guint name_watch;
|
2009-05-06 20:15:27 +00:00
|
|
|
gboolean lock;
|
2009-12-29 08:53:21 +00:00
|
|
|
gboolean registered;
|
2009-04-26 18:51:36 +00:00
|
|
|
};
|
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2012-10-03 11:57:23 +00:00
|
|
|
static struct filter_data *filter_data_find(DBusConnection *connection)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
|
|
|
GSList *current;
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
for (current = listeners;
|
2009-04-26 18:51:36 +00:00
|
|
|
current != NULL; current = current->next) {
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data = current->data;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
|
|
|
if (connection != data->connection)
|
|
|
|
continue;
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return data;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static void format_rule(struct filter_data *data, char *rule, size_t size)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
2010-09-06 10:26:20 +00:00
|
|
|
const char *sender;
|
2009-12-29 08:53:21 +00:00
|
|
|
int offset;
|
|
|
|
|
|
|
|
offset = snprintf(rule, size, "type='signal'");
|
2010-09-06 10:26:20 +00:00
|
|
|
sender = data->name ? : data->owner;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
if (sender)
|
2009-12-29 08:53:21 +00:00
|
|
|
offset += snprintf(rule + offset, size - offset,
|
2010-09-06 10:26:20 +00:00
|
|
|
",sender='%s'", sender);
|
2009-12-29 08:53:21 +00:00
|
|
|
if (data->path)
|
|
|
|
offset += snprintf(rule + offset, size - offset,
|
|
|
|
",path='%s'", data->path);
|
|
|
|
if (data->interface)
|
|
|
|
offset += snprintf(rule + offset, size - offset,
|
|
|
|
",interface='%s'", data->interface);
|
|
|
|
if (data->member)
|
|
|
|
offset += snprintf(rule + offset, size - offset,
|
|
|
|
",member='%s'", data->member);
|
|
|
|
if (data->argument)
|
|
|
|
snprintf(rule + offset, size - offset,
|
|
|
|
",arg0='%s'", data->argument);
|
|
|
|
}
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static gboolean add_match(struct filter_data *data,
|
|
|
|
DBusHandleMessageFunction filter)
|
|
|
|
{
|
|
|
|
DBusError err;
|
|
|
|
char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
|
|
|
|
|
|
|
|
format_rule(data, rule, sizeof(rule));
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
|
|
dbus_bus_add_match(data->connection, rule, &err);
|
|
|
|
if (dbus_error_is_set(&err)) {
|
2009-12-29 12:10:15 +00:00
|
|
|
error("Adding match rule \"%s\" failed: %s", rule,
|
2009-12-29 08:53:21 +00:00
|
|
|
err.message);
|
|
|
|
dbus_error_free(&err);
|
|
|
|
return FALSE;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
data->handle_func = filter;
|
|
|
|
data->registered = TRUE;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean remove_match(struct filter_data *data)
|
|
|
|
{
|
|
|
|
DBusError err;
|
|
|
|
char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH];
|
|
|
|
|
|
|
|
format_rule(data, rule, sizeof(rule));
|
|
|
|
|
|
|
|
dbus_error_init(&err);
|
|
|
|
|
|
|
|
dbus_bus_remove_match(data->connection, rule, &err);
|
|
|
|
if (dbus_error_is_set(&err)) {
|
|
|
|
error("Removing owner match rule for %s failed: %s",
|
2009-12-29 12:10:15 +00:00
|
|
|
rule, err.message);
|
2009-12-29 08:53:21 +00:00
|
|
|
dbus_error_free(&err);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct filter_data *filter_data_get(DBusConnection *connection,
|
|
|
|
DBusHandleMessageFunction filter,
|
|
|
|
const char *sender,
|
|
|
|
const char *path,
|
|
|
|
const char *interface,
|
|
|
|
const char *member,
|
|
|
|
const char *argument)
|
|
|
|
{
|
|
|
|
struct filter_data *data;
|
2010-09-06 10:26:20 +00:00
|
|
|
const char *name = NULL, *owner = NULL;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
2012-10-03 11:57:23 +00:00
|
|
|
if (filter_data_find(connection) == NULL) {
|
2009-12-29 08:53:21 +00:00
|
|
|
if (!dbus_connection_add_filter(connection,
|
|
|
|
message_filter, NULL, NULL)) {
|
|
|
|
error("dbus_connection_add_filter() failed");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
if (sender == NULL)
|
|
|
|
goto proceed;
|
|
|
|
|
|
|
|
if (sender[0] == ':')
|
|
|
|
owner = sender;
|
|
|
|
else
|
|
|
|
name = sender;
|
|
|
|
|
|
|
|
proceed:
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
data = filter_data_find_match(connection, name, owner, path,
|
|
|
|
interface, member, argument);
|
2009-12-29 08:53:21 +00:00
|
|
|
if (data)
|
|
|
|
return data;
|
|
|
|
|
|
|
|
data = g_new0(struct filter_data, 1);
|
|
|
|
|
|
|
|
data->connection = dbus_connection_ref(connection);
|
2012-11-21 10:21:03 +00:00
|
|
|
data->name = g_strdup(name);
|
|
|
|
data->owner = g_strdup(owner);
|
2009-12-29 08:53:21 +00:00
|
|
|
data->path = g_strdup(path);
|
|
|
|
data->interface = g_strdup(interface);
|
|
|
|
data->member = g_strdup(member);
|
|
|
|
data->argument = g_strdup(argument);
|
|
|
|
|
|
|
|
if (!add_match(data, filter)) {
|
|
|
|
g_free(data);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
listeners = g_slist_append(listeners, data);
|
|
|
|
|
|
|
|
return data;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static struct filter_callback *filter_data_find_callback(
|
|
|
|
struct filter_data *data,
|
|
|
|
guint id)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
for (l = data->callbacks; l; l = l->next) {
|
|
|
|
struct filter_callback *cb = l->data;
|
|
|
|
if (cb->id == id)
|
|
|
|
return cb;
|
|
|
|
}
|
|
|
|
for (l = data->processed; l; l = l->next) {
|
|
|
|
struct filter_callback *cb = l->data;
|
|
|
|
if (cb->id == id)
|
|
|
|
return cb;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return NULL;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static void filter_data_free(struct filter_data *data)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
2013-09-03 15:00:35 +00:00
|
|
|
/* Remove filter if there are no listeners left for the connection */
|
|
|
|
if (filter_data_find(data->connection) == NULL)
|
|
|
|
dbus_connection_remove_filter(data->connection, message_filter,
|
|
|
|
NULL);
|
|
|
|
|
2009-04-26 18:51:36 +00:00
|
|
|
for (l = data->callbacks; l != NULL; l = l->next)
|
|
|
|
g_free(l->data);
|
|
|
|
|
|
|
|
g_slist_free(data->callbacks);
|
2010-09-06 10:26:20 +00:00
|
|
|
g_dbus_remove_watch(data->connection, data->name_watch);
|
|
|
|
g_free(data->name);
|
|
|
|
g_free(data->owner);
|
2009-12-29 08:53:21 +00:00
|
|
|
g_free(data->path);
|
|
|
|
g_free(data->interface);
|
|
|
|
g_free(data->member);
|
|
|
|
g_free(data->argument);
|
|
|
|
dbus_connection_unref(data->connection);
|
2009-04-26 18:51:36 +00:00
|
|
|
g_free(data);
|
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static void filter_data_call_and_free(struct filter_data *data)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = data->callbacks; l != NULL; l = l->next) {
|
|
|
|
struct filter_callback *cb = l->data;
|
|
|
|
if (cb->disc_func)
|
|
|
|
cb->disc_func(data->connection, cb->user_data);
|
|
|
|
if (cb->destroy_func)
|
|
|
|
cb->destroy_func(cb->user_data);
|
|
|
|
g_free(cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
filter_data_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct filter_callback *filter_data_add_callback(
|
|
|
|
struct filter_data *data,
|
2009-04-26 18:51:36 +00:00
|
|
|
GDBusWatchFunction connect,
|
|
|
|
GDBusWatchFunction disconnect,
|
2009-12-29 08:53:21 +00:00
|
|
|
GDBusSignalFunction signal,
|
|
|
|
GDBusDestroyFunction destroy,
|
|
|
|
void *user_data)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_callback *cb = NULL;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
cb = g_new0(struct filter_callback, 1);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
|
|
|
cb->conn_func = connect;
|
|
|
|
cb->disc_func = disconnect;
|
2009-12-29 08:53:21 +00:00
|
|
|
cb->signal_func = signal;
|
|
|
|
cb->destroy_func = destroy;
|
2009-04-26 18:51:36 +00:00
|
|
|
cb->user_data = user_data;
|
2009-12-29 08:53:21 +00:00
|
|
|
cb->id = ++listener_id;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-05-06 20:15:27 +00:00
|
|
|
if (data->lock)
|
|
|
|
data->processed = g_slist_append(data->processed, cb);
|
|
|
|
else
|
|
|
|
data->callbacks = g_slist_append(data->callbacks, cb);
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return cb;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
static void service_data_free(struct service_data *data)
|
|
|
|
{
|
|
|
|
struct filter_callback *callback = data->callback;
|
|
|
|
|
|
|
|
dbus_connection_unref(data->conn);
|
|
|
|
|
|
|
|
if (data->call)
|
|
|
|
dbus_pending_call_unref(data->call);
|
|
|
|
|
|
|
|
if (data->id)
|
|
|
|
g_source_remove(data->id);
|
|
|
|
|
|
|
|
g_free(data->name);
|
|
|
|
g_free(data);
|
|
|
|
|
|
|
|
callback->data = NULL;
|
|
|
|
}
|
|
|
|
|
2014-08-11 07:50:44 +00:00
|
|
|
/* Returns TRUE if data is freed */
|
2009-12-29 08:53:21 +00:00
|
|
|
static gboolean filter_data_remove_callback(struct filter_data *data,
|
|
|
|
struct filter_callback *cb)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
data->callbacks = g_slist_remove(data->callbacks, cb);
|
|
|
|
data->processed = g_slist_remove(data->processed, cb);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
/* Cancel pending operations */
|
|
|
|
if (cb->data) {
|
|
|
|
if (cb->data->call)
|
|
|
|
dbus_pending_call_cancel(cb->data->call);
|
|
|
|
service_data_free(cb->data);
|
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
if (cb->destroy_func)
|
|
|
|
cb->destroy_func(cb->user_data);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
g_free(cb);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
/* Don't remove the filter if other callbacks exist or data is lock
|
|
|
|
* processing callbacks */
|
|
|
|
if (data->callbacks || data->lock)
|
2014-08-11 07:50:44 +00:00
|
|
|
return FALSE;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
if (data->registered && !remove_match(data))
|
|
|
|
return FALSE;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2010-01-08 10:17:19 +00:00
|
|
|
listeners = g_slist_remove(listeners, data);
|
2012-06-25 15:44:40 +00:00
|
|
|
filter_data_free(data);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static DBusHandlerResult signal_filter(DBusConnection *connection,
|
|
|
|
DBusMessage *message, void *user_data)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data = user_data;
|
|
|
|
struct filter_callback *cb;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
while (data->callbacks) {
|
|
|
|
cb = data->callbacks->data;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
if (cb->signal_func && !cb->signal_func(connection, message,
|
|
|
|
cb->user_data)) {
|
2014-08-11 07:50:44 +00:00
|
|
|
if (filter_data_remove_callback(data, cb))
|
|
|
|
break;
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
continue;
|
|
|
|
}
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
/* Check if the watch was removed/freed by the callback
|
|
|
|
* function */
|
|
|
|
if (!g_slist_find(data->callbacks, cb))
|
|
|
|
continue;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
data->callbacks = g_slist_remove(data->callbacks, cb);
|
|
|
|
data->processed = g_slist_append(data->processed, cb);
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
static void update_name_cache(const char *name, const char *owner)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = listeners; l != NULL; l = l->next) {
|
|
|
|
struct filter_data *data = l->data;
|
|
|
|
|
|
|
|
if (g_strcmp0(data->name, name) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
g_free(data->owner);
|
|
|
|
data->owner = g_strdup(owner);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *check_name_cache(const char *name)
|
|
|
|
{
|
|
|
|
GSList *l;
|
|
|
|
|
|
|
|
for (l = listeners; l != NULL; l = l->next) {
|
|
|
|
struct filter_data *data = l->data;
|
|
|
|
|
|
|
|
if (g_strcmp0(data->name, name) != 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
return data->owner;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
static DBusHandlerResult service_filter(DBusConnection *connection,
|
2009-04-26 18:51:36 +00:00
|
|
|
DBusMessage *message, void *user_data)
|
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data = user_data;
|
|
|
|
struct filter_callback *cb;
|
2009-04-26 18:51:36 +00:00
|
|
|
char *name, *old, *new;
|
|
|
|
|
|
|
|
if (!dbus_message_get_args(message, NULL,
|
|
|
|
DBUS_TYPE_STRING, &name,
|
|
|
|
DBUS_TYPE_STRING, &old,
|
|
|
|
DBUS_TYPE_STRING, &new,
|
|
|
|
DBUS_TYPE_INVALID)) {
|
|
|
|
error("Invalid arguments for NameOwnerChanged signal");
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
}
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
update_name_cache(name, new);
|
|
|
|
|
2009-05-06 20:15:27 +00:00
|
|
|
while (data->callbacks) {
|
|
|
|
cb = data->callbacks->data;
|
|
|
|
|
2009-04-26 18:51:36 +00:00
|
|
|
if (*new == '\0') {
|
|
|
|
if (cb->disc_func)
|
|
|
|
cb->disc_func(connection, cb->user_data);
|
|
|
|
} else {
|
|
|
|
if (cb->conn_func)
|
|
|
|
cb->conn_func(connection, cb->user_data);
|
|
|
|
}
|
2009-05-06 20:15:27 +00:00
|
|
|
|
2010-12-09 19:52:54 +00:00
|
|
|
/* Check if the watch was removed/freed by the callback
|
|
|
|
* function */
|
|
|
|
if (!g_slist_find(data->callbacks, cb))
|
|
|
|
continue;
|
|
|
|
|
2010-09-06 10:26:19 +00:00
|
|
|
/* Only auto remove if it is a bus name watch */
|
|
|
|
if (data->argument[0] == ':' &&
|
2010-11-27 19:39:01 +00:00
|
|
|
(cb->conn_func == NULL || cb->disc_func == NULL)) {
|
2014-08-11 07:50:44 +00:00
|
|
|
if (filter_data_remove_callback(data, cb))
|
|
|
|
break;
|
|
|
|
|
2010-09-06 10:26:19 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2009-05-06 20:15:27 +00:00
|
|
|
data->callbacks = g_slist_remove(data->callbacks, cb);
|
|
|
|
data->processed = g_slist_append(data->processed, cb);
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static DBusHandlerResult message_filter(DBusConnection *connection,
|
|
|
|
DBusMessage *message, void *user_data)
|
|
|
|
{
|
|
|
|
struct filter_data *data;
|
|
|
|
const char *sender, *path, *iface, *member, *arg = NULL;
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
GSList *current, *delete_listener = NULL;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
|
|
|
/* Only filter signals */
|
|
|
|
if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
|
|
|
|
sender = dbus_message_get_sender(message);
|
|
|
|
path = dbus_message_get_path(message);
|
|
|
|
iface = dbus_message_get_interface(message);
|
|
|
|
member = dbus_message_get_member(message);
|
|
|
|
dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
|
|
|
|
|
2015-02-23 18:33:00 +00:00
|
|
|
/* If sender != NULL it is always the owner */
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
|
|
|
|
for (current = listeners; current != NULL; current = current->next) {
|
|
|
|
data = current->data;
|
|
|
|
|
|
|
|
if (connection != data->connection)
|
|
|
|
continue;
|
|
|
|
|
2015-02-23 18:33:00 +00:00
|
|
|
if (!sender && data->owner)
|
|
|
|
continue;
|
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
if (data->owner && g_str_equal(sender, data->owner) == FALSE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (data->path && g_str_equal(path, data->path) == FALSE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (data->interface && g_str_equal(iface,
|
|
|
|
data->interface) == FALSE)
|
|
|
|
continue;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
if (data->member && g_str_equal(member, data->member) == FALSE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (data->argument && g_str_equal(arg,
|
|
|
|
data->argument) == FALSE)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (data->handle_func) {
|
|
|
|
data->lock = TRUE;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
data->handle_func(connection, message, data);
|
2009-12-29 08:53:21 +00:00
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
data->callbacks = data->processed;
|
|
|
|
data->processed = NULL;
|
|
|
|
data->lock = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!data->callbacks)
|
|
|
|
delete_listener = g_slist_prepend(delete_listener,
|
|
|
|
current);
|
2009-12-29 08:53:21 +00:00
|
|
|
}
|
2009-05-06 20:15:27 +00:00
|
|
|
|
2013-09-03 15:00:35 +00:00
|
|
|
if (delete_listener == NULL)
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
for (current = delete_listener; current != NULL;
|
|
|
|
current = delete_listener->next) {
|
|
|
|
GSList *l = current->data;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
data = l->data;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
/* Has any other callback added callbacks back to this data? */
|
|
|
|
if (data->callbacks != NULL)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
remove_match(data);
|
2012-10-03 11:57:24 +00:00
|
|
|
listeners = g_slist_delete_link(listeners, l);
|
gdbus: Fix wrong signal handler match
When we add a signal handler with g_dbus_add_signal_watch(), this
function tries to multiplex the matches added in libdbus by checking
if there's a previous filter_data with the same fields. However, if the
field is NULL it accepts as being the same. The result is that the
following watches will use the same filter data:
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
The result is that when a signal arrives with path == "/path2", all 3
callbacks above will be called, with the same signal delivered to all of
them.
Another problem is that, if we invert the calls like below, only signals
to cb1 will never be trigerred, nonetheless it used path == NULL.
watch2 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path2", iface, member,
cb2, data2, NULL);
watch1 = g_dbus_add_signal_watch(conn, BUS_NAME, NULL, iface, member,
cb1, data1, NULL);
watch3 = g_dbus_add_signal_watch(conn, BUS_NAME, "/path3", iface, member,
cb3, data3, NULL);
This is fixed by not multiplexing the matchs with filter data if any of
the fields are different, including being NULL. When a signal arrives,
if a field is NULL we accept it as a match, but not when adding the
signal handler.
2012-10-03 11:57:22 +00:00
|
|
|
|
|
|
|
filter_data_free(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_slist_free(delete_listener);
|
2009-04-26 18:51:36 +00:00
|
|
|
|
|
|
|
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
|
|
|
}
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
static gboolean update_service(void *user_data)
|
|
|
|
{
|
|
|
|
struct service_data *data = user_data;
|
2010-09-06 13:39:41 +00:00
|
|
|
struct filter_callback *cb = data->callback;
|
2013-09-02 12:55:45 +00:00
|
|
|
DBusConnection *conn;
|
2010-09-06 10:26:20 +00:00
|
|
|
|
2013-09-02 12:55:45 +00:00
|
|
|
conn = dbus_connection_ref(data->conn);
|
|
|
|
service_data_free(data);
|
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
if (cb->conn_func)
|
2013-09-02 12:55:45 +00:00
|
|
|
cb->conn_func(conn, cb->user_data);
|
2010-09-06 10:26:20 +00:00
|
|
|
|
2013-09-02 12:55:45 +00:00
|
|
|
dbus_connection_unref(conn);
|
2010-09-06 10:26:20 +00:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2009-08-07 05:10:19 +00:00
|
|
|
static void service_reply(DBusPendingCall *call, void *user_data)
|
|
|
|
{
|
|
|
|
struct service_data *data = user_data;
|
|
|
|
DBusMessage *reply;
|
2010-09-06 10:26:20 +00:00
|
|
|
DBusError err;
|
2009-08-07 05:10:19 +00:00
|
|
|
|
|
|
|
reply = dbus_pending_call_steal_reply(call);
|
|
|
|
if (reply == NULL)
|
|
|
|
return;
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
dbus_error_init(&err);
|
2009-08-07 05:10:19 +00:00
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
if (dbus_set_error_from_message(&err, reply))
|
|
|
|
goto fail;
|
2009-08-07 05:10:19 +00:00
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
if (dbus_message_get_args(reply, &err,
|
|
|
|
DBUS_TYPE_STRING, &data->owner,
|
|
|
|
DBUS_TYPE_INVALID) == FALSE)
|
|
|
|
goto fail;
|
2009-08-07 05:10:19 +00:00
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
update_service(data);
|
|
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
|
|
fail:
|
|
|
|
error("%s", err.message);
|
|
|
|
dbus_error_free(&err);
|
|
|
|
service_data_free(data);
|
2009-08-07 05:10:19 +00:00
|
|
|
done:
|
|
|
|
dbus_message_unref(reply);
|
|
|
|
}
|
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
static void check_service(DBusConnection *connection,
|
|
|
|
const char *name,
|
|
|
|
struct filter_callback *callback)
|
2009-08-07 05:10:19 +00:00
|
|
|
{
|
|
|
|
DBusMessage *message;
|
|
|
|
struct service_data *data;
|
|
|
|
|
|
|
|
data = g_try_malloc0(sizeof(*data));
|
|
|
|
if (data == NULL) {
|
|
|
|
error("Can't allocate data structure");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
data->conn = dbus_connection_ref(connection);
|
|
|
|
data->name = g_strdup(name);
|
2010-09-06 13:39:41 +00:00
|
|
|
data->callback = callback;
|
|
|
|
callback->data = data;
|
2009-08-07 05:10:19 +00:00
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
data->owner = check_name_cache(name);
|
|
|
|
if (data->owner != NULL) {
|
2010-09-06 13:39:41 +00:00
|
|
|
data->id = g_idle_add(update_service, data);
|
2010-09-06 10:26:20 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-07 05:10:19 +00:00
|
|
|
message = dbus_message_new_method_call(DBUS_SERVICE_DBUS,
|
2010-09-06 10:26:20 +00:00
|
|
|
DBUS_PATH_DBUS, DBUS_INTERFACE_DBUS, "GetNameOwner");
|
2009-08-07 05:10:19 +00:00
|
|
|
if (message == NULL) {
|
|
|
|
error("Can't allocate new message");
|
|
|
|
g_free(data);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-08-08 17:21:26 +00:00
|
|
|
dbus_message_append_args(message, DBUS_TYPE_STRING, &name,
|
|
|
|
DBUS_TYPE_INVALID);
|
|
|
|
|
2009-08-07 05:10:19 +00:00
|
|
|
if (dbus_connection_send_with_reply(connection, message,
|
2010-09-06 13:39:41 +00:00
|
|
|
&data->call, -1) == FALSE) {
|
2009-08-07 05:10:19 +00:00
|
|
|
error("Failed to execute method call");
|
|
|
|
g_free(data);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
if (data->call == NULL) {
|
2009-08-07 05:10:19 +00:00
|
|
|
error("D-Bus connection not available");
|
|
|
|
g_free(data);
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2010-09-06 13:39:41 +00:00
|
|
|
dbus_pending_call_set_notify(data->call, service_reply, data, NULL);
|
2010-02-12 20:35:08 +00:00
|
|
|
|
2009-08-07 05:10:19 +00:00
|
|
|
done:
|
|
|
|
dbus_message_unref(message);
|
|
|
|
}
|
|
|
|
|
2009-04-26 18:51:36 +00:00
|
|
|
guint g_dbus_add_service_watch(DBusConnection *connection, const char *name,
|
|
|
|
GDBusWatchFunction connect,
|
|
|
|
GDBusWatchFunction disconnect,
|
|
|
|
void *user_data, GDBusDestroyFunction destroy)
|
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data;
|
|
|
|
struct filter_callback *cb;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2010-11-27 19:39:01 +00:00
|
|
|
if (name == NULL)
|
2009-12-29 08:53:21 +00:00
|
|
|
return 0;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2014-07-15 10:29:41 +00:00
|
|
|
data = filter_data_get(connection, service_filter,
|
|
|
|
DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
|
2009-12-29 08:53:21 +00:00
|
|
|
DBUS_INTERFACE_DBUS, "NameOwnerChanged",
|
|
|
|
name);
|
2010-11-27 19:39:01 +00:00
|
|
|
if (data == NULL)
|
2009-12-29 08:53:21 +00:00
|
|
|
return 0;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2012-04-03 16:14:58 +00:00
|
|
|
cb = filter_data_add_callback(data, connect, disconnect, NULL, destroy,
|
2009-12-29 08:53:21 +00:00
|
|
|
user_data);
|
2010-11-27 19:39:01 +00:00
|
|
|
if (cb == NULL)
|
2009-12-29 08:53:21 +00:00
|
|
|
return 0;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2009-08-07 05:10:19 +00:00
|
|
|
if (connect)
|
2010-09-06 13:39:41 +00:00
|
|
|
check_service(connection, name, cb);
|
2009-08-07 05:10:19 +00:00
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return cb->id;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
guint g_dbus_add_disconnect_watch(DBusConnection *connection, const char *name,
|
|
|
|
GDBusWatchFunction func,
|
|
|
|
void *user_data, GDBusDestroyFunction destroy)
|
|
|
|
{
|
|
|
|
return g_dbus_add_service_watch(connection, name, NULL, func,
|
|
|
|
user_data, destroy);
|
|
|
|
}
|
|
|
|
|
|
|
|
guint g_dbus_add_signal_watch(DBusConnection *connection,
|
2009-12-29 08:53:21 +00:00
|
|
|
const char *sender, const char *path,
|
|
|
|
const char *interface, const char *member,
|
|
|
|
GDBusSignalFunction function, void *user_data,
|
|
|
|
GDBusDestroyFunction destroy)
|
2009-04-26 18:51:36 +00:00
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data;
|
|
|
|
struct filter_callback *cb;
|
|
|
|
|
|
|
|
data = filter_data_get(connection, signal_filter, sender, path,
|
|
|
|
interface, member, NULL);
|
2010-11-27 19:39:01 +00:00
|
|
|
if (data == NULL)
|
2009-12-29 08:53:21 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
|
|
|
|
user_data);
|
2010-11-27 19:39:01 +00:00
|
|
|
if (cb == NULL)
|
2009-12-29 08:53:21 +00:00
|
|
|
return 0;
|
|
|
|
|
2010-09-06 10:26:20 +00:00
|
|
|
if (data->name != NULL && data->name_watch == 0)
|
|
|
|
data->name_watch = g_dbus_add_service_watch(connection,
|
|
|
|
data->name, NULL,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
return cb->id;
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
2012-11-27 12:51:20 +00:00
|
|
|
guint g_dbus_add_properties_watch(DBusConnection *connection,
|
|
|
|
const char *sender, const char *path,
|
|
|
|
const char *interface,
|
|
|
|
GDBusSignalFunction function, void *user_data,
|
|
|
|
GDBusDestroyFunction destroy)
|
|
|
|
{
|
|
|
|
struct filter_data *data;
|
|
|
|
struct filter_callback *cb;
|
|
|
|
|
|
|
|
data = filter_data_get(connection, signal_filter, sender, path,
|
|
|
|
DBUS_INTERFACE_PROPERTIES, "PropertiesChanged",
|
|
|
|
interface);
|
|
|
|
if (data == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
|
|
|
|
user_data);
|
|
|
|
if (cb == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (data->name != NULL && data->name_watch == 0)
|
|
|
|
data->name_watch = g_dbus_add_service_watch(connection,
|
|
|
|
data->name, NULL,
|
|
|
|
NULL, NULL, NULL);
|
|
|
|
|
|
|
|
return cb->id;
|
|
|
|
}
|
|
|
|
|
2009-04-26 18:51:36 +00:00
|
|
|
gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
|
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data;
|
|
|
|
struct filter_callback *cb;
|
|
|
|
GSList *ldata;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
|
|
|
if (id == 0)
|
|
|
|
return FALSE;
|
|
|
|
|
2009-12-29 08:53:21 +00:00
|
|
|
for (ldata = listeners; ldata; ldata = ldata->next) {
|
2009-04-26 18:51:36 +00:00
|
|
|
data = ldata->data;
|
2009-12-29 08:53:21 +00:00
|
|
|
|
|
|
|
cb = filter_data_find_callback(data, id);
|
|
|
|
if (cb) {
|
|
|
|
filter_data_remove_callback(data, cb);
|
|
|
|
return TRUE;
|
2009-05-06 20:15:27 +00:00
|
|
|
}
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
void g_dbus_remove_all_watches(DBusConnection *connection)
|
|
|
|
{
|
2009-12-29 08:53:21 +00:00
|
|
|
struct filter_data *data;
|
2009-04-26 18:51:36 +00:00
|
|
|
|
2012-10-03 11:57:23 +00:00
|
|
|
while ((data = filter_data_find(connection))) {
|
2009-12-29 08:53:21 +00:00
|
|
|
listeners = g_slist_remove(listeners, data);
|
|
|
|
filter_data_call_and_free(data);
|
2009-04-26 18:51:36 +00:00
|
|
|
}
|
|
|
|
}
|