diff options
Diffstat (limited to 'gdbus')
-rw-r--r-- | gdbus/client.c | 466 | ||||
-rw-r--r-- | gdbus/gdbus.h | 12 | ||||
-rw-r--r-- | gdbus/mainloop.c | 15 | ||||
-rw-r--r-- | gdbus/object.c | 190 | ||||
-rw-r--r-- | gdbus/watch.c | 35 |
5 files changed, 370 insertions, 348 deletions
diff --git a/gdbus/client.c b/gdbus/client.c index f700b7ee..3bf883ac 100644 --- a/gdbus/client.c +++ b/gdbus/client.c @@ -25,6 +25,7 @@ #include <config.h> #endif +#include <stdio.h> #include <glib.h> #include <dbus/dbus.h> @@ -32,12 +33,18 @@ #define METHOD_CALL_TIMEOUT (300 * 1000) +#ifndef DBUS_INTERFACE_OBJECT_MANAGER +#define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager" +#endif + struct GDBusClient { int ref_count; DBusConnection *dbus_conn; char *service_name; - char *unique_name; char *base_path; + guint watch; + guint added_watch; + guint removed_watch; GPtrArray *match_rules; DBusPendingCall *pending_call; DBusPendingCall *get_objects_call; @@ -49,6 +56,8 @@ struct GDBusClient { void *signal_data; GDBusProxyFunction proxy_added; GDBusProxyFunction proxy_removed; + GDBusClientFunction ready; + void *ready_data; GDBusPropertyFunction property_changed; void *user_data; GList *proxy_list; @@ -60,7 +69,7 @@ struct GDBusProxy { char *obj_path; char *interface; GHashTable *prop_list; - char *match_rule; + guint watch; GDBusPropertyFunction prop_func; void *prop_data; GDBusProxyFunction removed_func; @@ -100,12 +109,7 @@ static gboolean modify_match(DBusConnection *conn, const char *member, dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule, DBUS_TYPE_INVALID); - if (dbus_connection_send_with_reply(conn, msg, &call, -1) == FALSE) { - dbus_message_unref(msg); - return FALSE; - } - - if (call == NULL) { + if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) { dbus_message_unref(msg); return FALSE; } @@ -319,7 +323,7 @@ static void get_all_properties(GDBusProxy *proxy) dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface, DBUS_TYPE_INVALID); - if (dbus_connection_send_with_reply(client->dbus_conn, msg, + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, -1) == FALSE) { dbus_message_unref(msg); return; @@ -351,6 +355,52 @@ static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path, return NULL; } +static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg, + void *user_data) +{ + GDBusProxy *proxy = user_data; + GDBusClient *client = proxy->client; + DBusMessageIter iter, entry; + const char *interface; + + if (dbus_message_iter_init(msg, &iter) == FALSE) + return TRUE; + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) + return TRUE; + + dbus_message_iter_get_basic(&iter, &interface); + dbus_message_iter_next(&iter); + + update_properties(proxy, &iter, TRUE); + + dbus_message_iter_next(&iter); + + if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) + return TRUE; + + dbus_message_iter_recurse(&iter, &entry); + + while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { + const char *name; + + dbus_message_iter_get_basic(&entry, &name); + + g_hash_table_remove(proxy->prop_list, name); + + if (proxy->prop_func) + proxy->prop_func(proxy, name, NULL, proxy->prop_data); + + if (client->property_changed) + client->property_changed(proxy, name, NULL, + client->user_data); + + dbus_message_iter_next(&entry); + } + + return TRUE; +} + static GDBusProxy *proxy_new(GDBusClient *client, const char *path, const char *interface) { @@ -366,14 +416,12 @@ static GDBusProxy *proxy_new(GDBusClient *client, const char *path, proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, prop_entry_free); - - proxy->match_rule = g_strdup_printf("type='signal'," - "sender='%s',path='%s',interface='%s'," - "member='PropertiesChanged',arg0='%s'", - client->service_name, proxy->obj_path, - DBUS_INTERFACE_PROPERTIES, proxy->interface); - - modify_match(client->dbus_conn, "AddMatch", proxy->match_rule); + proxy->watch = g_dbus_add_properties_watch(client->dbus_conn, + client->service_name, + proxy->obj_path, + proxy->interface, + properties_changed, + proxy, NULL); return g_dbus_proxy_ref(proxy); } @@ -388,11 +436,7 @@ static void proxy_free(gpointer data) if (client->proxy_removed) client->proxy_removed(proxy, client->user_data); - modify_match(client->dbus_conn, "RemoveMatch", - proxy->match_rule); - - g_free(proxy->match_rule); - proxy->match_rule = NULL; + g_dbus_remove_watch(client->dbus_conn, proxy->watch); g_hash_table_remove_all(proxy->prop_list); @@ -575,7 +619,7 @@ gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name) &proxy->interface); dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); - if (dbus_connection_send_with_reply(client->dbus_conn, msg, + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, -1) == FALSE) { dbus_message_unref(msg); refresh_property_free(data); @@ -668,7 +712,94 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, dbus_message_iter_append_basic(&variant, type, value); dbus_message_iter_close_container(&iter, &variant); - if (dbus_connection_send_with_reply(client->dbus_conn, msg, + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, + &call, -1) == FALSE) { + dbus_message_unref(msg); + g_free(data); + return FALSE; + } + + dbus_pending_call_set_notify(call, set_property_reply, data, g_free); + dbus_pending_call_unref(call); + + dbus_message_unref(msg); + + return TRUE; +} + +gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, + const char *name, int type, const void *value, + size_t size, GDBusResultFunction function, + void *user_data, GDBusDestroyFunction destroy) +{ + struct set_property_data *data; + GDBusClient *client; + DBusMessage *msg; + DBusMessageIter iter, variant, array; + DBusPendingCall *call; + char array_sig[3]; + char type_sig[2]; + + if (!proxy || !name || !value) + return FALSE; + + if (!dbus_type_is_basic(type)) + return FALSE; + + client = proxy->client; + if (!client) + return FALSE; + + data = g_try_new0(struct set_property_data, 1); + if (!data) + return FALSE; + + data->function = function; + data->user_data = user_data; + data->destroy = destroy; + + msg = dbus_message_new_method_call(client->service_name, + proxy->obj_path, + DBUS_INTERFACE_PROPERTIES, + "Set"); + if (!msg) { + g_free(data); + return FALSE; + } + + array_sig[0] = DBUS_TYPE_ARRAY; + array_sig[1] = (char) type; + array_sig[2] = '\0'; + + type_sig[0] = (char) type; + type_sig[1] = '\0'; + + dbus_message_iter_init_append(msg, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, + &proxy->interface); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name); + + dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT, + array_sig, &variant); + + dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY, + type_sig, &array); + + if (dbus_type_is_fixed(type)) + dbus_message_iter_append_fixed_array(&array, type, &value, + size); + else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) { + const char **str = (const char **) value; + size_t i; + + for (i = 0; i < size; i++) + dbus_message_iter_append_basic(&array, type, &str[i]); + } + + dbus_message_iter_close_container(&variant, &array); + dbus_message_iter_close_container(&iter, &variant); + + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, -1) == FALSE) { dbus_message_unref(msg); g_free(data); @@ -742,7 +873,7 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method, setup(&iter, data->user_data); } - if (dbus_connection_send_with_reply(client->dbus_conn, msg, + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &call, METHOD_CALL_TIMEOUT) == FALSE) { dbus_message_unref(msg); g_free(data); @@ -793,64 +924,6 @@ static void refresh_properties(GDBusClient *client) } } -static void properties_changed(GDBusClient *client, const char *path, - DBusMessage *msg) -{ - GDBusProxy *proxy = NULL; - DBusMessageIter iter, entry; - const char *interface; - GList *list; - - if (dbus_message_iter_init(msg, &iter) == FALSE) - return; - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) - return; - - dbus_message_iter_get_basic(&iter, &interface); - dbus_message_iter_next(&iter); - - for (list = g_list_first(client->proxy_list); list; - list = g_list_next(list)) { - GDBusProxy *data = list->data; - - if (g_str_equal(data->interface, interface) == TRUE && - g_str_equal(data->obj_path, path) == TRUE) { - proxy = data; - break; - } - } - - if (proxy == NULL) - return; - - update_properties(proxy, &iter, TRUE); - - dbus_message_iter_next(&iter); - - if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) - return; - - dbus_message_iter_recurse(&iter, &entry); - - while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) { - const char *name; - - dbus_message_iter_get_basic(&entry, &name); - - g_hash_table_remove(proxy->prop_list, name); - - if (proxy->prop_func) - proxy->prop_func(proxy, name, NULL, proxy->prop_data); - - if (client->property_changed) - client->property_changed(proxy, name, NULL, - client->user_data); - - dbus_message_iter_next(&entry); - } -} - static void parse_properties(GDBusClient *client, const char *path, const char *interface, DBusMessageIter *iter) { @@ -908,16 +981,18 @@ static void parse_interfaces(GDBusClient *client, const char *path, } } -static void interfaces_added(GDBusClient *client, DBusMessage *msg) +static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg, + void *user_data) { + GDBusClient *client = user_data; DBusMessageIter iter; const char *path; if (dbus_message_iter_init(msg, &iter) == FALSE) - return; + return TRUE; if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) - return; + return TRUE; dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); @@ -927,24 +1002,28 @@ static void interfaces_added(GDBusClient *client, DBusMessage *msg) parse_interfaces(client, path, &iter); g_dbus_client_unref(client); + + return TRUE; } -static void interfaces_removed(GDBusClient *client, DBusMessage *msg) +static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg, + void *user_data) { + GDBusClient *client = user_data; DBusMessageIter iter, entry; const char *path; if (dbus_message_iter_init(msg, &iter) == FALSE) - return; + return TRUE; if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH) - return; + return TRUE; dbus_message_iter_get_basic(&iter, &path); dbus_message_iter_next(&iter); if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) - return; + return TRUE; dbus_message_iter_recurse(&iter, &entry); @@ -959,6 +1038,8 @@ static void interfaces_removed(GDBusClient *client, DBusMessage *msg) } g_dbus_client_unref(client); + + return TRUE; } static void parse_managed_objects(GDBusClient *client, DBusMessage *msg) @@ -990,6 +1071,9 @@ static void parse_managed_objects(GDBusClient *client, DBusMessage *msg) dbus_message_iter_next(&dict); } + + if (client->ready) + client->ready(client, client->ready_data); } static void get_managed_objects_reply(DBusPendingCall *call, void *user_data) @@ -1038,7 +1122,7 @@ static void get_managed_objects(GDBusClient *client) dbus_message_append_args(msg, DBUS_TYPE_INVALID); - if (dbus_connection_send_with_reply(client->dbus_conn, msg, + if (g_dbus_send_message_with_reply(client->dbus_conn, msg, &client->get_objects_call, -1) == FALSE) { dbus_message_unref(msg); return; @@ -1051,74 +1135,36 @@ static void get_managed_objects(GDBusClient *client) dbus_message_unref(msg); } -static void get_name_owner_reply(DBusPendingCall *call, void *user_data) +static void service_connect(DBusConnection *conn, void *user_data) { GDBusClient *client = user_data; - DBusMessage *reply = dbus_pending_call_steal_reply(call); - DBusError error; - const char *name; g_dbus_client_ref(client); - dbus_error_init(&error); - - if (dbus_set_error_from_message(&error, reply) == TRUE) { - dbus_error_free(&error); - goto done; - } - - if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID) == FALSE) - goto done; - - if (client->unique_name == NULL) { - client->unique_name = g_strdup(name); - - if (client->connect_func) - client->connect_func(client->dbus_conn, - client->connect_data); - - get_managed_objects(client); - } - -done: - dbus_message_unref(reply); + if (client->connect_func) + client->connect_func(conn, client->connect_data); - dbus_pending_call_unref(client->pending_call); - client->pending_call = NULL; + get_managed_objects(client); g_dbus_client_unref(client); } -static void get_name_owner(GDBusClient *client, const char *name) +static void service_disconnect(DBusConnection *conn, void *user_data) { - DBusMessage *msg; - - msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, "GetNameOwner"); - if (msg == NULL) - return; - - dbus_message_append_args(msg, DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID); - - if (dbus_connection_send_with_reply(client->dbus_conn, msg, - &client->pending_call, -1) == FALSE) { - dbus_message_unref(msg); - return; - } + GDBusClient *client = user_data; - dbus_pending_call_set_notify(client->pending_call, - get_name_owner_reply, client, NULL); + g_list_free_full(client->proxy_list, proxy_free); + client->proxy_list = NULL; - dbus_message_unref(msg); + if (client->disconn_func) + client->disconn_func(conn, client->disconn_data); } static DBusHandlerResult message_filter(DBusConnection *connection, DBusMessage *message, void *user_data) { GDBusClient *client = user_data; - const char *sender; + const char *sender, *path, *interface; if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; @@ -1127,93 +1173,17 @@ static DBusHandlerResult message_filter(DBusConnection *connection, if (sender == NULL) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (g_str_equal(sender, DBUS_SERVICE_DBUS) == TRUE) { - const char *interface, *member; - const char *name, *old, *new; - - interface = dbus_message_get_interface(message); - - if (g_str_equal(interface, DBUS_INTERFACE_DBUS) == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - member = dbus_message_get_member(message); - - if (g_str_equal(member, "NameOwnerChanged") == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (dbus_message_get_args(message, NULL, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_STRING, &old, - DBUS_TYPE_STRING, &new, - DBUS_TYPE_INVALID) == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (g_str_equal(name, client->service_name) == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (*new == '\0' && client->unique_name != NULL && - g_str_equal(old, client->unique_name) == TRUE) { - if (client->disconn_func) - client->disconn_func(client->dbus_conn, - client->disconn_data); - - g_free(client->unique_name); - client->unique_name = NULL; - } else if (*old == '\0' && client->unique_name == NULL) { - client->unique_name = g_strdup(new); - - if (client->connect_func) - client->connect_func(client->dbus_conn, - client->connect_data); - - get_managed_objects(client); - } + path = dbus_message_get_path(message); + interface = dbus_message_get_interface(message); + if (g_str_has_prefix(path, client->base_path) == FALSE) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - if (client->unique_name == NULL) + if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - if (g_str_equal(sender, client->unique_name) == TRUE) { - const char *path, *interface, *member; - - path = dbus_message_get_path(message); - interface = dbus_message_get_interface(message); - member = dbus_message_get_member(message); - - if (g_str_equal(path, "/") == TRUE) { - if (g_str_equal(interface, DBUS_INTERFACE_DBUS - ".ObjectManager") == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (g_str_equal(member, "InterfacesAdded") == TRUE) { - interfaces_added(client, message); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if (g_str_equal(member, "InterfacesRemoved") == TRUE) { - interfaces_removed(client, message); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if (g_str_has_prefix(path, client->base_path) == FALSE) - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - - if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE) { - if (g_str_equal(member, "PropertiesChanged") == TRUE) - properties_changed(client, path, message); - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; - } - - if (client->signal_func) - client->signal_func(client->dbus_conn, - message, client->signal_data); - } + if (client->signal_func) + client->signal_func(connection, message, client->signal_data); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -1241,26 +1211,25 @@ GDBusClient *g_dbus_client_new(DBusConnection *connection, client->service_name = g_strdup(service); client->base_path = g_strdup(path); - get_name_owner(client, client->service_name); - - client->match_rules = g_ptr_array_sized_new(4); + client->match_rules = g_ptr_array_sized_new(1); g_ptr_array_set_free_func(client->match_rules, g_free); - g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal'," - "sender='%s',path='%s',interface='%s'," - "member='NameOwnerChanged',arg0='%s'", - DBUS_SERVICE_DBUS, DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, client->service_name)); - g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal'," - "sender='%s'," - "path='/',interface='%s.ObjectManager'," - "member='InterfacesAdded'", - client->service_name, DBUS_INTERFACE_DBUS)); - g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal'," - "sender='%s'," - "path='/',interface='%s.ObjectManager'," - "member='InterfacesRemoved'", - client->service_name, DBUS_INTERFACE_DBUS)); + client->watch = g_dbus_add_service_watch(connection, service, + service_connect, + service_disconnect, + client, NULL); + client->added_watch = g_dbus_add_signal_watch(connection, service, + "/", + DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesAdded", + interfaces_added, + client, NULL); + client->removed_watch = g_dbus_add_signal_watch(connection, service, + "/", + DBUS_INTERFACE_OBJECT_MANAGER, + "InterfacesRemoved", + interfaces_removed, + client, NULL); g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal'," "sender='%s',path_namespace='%s'", client->service_name, client->base_path)); @@ -1318,10 +1287,13 @@ void g_dbus_client_unref(GDBusClient *client) if (client->disconn_func) client->disconn_func(client->dbus_conn, client->disconn_data); + g_dbus_remove_watch(client->dbus_conn, client->watch); + g_dbus_remove_watch(client->dbus_conn, client->added_watch); + g_dbus_remove_watch(client->dbus_conn, client->removed_watch); + dbus_connection_unref(client->dbus_conn); g_free(client->service_name); - g_free(client->unique_name); g_free(client->base_path); g_free(client); @@ -1363,6 +1335,18 @@ gboolean g_dbus_client_set_signal_watch(GDBusClient *client, return TRUE; } +gboolean g_dbus_client_set_ready_watch(GDBusClient *client, + GDBusClientFunction ready, void *user_data) +{ + if (client == NULL) + return FALSE; + + client->ready = ready; + client->ready_data = user_data; + + return TRUE; +} + gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client, GDBusProxyFunction proxy_added, GDBusProxyFunction proxy_removed, diff --git a/gdbus/gdbus.h b/gdbus/gdbus.h index 8b133939..551c306a 100644 --- a/gdbus/gdbus.h +++ b/gdbus/gdbus.h @@ -250,6 +250,9 @@ DBusMessage *g_dbus_create_reply_valist(DBusMessage *message, int type, va_list args); gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message); +gboolean g_dbus_send_message_with_reply(DBusConnection *connection, + DBusMessage *message, + DBusPendingCall **call, int timeout); gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message, const char *name, const char *format, ...) __attribute__((format(printf, 4, 5))); @@ -326,6 +329,11 @@ gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy, GDBusResultFunction function, void *user_data, GDBusDestroyFunction destroy); +gboolean g_dbus_proxy_set_property_array(GDBusProxy *proxy, + const char *name, int type, const void *value, + size_t size, GDBusResultFunction function, + void *user_data, GDBusDestroyFunction destroy); + typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data); typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data); @@ -334,6 +342,7 @@ gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method, GDBusReturnFunction function, void *user_data, GDBusDestroyFunction destroy); +typedef void (* GDBusClientFunction) (GDBusClient *client, void *user_data); typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data); typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name, DBusMessageIter *iter, void *user_data); @@ -356,7 +365,8 @@ gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client, GDBusWatchFunction function, void *user_data); gboolean g_dbus_client_set_signal_watch(GDBusClient *client, GDBusMessageFunction function, void *user_data); - +gboolean g_dbus_client_set_ready_watch(GDBusClient *client, + GDBusClientFunction ready, void *user_data); gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client, GDBusProxyFunction proxy_added, GDBusProxyFunction proxy_removed, diff --git a/gdbus/mainloop.c b/gdbus/mainloop.c index 099b67fe..435fb93b 100644 --- a/gdbus/mainloop.c +++ b/gdbus/mainloop.c @@ -30,8 +30,6 @@ #include "gdbus.h" -#define DISPATCH_TIMEOUT 0 - #define info(fmt...) #define error(fmt...) #define debug(fmt...) @@ -70,8 +68,6 @@ static gboolean message_dispatch(void *data) { DBusConnection *conn = data; - dbus_connection_ref(conn); - /* Dispatch messages */ while (dbus_connection_dispatch(conn) == DBUS_DISPATCH_DATA_REMAINS); @@ -84,7 +80,7 @@ static inline void queue_dispatch(DBusConnection *conn, DBusDispatchStatus status) { if (status == DBUS_DISPATCH_DATA_REMAINS) - g_timeout_add(DISPATCH_TIMEOUT, message_dispatch, conn); + g_idle_add(message_dispatch, dbus_connection_ref(conn)); } static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) @@ -92,9 +88,6 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) struct watch_info *info = data; unsigned int flags = 0; DBusDispatchStatus status; - DBusConnection *conn; - - conn = dbus_connection_ref(info->conn); if (cond & G_IO_IN) flags |= DBUS_WATCH_READABLE; if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE; @@ -103,10 +96,8 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data) dbus_watch_handle(info->watch, flags); - status = dbus_connection_get_dispatch_status(conn); - queue_dispatch(conn, status); - - dbus_connection_unref(conn); + status = dbus_connection_get_dispatch_status(info->conn); + queue_dispatch(info->conn, status); return TRUE; } diff --git a/gdbus/object.c b/gdbus/object.c index 2f8ef453..13cf9a95 100644 --- a/gdbus/object.c +++ b/gdbus/object.c @@ -86,6 +86,7 @@ struct property_data { static int global_flags = 0; static struct generic_data *root; +static GSList *pending = NULL; static gboolean process_changes(gpointer user_data); static void process_properties_from_interface(struct generic_data *data, @@ -271,8 +272,7 @@ static DBusHandlerResult process_message(DBusConnection *connection, if (reply == NULL) return DBUS_HANDLER_RESULT_NEED_MEMORY; - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); + g_dbus_send_message(connection, reply); return DBUS_HANDLER_RESULT_HANDLED; } @@ -312,19 +312,14 @@ void g_dbus_pending_error_valist(DBusConnection *connection, for (list = pending_security; list; list = list->next) { struct security_data *secdata = list->data; - DBusMessage *reply; if (secdata->pending != pending) continue; pending_security = g_slist_remove(pending_security, secdata); - reply = g_dbus_create_error_valist(secdata->message, + g_dbus_send_error_valist(connection, secdata->message, name, format, args); - if (reply != NULL) { - dbus_connection_send(connection, reply, NULL); - dbus_message_unref(reply); - } dbus_message_unref(secdata->message); g_free(secdata); @@ -469,18 +464,13 @@ void g_dbus_pending_property_error_valist(GDBusPendingReply id, va_list args) { struct property_data *propdata; - DBusMessage *reply; propdata = remove_pending_property_data(id); if (propdata == NULL) return; - reply = g_dbus_create_error_valist(propdata->message, name, format, - args); - if (reply != NULL) { - dbus_connection_send(propdata->conn, reply, NULL); - dbus_message_unref(reply); - } + g_dbus_send_error_valist(propdata->conn, propdata->message, name, + format, args); dbus_message_unref(propdata->message); g_free(propdata); @@ -599,7 +589,9 @@ static void emit_interfaces_added(struct generic_data *data) dbus_message_iter_close_container(&iter, &array); - g_dbus_send_message(data->conn, signal); + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ + dbus_connection_send(data->conn, signal, NULL); + dbus_message_unref(signal); } static struct interface_data *find_interface(GSList *interfaces, @@ -640,6 +632,16 @@ static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args, return TRUE; } +static void add_pending(struct generic_data *data) +{ + if (data->process_id > 0) + return; + + data->process_id = g_idle_add(process_changes, data); + + pending = g_slist_append(pending, data); +} + static gboolean remove_interface(struct generic_data *data, const char *name) { struct interface_data *iface; @@ -677,10 +679,7 @@ static gboolean remove_interface(struct generic_data *data, const char *name) data->removed = g_slist_prepend(data->removed, iface->name); g_free(iface); - if (data->process_id > 0) - return TRUE; - - data->process_id = g_idle_add(process_changes, data); + add_pending(data); return TRUE; } @@ -976,14 +975,26 @@ static void emit_interfaces_removed(struct generic_data *data) dbus_message_iter_close_container(&iter, &array); - g_dbus_send_message(data->conn, signal); + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ + dbus_connection_send(data->conn, signal, NULL); + dbus_message_unref(signal); +} + +static void remove_pending(struct generic_data *data) +{ + if (data->process_id > 0) { + g_source_remove(data->process_id); + data->process_id = 0; + } + + pending = g_slist_remove(pending, data); } static gboolean process_changes(gpointer user_data) { struct generic_data *data = user_data; - data->process_id = 0; + remove_pending(data); if (data->added != NULL) emit_interfaces_added(data); @@ -995,6 +1006,8 @@ static gboolean process_changes(gpointer user_data) if (data->removed != NULL) emit_interfaces_removed(data); + data->process_id = 0; + return FALSE; } @@ -1008,6 +1021,7 @@ static void generic_unregister(DBusConnection *connection, void *user_data) if (data->process_id > 0) { g_source_remove(data->process_id); + data->process_id = 0; process_changes(data); } @@ -1211,10 +1225,8 @@ done: return TRUE; data->added = g_slist_append(data->added, iface); - if (data->process_id > 0) - return TRUE; - data->process_id = g_idle_add(process_changes, data); + add_pending(data); return TRUE; } @@ -1241,6 +1253,8 @@ static struct generic_data *object_path_ref(DBusConnection *connection, if (!dbus_connection_register_object_path(connection, path, &generic_table, data)) { + dbus_connection_unref(data->conn); + g_free(data->path); g_free(data->introspect); g_free(data); return NULL; @@ -1319,45 +1333,6 @@ static gboolean check_signal(DBusConnection *conn, const char *path, return FALSE; } -static dbus_bool_t emit_signal_valist(DBusConnection *conn, - const char *path, - const char *interface, - const char *name, - int first, - va_list var_args) -{ - DBusMessage *signal; - dbus_bool_t ret; - const GDBusArgInfo *args; - - if (!check_signal(conn, path, interface, name, &args)) - return FALSE; - - signal = dbus_message_new_signal(path, interface, name); - if (signal == NULL) { - error("Unable to allocate new %s.%s signal", interface, name); - return FALSE; - } - - ret = dbus_message_append_args_valist(signal, first, var_args); - if (!ret) - goto fail; - - if (g_dbus_args_have_signature(args, signal) == FALSE) { - error("%s.%s: got unexpected signature '%s'", interface, name, - dbus_message_get_signature(signal)); - ret = FALSE; - goto fail; - } - - ret = dbus_connection_send(conn, signal, NULL); - -fail: - dbus_message_unref(signal); - - return ret; -} - gboolean g_dbus_register_interface(DBusConnection *connection, const char *path, const char *name, const GDBusMethodTable *methods, @@ -1494,6 +1469,21 @@ DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...) return reply; } +static void g_dbus_flush(DBusConnection *connection) +{ + GSList *l; + + for (l = pending; l;) { + struct generic_data *data = l->data; + + l = l->next; + if (data->conn != connection) + continue; + + process_changes(data); + } +} + gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message) { dbus_bool_t result = FALSE; @@ -1510,6 +1500,9 @@ gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message) goto out; } + /* Flush pending signal to guarantee message order */ + g_dbus_flush(connection); + result = dbus_connection_send(connection, message, NULL); out: @@ -1518,6 +1511,26 @@ out: return result; } +gboolean g_dbus_send_message_with_reply(DBusConnection *connection, + DBusMessage *message, + DBusPendingCall **call, int timeout) +{ + dbus_bool_t ret; + + /* Flush pending signal to guarantee message order */ + g_dbus_flush(connection); + + ret = dbus_connection_send_with_reply(connection, message, call, + timeout); + + if (ret == TRUE && call != NULL && *call == NULL) { + error("Unable to send message (passing fd blocked?)"); + return FALSE; + } + + return ret; +} + gboolean g_dbus_send_error_valist(DBusConnection *connection, DBusMessage *message, const char *name, const char *format, va_list args) @@ -1591,7 +1604,7 @@ gboolean g_dbus_emit_signal(DBusConnection *connection, va_start(args, type); - result = emit_signal_valist(connection, path, interface, + result = g_dbus_emit_signal_valist(connection, path, interface, name, type, args); va_end(args); @@ -1603,8 +1616,36 @@ gboolean g_dbus_emit_signal_valist(DBusConnection *connection, const char *path, const char *interface, const char *name, int type, va_list args) { - return emit_signal_valist(connection, path, interface, - name, type, args); + DBusMessage *signal; + dbus_bool_t ret; + const GDBusArgInfo *args_info; + + if (!check_signal(connection, path, interface, name, &args_info)) + return FALSE; + + signal = dbus_message_new_signal(path, interface, name); + if (signal == NULL) { + error("Unable to allocate new %s.%s signal", interface, name); + return FALSE; + } + + ret = dbus_message_append_args_valist(signal, type, args); + if (!ret) + goto fail; + + if (g_dbus_args_have_signature(args_info, signal) == FALSE) { + error("%s.%s: got unexpected signature '%s'", interface, name, + dbus_message_get_signature(signal)); + ret = FALSE; + goto fail; + } + + return g_dbus_send_message(connection, signal); + +fail: + dbus_message_unref(signal); + + return ret; } static void process_properties_from_interface(struct generic_data *data, @@ -1615,6 +1656,8 @@ static void process_properties_from_interface(struct generic_data *data, DBusMessageIter iter, dict, array; GSList *invalidated; + data->pending_prop = FALSE; + if (iface->pending_prop == NULL) return; @@ -1664,10 +1707,12 @@ static void process_properties_from_interface(struct generic_data *data, g_slist_free(invalidated); dbus_message_iter_close_container(&iter, &array); - g_dbus_send_message(data->conn, signal); - g_slist_free(iface->pending_prop); iface->pending_prop = NULL; + + /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */ + dbus_connection_send(data->conn, signal, NULL); + dbus_message_unref(signal); } static void process_property_changes(struct generic_data *data) @@ -1679,8 +1724,6 @@ static void process_property_changes(struct generic_data *data) process_properties_from_interface(data, iface); } - - data->pending_prop = FALSE; } void g_dbus_emit_property_changed(DBusConnection *connection, @@ -1723,10 +1766,7 @@ void g_dbus_emit_property_changed(DBusConnection *connection, iface->pending_prop = g_slist_prepend(iface->pending_prop, (void *) property); - if (!data->process_id) { - data->process_id = g_idle_add(process_changes, data); - return; - } + add_pending(data); } gboolean g_dbus_get_properties(DBusConnection *connection, const char *path, diff --git a/gdbus/watch.c b/gdbus/watch.c index 9e4f994a..0f99f4f1 100644 --- a/gdbus/watch.c +++ b/gdbus/watch.c @@ -281,6 +281,11 @@ static void filter_data_free(struct filter_data *data) { GSList *l; + /* 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); + for (l = data->callbacks; l != NULL; l = l->next) g_free(l->data); @@ -360,8 +365,6 @@ static void service_data_free(struct service_data *data) static gboolean filter_data_remove_callback(struct filter_data *data, struct filter_callback *cb) { - DBusConnection *connection; - data->callbacks = g_slist_remove(data->callbacks, cb); data->processed = g_slist_remove(data->processed, cb); @@ -385,16 +388,8 @@ static gboolean filter_data_remove_callback(struct filter_data *data, if (data->registered && !remove_match(data)) return FALSE; - connection = dbus_connection_ref(data->connection); listeners = g_slist_remove(listeners, data); - - /* Remove filter if there are no listeners left for the connection */ - if (filter_data_find(connection) == NULL) - dbus_connection_remove_filter(connection, message_filter, - NULL); - filter_data_free(data); - dbus_connection_unref(connection); return TRUE; } @@ -524,6 +519,8 @@ static DBusHandlerResult message_filter(DBusConnection *connection, dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID); /* Sender is always the owner */ + if (sender == NULL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; for (current = listeners; current != NULL; current = current->next) { data = current->data; @@ -563,6 +560,9 @@ static DBusHandlerResult message_filter(DBusConnection *connection, current); } + if (delete_listener == NULL) + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + for (current = delete_listener; current != NULL; current = delete_listener->next) { GSList *l = current->data; @@ -581,11 +581,6 @@ static DBusHandlerResult message_filter(DBusConnection *connection, g_slist_free(delete_listener); - /* Remove filter if there are no listeners left for the connection */ - if (filter_data_find(connection) == NULL) - dbus_connection_remove_filter(connection, message_filter, - NULL); - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } @@ -593,12 +588,16 @@ static gboolean update_service(void *user_data) { struct service_data *data = user_data; struct filter_callback *cb = data->callback; + DBusConnection *conn; update_name_cache(data->name, data->owner); + conn = dbus_connection_ref(data->conn); + service_data_free(data); + if (cb->conn_func) - cb->conn_func(data->conn, cb->user_data); + cb->conn_func(conn, cb->user_data); - service_data_free(data); + dbus_connection_unref(conn); return FALSE; } @@ -810,6 +809,4 @@ void g_dbus_remove_all_watches(DBusConnection *connection) listeners = g_slist_remove(listeners, data); filter_data_call_and_free(data); } - - dbus_connection_remove_filter(connection, message_filter, NULL); } |