From ab1ae1f4e204e0ee36690c828ea4a66fb9427633 Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Wed, 29 Jun 2005 16:59:00 +0000 Subject: 2005-06-29 Colin Walters * glib/dbus-gproxy.c (struct _DBusGProxy): Add new member name_call for keeping track of any outgoing GetNameOwner call. Also add for_owner and associated. (struct _DBusGProxyManager): Add owner_names, which is hash table that maps a base name to a list of names it owns (that we're interested in). Add pending_nameowner_calls which is a list of all outstanding GetNameOwner; avoids us having to iterate over every proxy. Add unassociated_proxies which keeps track of name proxies with no associated name owner. (dbus_g_proxy_manager_unref): Destroy owner_names. (struct DBusGProxyNameOwnerInfo): New struct for keeping track of name refcounts. (find_name_in_info, name_owner_foreach) (dbus_g_proxy_manager_lookup_name_owner, insert_nameinfo) (dbus_g_proxy_manager_monitor_name_owner) (dbus_g_proxy_manager_unmonitor_name_owner) (unassociate_proxies, dbus_g_proxy_manager_replace_name_owner): New functions; they manipulate the owner_names mapping. (got_name_owner_cb): New function. (get_name_owner): New function, extracted from dbus_g_proxy_new_for_name_owner. (dbus_g_proxy_manager_register): For now we need to keep track of all NameOwnerChanged. Also if the proxy is for a name, if we don't already know the name owner, queue a new GetNameOwner request and add it to our list of unassociated proxies. Otherwise inc the refcount. (dbus_g_proxy_manager_unregister): If this proxy is for a name, cancel any pending GetNameOwner call, etc. (dbus_g_proxy_manager_filter): Handle NameOwnerChanged. Also use the owner_names mapping to look up the current names for the signal source, and dispatch to any proxies for that name. (dbus_g_proxy_new): Initialize new members. (dbus_g_proxy_new_for_name): Delete unused proxy variable. (dbus_g_proxy_new_for_name_owner): Use get_name_owner. (dbus_g_pending_call_end_valist): New function, extracted from dbus_g_proxy_end_call_internal. Useful when we don't have a proxy but want to use the GLib infrastructure. Also note how many arguments in reply were over. (dbus_g_pending_call_end): New function, just call dbus_g_pending_call_end_valist. (dbus_g_proxy_end_call_internal): Just call dbus_g_pending_call_end_valist. * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Fix lookup of builtin marshaller for STRING_STRING_STRING. * test/glib/test-dbus-glib.c: * test/glib/test-service-glib.c: * test/glib/test-service-glib.xml: Extend tests to cover name proxies, destruction of owner proxies, etc. * glib/examples/example-signal-recipient.c (dbus_g_proxy_new_for_name_owner): Create a name proxy. * tools/dbus-send.c (main): Print D-BUS error name in addition to message. --- ChangeLog | 60 +++ glib/dbus-gobject.c | 14 +- glib/dbus-gproxy.c | 780 +++++++++++++++++++++++++++---- glib/examples/example-signal-recipient.c | 9 +- test/glib/test-dbus-glib.c | 324 ++++++++++++- test/glib/test-service-glib.c | 9 + test/glib/test-service-glib.xml | 6 + tools/dbus-send.c | 3 +- 8 files changed, 1076 insertions(+), 129 deletions(-) diff --git a/ChangeLog b/ChangeLog index 48ddf6b3..e67e5ee4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,63 @@ +2005-06-29 Colin Walters + + * glib/dbus-gproxy.c (struct _DBusGProxy): Add new member + name_call for keeping track of any outgoing GetNameOwner call. + Also add for_owner and associated. + (struct _DBusGProxyManager): Add owner_names, which is hash table + that maps a base name to a list of names it owns (that we're + interested in). Add pending_nameowner_calls which is a list of + all outstanding GetNameOwner; avoids us having to iterate over + every proxy. Add unassociated_proxies which keeps track of name + proxies with no associated name owner. + (dbus_g_proxy_manager_unref): Destroy owner_names. + (struct DBusGProxyNameOwnerInfo): New struct for keeping track of + name refcounts. + (find_name_in_info, name_owner_foreach) + (dbus_g_proxy_manager_lookup_name_owner, insert_nameinfo) + (dbus_g_proxy_manager_monitor_name_owner) + (dbus_g_proxy_manager_unmonitor_name_owner) + (unassociate_proxies, dbus_g_proxy_manager_replace_name_owner): + New functions; they manipulate the owner_names mapping. + (got_name_owner_cb): New function. + (get_name_owner): New function, extracted from + dbus_g_proxy_new_for_name_owner. + (dbus_g_proxy_manager_register): For now we need to keep track of + all NameOwnerChanged. Also if the proxy is for a name, if we + don't already know the name owner, queue a new GetNameOwner + request and add it to our list of unassociated proxies. Otherwise + inc the refcount. + (dbus_g_proxy_manager_unregister): If this proxy is for a name, + cancel any pending GetNameOwner call, etc. + (dbus_g_proxy_manager_filter): Handle NameOwnerChanged. Also use + the owner_names mapping to look up the current names for the + signal source, and dispatch to any proxies for that name. + (dbus_g_proxy_new): Initialize new members. + (dbus_g_proxy_new_for_name): Delete unused proxy variable. + (dbus_g_proxy_new_for_name_owner): Use get_name_owner. + (dbus_g_pending_call_end_valist): New function, extracted from + dbus_g_proxy_end_call_internal. Useful when we don't have a proxy + but want to use the GLib infrastructure. Also note how many + arguments in reply were over. + (dbus_g_pending_call_end): New function, just call + dbus_g_pending_call_end_valist. + (dbus_g_proxy_end_call_internal): Just call + dbus_g_pending_call_end_valist. + + * glib/dbus-gobject.c (_dbus_gobject_lookup_marshaller): Fix lookup + of builtin marshaller for STRING_STRING_STRING. + + * test/glib/test-dbus-glib.c: + * test/glib/test-service-glib.c: + * test/glib/test-service-glib.xml: + Extend tests to cover name proxies, destruction of owner proxies, + etc. + + * glib/examples/example-signal-recipient.c + (dbus_g_proxy_new_for_name_owner): Create a name proxy. + + * tools/dbus-send.c (main): Print D-BUS error name in addition + to message. + 2005-06-28 John (J5) Palmieri * python/dbus_bindings.pyx.in (cunregister_function_handler, diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index 93c65a2f..2bebf5eb 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -1484,13 +1484,13 @@ _dbus_gobject_lookup_marshaller (GType rettype, break; } } - } - else if (n_params == 3 - && params[0] == G_TYPE_STRING - && params[1] == G_TYPE_STRING - && params[2] == G_TYPE_STRING) - { - ret = _dbus_g_marshal_NONE__STRING_STRING_STRING; + else if (n_params == 3 + && params[0] == G_TYPE_STRING + && params[1] == G_TYPE_STRING + && params[2] == G_TYPE_STRING) + { + ret = _dbus_g_marshal_NONE__STRING_STRING_STRING; + } } } diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 3b13ff23..9ea4c16c 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -56,6 +56,10 @@ struct _DBusGProxy char *path; /**< Path messages go to or NULL */ char *interface; /**< Interface messages go to or NULL */ + DBusGPendingCall *name_call;/**< Pending call to retrieve name owner */ + guint for_owner : 1; /**< Whether or not this proxy is for a name owner */ + guint associated : 1; /**< Whether or not this proxy is associated (for name proxies) */ + GData *signal_signatures; /**< D-BUS signatures for each signal */ }; @@ -75,6 +79,13 @@ static void dbus_g_proxy_destroy (DBusGProxy *proxy); static void dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy, DBusMessage *message); +static gboolean dbus_g_pending_call_end (DBusGConnection *connection, + DBusGProxy *proxycon, + DBusGPendingCall *pending, + GError **error, + GType first_arg_type, + ...); + /** * A list of proxies with a given name+path+interface, used to * route incoming signals. @@ -104,7 +115,17 @@ struct _DBusGProxyManager GHashTable *proxy_lists; /**< Hash used to route incoming signals * and iterate over proxies */ - + GHashTable *owner_names; /**< Hash to keep track of mapping from + * base name -> [name,name,...] for proxies which + * are for names. + */ + GSList *pending_nameowner_calls; /**< List to keep track of pending + * GetNameOwner calls + */ + GSList *unassociated_proxies; /**< List of name proxies for which + * there was no result for + * GetNameOwner + */ }; static DBusGProxyManager *dbus_g_proxy_manager_ref (DBusGProxyManager *manager); @@ -203,7 +224,22 @@ dbus_g_proxy_manager_unref (DBusGProxyManager *manager) g_hash_table_destroy (manager->proxy_lists); manager->proxy_lists = NULL; + } + + if (manager->owner_names) + { + /* Since we destroyed all proxies, none can be tracking + * name owners + */ + g_assert (g_hash_table_size (manager->owner_names) == 0); + + g_hash_table_destroy (manager->owner_names); + manager->owner_names = NULL; + } + + g_assert (manager->pending_nameowner_calls == NULL); + g_assert (manager->unassociated_proxies == NULL); g_static_mutex_free (&manager->lock); @@ -412,6 +448,389 @@ g_proxy_get_match_rule (DBusGProxy *proxy) proxy->path, proxy->interface); } +typedef struct +{ + char *name; + guint refcount; +} DBusGProxyNameOwnerInfo; + +static gint +find_name_in_info (gconstpointer a, gconstpointer b) +{ + const DBusGProxyNameOwnerInfo *info = a; + const char *name = b; + + return strcmp (info->name, name); +} + +typedef struct +{ + const char *name; + const char *owner; + DBusGProxyNameOwnerInfo *info; +} DBusGProxyNameOwnerForeachData; + +static void +name_owner_foreach (gpointer key, gpointer val, gpointer data) +{ + const char *owner; + DBusGProxyNameOwnerForeachData *foreach_data; + GSList *names; + GSList *link; + + owner = key; + names = val; + foreach_data = data; + + if (foreach_data->owner != NULL) + return; + + g_assert (foreach_data->info == NULL); + + link = g_slist_find_custom (names, foreach_data->name, find_name_in_info); + if (link) + { + foreach_data->owner = owner; + foreach_data->info = link->data; + } +} + +static gboolean +dbus_g_proxy_manager_lookup_name_owner (DBusGProxyManager *manager, + const char *name, + DBusGProxyNameOwnerInfo **info, + const char **owner) +{ + DBusGProxyNameOwnerForeachData foreach_data; + + foreach_data.name = name; + foreach_data.owner = NULL; + foreach_data.info = NULL; + + g_hash_table_foreach (manager->owner_names, name_owner_foreach, &foreach_data); + + *info = foreach_data.info; + *owner = foreach_data.owner; + return *info != NULL; +} + +static void +insert_nameinfo (DBusGProxyManager *manager, + const char *owner, + DBusGProxyNameOwnerInfo *info) +{ + GSList *names; + gboolean insert; + + names = g_hash_table_lookup (manager->owner_names, owner); + + /* Only need to g_hash_table_insert the first time */ + insert = (names == NULL); + + names = g_slist_append (names, info); + + if (insert) + g_hash_table_insert (manager->owner_names, g_strdup (owner), names); +} + +static void +dbus_g_proxy_manager_monitor_name_owner (DBusGProxyManager *manager, + const char *owner, + const char *name) +{ + GSList *names; + GSList *link; + DBusGProxyNameOwnerInfo *nameinfo; + + names = g_hash_table_lookup (manager->owner_names, owner); + link = g_slist_find_custom (names, name, find_name_in_info); + + if (!link) + { + nameinfo = g_new0 (DBusGProxyNameOwnerInfo, 1); + nameinfo->name = g_strdup (name); + nameinfo->refcount = 1; + + insert_nameinfo (manager, owner, nameinfo); + } + else + { + nameinfo = link->data; + nameinfo->refcount++; + } +} + +static void +dbus_g_proxy_manager_unmonitor_name_owner (DBusGProxyManager *manager, + const char *name) +{ + DBusGProxyNameOwnerInfo *info; + const char *owner; + gboolean ret; + + ret = dbus_g_proxy_manager_lookup_name_owner (manager, name, &info, &owner); + g_assert (ret); + g_assert (info != NULL); + g_assert (owner != NULL); + + info->refcount--; + if (info->refcount == 0) + { + GSList *names; + GSList *link; + + names = g_hash_table_lookup (manager->owner_names, owner); + link = g_slist_find_custom (names, name, find_name_in_info); + names = g_slist_delete_link (names, link); + if (names != NULL) + g_hash_table_insert (manager->owner_names, g_strdup (owner), names); + else + g_hash_table_remove (manager->owner_names, owner); + + g_free (info->name); + g_free (info); + } +} + +typedef struct +{ + const char *name; + GSList *destroyed; +} DBusGProxyUnassociateData; + +static void +unassociate_proxies (gpointer key, gpointer val, gpointer user_data) +{ + const char *tri; + DBusGProxyList *list; + const char *name; + GSList *tmp; + DBusGProxyUnassociateData *data; + + tri = key; + list = val; + data = user_data; + name = data->name; + + for (tmp = list->proxies; tmp; tmp = tmp->next) + { + DBusGProxy *proxy = DBUS_G_PROXY (tmp->data); + DBusGProxyManager *manager; + + manager = proxy->manager; + + if (!strcmp (proxy->name, name)) + { + if (!proxy->for_owner) + { + g_assert (proxy->associated); + g_assert (proxy->name_call == NULL); + + proxy->associated = FALSE; + manager->unassociated_proxies = g_slist_prepend (manager->unassociated_proxies, proxy); + } + else + { + data->destroyed = g_slist_prepend (data->destroyed, proxy); + } + } + } +} + +static void +dbus_g_proxy_manager_replace_name_owner (DBusGProxyManager *manager, + const char *name, + const char *prev_owner, + const char *new_owner) +{ + GSList *names; + + if (prev_owner[0] == '\0') + { + GSList *tmp; + GSList *removed; + + /* We have a new service, look at unassociated proxies */ + + removed = NULL; + + for (tmp = manager->unassociated_proxies; tmp ; tmp = tmp->next) + { + DBusGProxy *proxy; + + proxy = tmp->data; + + if (!strcmp (proxy->name, name)) + { + removed = g_slist_prepend (removed, tmp); + + dbus_g_proxy_manager_monitor_name_owner (manager, new_owner, name); + proxy->associated = TRUE; + } + } + + for (tmp = removed; tmp; tmp = tmp->next) + manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, tmp->data); + g_slist_free (removed); + } + else + { + DBusGProxyNameOwnerInfo *info; + GSList *link; + + /* Name owner changed or deleted */ + + names = g_hash_table_lookup (manager->owner_names, prev_owner); + + link = g_slist_find_custom (names, name, find_name_in_info); + + info = NULL; + if (link != NULL) + { + info = link->data; + + names = g_slist_delete_link (names, link); + + if (names == NULL) + g_hash_table_remove (manager->owner_names, prev_owner); + } + + if (new_owner[0] == '\0') + { + DBusGProxyUnassociateData data; + GSList *tmp; + + data.name = name; + data.destroyed = NULL; + + /* A service went away, we need to unassociate proxies */ + g_hash_table_foreach (manager->proxy_lists, + unassociate_proxies, &data); + + UNLOCK_MANAGER (manager); + + for (tmp = data.destroyed; tmp; tmp = tmp->next) + dbus_g_proxy_destroy (tmp->data); + g_slist_free (data.destroyed); + + LOCK_MANAGER (manager); + } + else + { + insert_nameinfo (manager, new_owner, info); + } + } +} + +static void +got_name_owner_cb (DBusGPendingCall *pending, + void *user_data) +{ + DBusGProxy *proxy; + GError *error; + char *owner; + GSList *link; + + proxy = user_data; + error = NULL; + owner = NULL; + + LOCK_MANAGER (proxy->manager); + + link = g_slist_find (proxy->manager->pending_nameowner_calls, pending); + g_assert (link != NULL); + + if (!dbus_g_pending_call_end (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection), + NULL, + pending, + &error, + G_TYPE_STRING, &owner, + G_TYPE_INVALID)) + { + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER) + { + proxy->manager->unassociated_proxies = g_slist_prepend (proxy->manager->unassociated_proxies, proxy); + } + else + g_warning ("Couldn't get name owner (%s): %s", + dbus_g_error_get_name (error), + error->message); + + g_clear_error (&error); + goto out; + } + else + { + dbus_g_proxy_manager_monitor_name_owner (proxy->manager, owner, proxy->name); + proxy->associated = TRUE; + } + + out: + proxy->name_call = NULL; + proxy->manager->pending_nameowner_calls = g_slist_delete_link (proxy->manager->pending_nameowner_calls, link); + UNLOCK_MANAGER (proxy->manager); + g_free (owner); +} + +static char * +get_name_owner (DBusConnection *connection, + const char *name, + GError **error) +{ + DBusError derror; + DBusMessage *request, *reply; + char *base_name; + + dbus_error_init (&derror); + + base_name = NULL; + reply = NULL; + + request = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner"); + if (request == NULL) + g_error ("Out of memory"); + + if (!dbus_message_append_args (request, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID)) + g_error ("Out of memory"); + + reply = + dbus_connection_send_with_reply_and_block (connection, + request, + 2000, &derror); + if (reply == NULL) + goto error; + + if (dbus_set_error_from_message (&derror, reply)) + goto error; + + if (!dbus_message_get_args (reply, &derror, + DBUS_TYPE_STRING, &base_name, + DBUS_TYPE_INVALID)) + goto error; + + base_name = g_strdup (base_name); + goto out; + + error: + g_assert (dbus_error_is_set (&derror)); + dbus_g_error_set (error, derror.name, derror.message); + dbus_error_free (&derror); + + out: + if (request) + dbus_message_unref (request); + if (reply) + dbus_message_unref (reply); + + return base_name; +} + + static void dbus_g_proxy_manager_register (DBusGProxyManager *manager, DBusGProxy *proxy) @@ -422,11 +841,26 @@ dbus_g_proxy_manager_register (DBusGProxyManager *manager, if (manager->proxy_lists == NULL) { + g_assert (manager->owner_names == NULL); + list = NULL; manager->proxy_lists = g_hash_table_new_full (tristring_hash, tristring_equal, NULL, (GFreeFunc) g_proxy_list_free); + manager->owner_names = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + NULL); + /* FIXME - for now we listen for all NameOwnerChanged; once + * Anders' detail patch lands we should add individual rules + */ + dbus_bus_add_match (manager->connection, + "type='signal',sender='" DBUS_SERVICE_DBUS + "',path='" DBUS_PATH_DBUS + "',interface='" DBUS_INTERFACE_DBUS + "',member='NameOwnerChanged'", + NULL); } else { @@ -469,6 +903,61 @@ dbus_g_proxy_manager_register (DBusGProxyManager *manager, g_assert (g_slist_find (list->proxies, proxy) == NULL); list->proxies = g_slist_prepend (list->proxies, proxy); + + if (!proxy->for_owner) + { + const char *owner; + DBusGProxyNameOwnerInfo *info; + + if (!dbus_g_proxy_manager_lookup_name_owner (manager, proxy->name, &info, &owner)) + { + DBusPendingCall *pending; + DBusGPendingCall *gpending; + DBusMessage *request, *reply; + + g_assert (owner == NULL); + + reply = NULL; + + request = dbus_message_new_method_call (DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner"); + if (request == NULL) + g_error ("Out of memory"); + + if (!dbus_message_append_args (request, + DBUS_TYPE_STRING, &(proxy->name), + DBUS_TYPE_INVALID)) + g_error ("Out of memory"); + + if (!dbus_connection_send_with_reply (manager->connection, + request, + &pending, + -1)) + g_error ("Out of memory"); + g_assert (pending != NULL); + + gpending = DBUS_G_PENDING_CALL_FROM_PENDING_CALL (pending); + + /* It's safe to keep a reference to proxy here; + * when the proxy is unreffed we cancel the call + */ + dbus_g_pending_call_set_notify (gpending, + got_name_owner_cb, + proxy, + NULL); + + proxy->associated = FALSE; + proxy->name_call = gpending; + manager->pending_nameowner_calls = g_slist_prepend (manager->pending_nameowner_calls, gpending); + } + else + { + info->refcount++; + proxy->associated = TRUE; + } + } UNLOCK_MANAGER (manager); } @@ -508,6 +997,37 @@ dbus_g_proxy_manager_unregister (DBusGProxyManager *manager, g_assert (g_slist_find (list->proxies, proxy) == NULL); + if (!proxy->for_owner) + { + if (!proxy->associated) + { + GSList *link; + + if (proxy->name_call != NULL) + { + link = g_slist_find (manager->pending_nameowner_calls, proxy->name_call); + g_assert (link != NULL); + + dbus_g_pending_call_cancel (proxy->name_call); + + manager->pending_nameowner_calls = g_slist_delete_link (manager->pending_nameowner_calls, link); + } + else + { + link = g_slist_find (manager->unassociated_proxies, proxy); + g_assert (link != NULL); + + manager->unassociated_proxies = g_slist_delete_link (manager->unassociated_proxies, link); + } + } + else + { + g_assert (proxy->name_call == NULL); + + dbus_g_proxy_manager_unmonitor_name_owner (manager, proxy->name); + } + } + if (list->proxies == NULL) { g_hash_table_remove (manager->proxy_lists, @@ -620,9 +1140,45 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, else { char *tri; - DBusGProxyList *list; + GSList *full_list; + GSList *owned_names; + GSList *tmp; + const char *sender; + + /* First we handle NameOwnerChanged internally */ + if (dbus_message_is_signal (message, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged")) + { + const char *name; + const char *prev_owner; + const char *new_owner; + DBusError derr; + + dbus_error_init (&derr); + if (!dbus_message_get_args (message, + &derr, + DBUS_TYPE_STRING, + &name, + DBUS_TYPE_STRING, + &prev_owner, + DBUS_TYPE_STRING, + &new_owner, + DBUS_TYPE_INVALID)) + { + /* Ignore this error */ + dbus_error_free (&derr); + } + else if (manager->owner_names != NULL) + { + dbus_g_proxy_manager_replace_name_owner (manager, name, prev_owner, new_owner); + } + } + + sender = dbus_message_get_sender (message); /* dbus spec requires these, libdbus validates */ + g_assert (sender != NULL); g_assert (dbus_message_get_path (message) != NULL); g_assert (dbus_message_get_interface (message) != NULL); g_assert (dbus_message_get_member (message) != NULL); @@ -630,9 +1186,38 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, tri = tristring_from_message (message); if (manager->proxy_lists) - list = g_hash_table_lookup (manager->proxy_lists, tri); + { + DBusGProxyList *owner_list; + owner_list = g_hash_table_lookup (manager->proxy_lists, tri); + if (owner_list) + full_list = g_slist_copy (owner_list->proxies); + else + full_list = NULL; + } else - list = NULL; + full_list = NULL; + + g_free (tri); + + if (manager->owner_names) + { + owned_names = g_hash_table_lookup (manager->owner_names, sender); + for (tmp = owned_names; tmp; tmp = tmp->next) + { + DBusGProxyList *owner_list; + DBusGProxyNameOwnerInfo *nameinfo; + + nameinfo = tmp->data; + g_assert (nameinfo->refcount > 0); + tri = tristring_alloc_from_strings (0, nameinfo->name, + dbus_message_get_path (message), + dbus_message_get_interface (message)); + + owner_list = g_hash_table_lookup (manager->proxy_lists, tri); + full_list = g_slist_concat (full_list, g_slist_copy (owner_list->proxies)); + g_free (tri); + } + } #if 0 g_print ("proxy got %s,%s,%s = list %p\n", @@ -642,35 +1227,22 @@ dbus_g_proxy_manager_filter (DBusConnection *connection, list); #endif - g_free (tri); - /* Emit the signal */ - if (list != NULL) - { - GSList *tmp; - GSList *copy; - - copy = g_slist_copy (list->proxies); - g_slist_foreach (copy, (GFunc) g_object_ref, NULL); - - tmp = copy; - while (tmp != NULL) - { - DBusGProxy *proxy; - - proxy = DBUS_G_PROXY (tmp->data); - - UNLOCK_MANAGER (manager); - dbus_g_proxy_emit_remote_signal (proxy, message); - g_object_unref (G_OBJECT (proxy)); - LOCK_MANAGER (manager); - - tmp = tmp->next; - } - - g_slist_free (copy); - } + g_slist_foreach (full_list, (GFunc) g_object_ref, NULL); + + for (tmp = full_list; tmp; tmp = tmp->next) + { + DBusGProxy *proxy; + + proxy = DBUS_G_PROXY (tmp->data); + + UNLOCK_MANAGER (manager); + dbus_g_proxy_emit_remote_signal (proxy, message); + g_object_unref (G_OBJECT (proxy)); + LOCK_MANAGER (manager); + } + g_slist_free (full_list); } UNLOCK_MANAGER (manager); @@ -887,7 +1459,7 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy, GQuark q; g_return_if_fail (!DBUS_G_PROXY_DESTROYED (proxy)); - + interface = dbus_message_get_interface (message); signal = dbus_message_get_member (message); @@ -1004,6 +1576,10 @@ dbus_g_proxy_new (DBusGConnection *connection, proxy->path = g_strdup (path_name); proxy->interface = g_strdup (interface_name); + proxy->for_owner = (proxy->name[0] == ':'); + proxy->name_call = NULL; + proxy->associated = FALSE; + dbus_g_proxy_manager_register (proxy->manager, proxy); return proxy; @@ -1041,17 +1617,13 @@ dbus_g_proxy_new_for_name (DBusGConnection *connection, const char *path_name, const char *interface_name) { - DBusGProxy *proxy; - g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (path_name != NULL, NULL); g_return_val_if_fail (interface_name != NULL, NULL); - - proxy = dbus_g_proxy_new (connection, name, - path_name, interface_name); - return proxy; + return dbus_g_proxy_new (connection, name, + path_name, interface_name); } /** @@ -1085,65 +1657,19 @@ dbus_g_proxy_new_for_name_owner (DBusGConnection *connection, GError **error) { DBusGProxy *proxy; - DBusMessage *request, *reply; - DBusError derror; - const char *unique_name; - + char *unique_name; + g_return_val_if_fail (connection != NULL, NULL); g_return_val_if_fail (name != NULL, NULL); g_return_val_if_fail (path_name != NULL, NULL); g_return_val_if_fail (interface_name != NULL, NULL); - dbus_error_init (&derror); - - proxy = NULL; - unique_name = NULL; - reply = NULL; - - request = dbus_message_new_method_call (DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetNameOwner"); - if (request == NULL) - g_error ("Out of memory"); - - if (! dbus_message_append_args (request, - DBUS_TYPE_STRING, &name, - DBUS_TYPE_INVALID)) - g_error ("Out of memory"); - - reply = - dbus_connection_send_with_reply_and_block (DBUS_CONNECTION_FROM_G_CONNECTION (connection), - request, - 2000, &derror); - if (reply == NULL) - goto error; - - if (dbus_set_error_from_message (&derror, reply)) - goto error; - - if (! dbus_message_get_args (reply, &derror, - DBUS_TYPE_STRING, &unique_name, - DBUS_TYPE_INVALID)) - goto error; - + if (!(unique_name = get_name_owner (DBUS_CONNECTION_FROM_G_CONNECTION (connection), name, error))) + return NULL; proxy = dbus_g_proxy_new (connection, unique_name, - path_name, interface_name); - - goto out; - - error: - g_assert (dbus_error_is_set (&derror)); - dbus_g_error_set (error, derror.name, derror.message); - dbus_error_free (&derror); - - out: - if (request) - dbus_message_unref (request); - if (reply) - dbus_message_unref (reply); - + path_name, interface_name); + g_free (unique_name); return proxy; } @@ -1356,16 +1882,18 @@ dbus_g_proxy_begin_call_internal (DBusGProxy *proxy, } static gboolean -dbus_g_proxy_end_call_internal (DBusGProxy *proxy, - DBusGPendingCall *pending, - GError **error, - GType first_arg_type, - va_list args) +dbus_g_pending_call_end_valist (DBusGConnection *connection, + DBusGProxy *proxycon, + DBusGPendingCall *pending, + GError **error, + GType first_arg_type, + va_list args) { DBusMessage *reply; DBusMessageIter msgiter; DBusError derror; va_list args_unwind; + guint over; int n_retvals_processed; gboolean ret; GType valtype; @@ -1373,6 +1901,7 @@ dbus_g_proxy_end_call_internal (DBusGProxy *proxy, reply = NULL; ret = FALSE; n_retvals_processed = 0; + over = 0; dbus_pending_call_block (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending)); reply = dbus_pending_call_steal_reply (DBUS_PENDING_CALL_FROM_G_PENDING_CALL (pending)); @@ -1393,15 +1922,18 @@ dbus_g_proxy_end_call_internal (DBusGProxy *proxy, GValue gvalue = { 0, }; DBusGValueMarshalCtx context; - context.gconnection = DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection); - context.proxy = proxy; + context.gconnection = connection; + context.proxy = proxycon; arg_type = dbus_message_iter_get_arg_type (&msgiter); if (arg_type == DBUS_TYPE_INVALID) - g_set_error (error, DBUS_GERROR, - DBUS_GERROR_INVALID_ARGS, - _("Too few arguments in reply")); + { + g_set_error (error, DBUS_GERROR, + DBUS_GERROR_INVALID_ARGS, + _("Too few arguments in reply")); + goto out; + } return_storage = va_arg (args, gpointer); if (return_storage == NULL) @@ -1459,11 +1991,19 @@ dbus_g_proxy_end_call_internal (DBusGProxy *proxy, dbus_message_iter_next (&msgiter); valtype = va_arg (args, GType); } - if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID) + + while (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID) + { + over++; + dbus_message_iter_next (&msgiter); + } + + if (over > 0) { g_set_error (error, DBUS_GERROR, DBUS_GERROR_INVALID_ARGS, - _("Too many arguments in reply")); + _("Too many arguments in reply; expected %d, got %d"), + n_retvals_processed, over); goto out; } break; @@ -1507,6 +2047,42 @@ dbus_g_proxy_end_call_internal (DBusGProxy *proxy, return ret; } +static gboolean +dbus_g_pending_call_end (DBusGConnection *connection, + DBusGProxy *proxycon, + DBusGPendingCall *pending, + GError **error, + GType first_arg_type, + ...) +{ + va_list args; + gboolean ret; + + va_start (args, first_arg_type); + + ret = dbus_g_pending_call_end_valist (connection, proxycon, pending, + error, first_arg_type, args); + + va_end (args); + + return ret; +} + +static gboolean +dbus_g_proxy_end_call_internal (DBusGProxy *proxy, + DBusGPendingCall *pending, + GError **error, + GType first_arg_type, + va_list args) +{ + return dbus_g_pending_call_end_valist (DBUS_G_CONNECTION_FROM_CONNECTION (proxy->manager->connection), + proxy, + pending, + error, + first_arg_type, + args); +} + /** * Invokes a method on a remote interface. This function does not diff --git a/glib/examples/example-signal-recipient.c b/glib/examples/example-signal-recipient.c index 30fa1502..86ba4c77 100644 --- a/glib/examples/example-signal-recipient.c +++ b/glib/examples/example-signal-recipient.c @@ -60,11 +60,10 @@ main (int argc, char **argv) /* We use _for_name_owner in order to track this particular service * instance, which lets us receive signals. */ - remote_object = dbus_g_proxy_new_for_name_owner (bus, - "org.designfu.TestService", - "/org/designfu/TestService/object", - "org.designfu.TestService", - &error); + remote_object = dbus_g_proxy_new_for_name (bus, + "org.designfu.TestService", + "/org/designfu/TestService/object", + "org.designfu.TestService"); if (!remote_object) lose_gerror ("Failed to get name owner", error); diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index 59284913..178d819f 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -6,24 +6,69 @@ #include "test-service-glib-bindings.h" #include #include +#include #include #include "my-object-marshal.h" static GMainLoop *loop = NULL; +static const char *await_terminating_service = NULL; static int n_times_foo_received = 0; static int n_times_frobnicate_received = 0; +static int n_times_frobnicate_received_2 = 0; static int n_times_sig0_received = 0; static int n_times_sig1_received = 0; static int n_times_sig2_received = 0; static guint exit_timeout = 0; +static gboolean proxy_destroyed = FALSE; +static gboolean proxy_destroy_and_nameowner = FALSE; +static gboolean proxy_destroy_and_nameowner_complete = FALSE; static gboolean timed_exit (gpointer loop) { + g_print ("timed exit!\n"); g_main_loop_quit (loop); return TRUE; } +static void +proxy_destroyed_cb (DBusGProxy *proxy, gpointer user_data) +{ + proxy_destroyed = TRUE; + if (proxy_destroy_and_nameowner && !proxy_destroy_and_nameowner_complete && await_terminating_service == NULL) + { + g_main_loop_quit (loop); + proxy_destroy_and_nameowner_complete = TRUE; + } +} + +static void +name_owner_changed (DBusGProxy *proxy, + const char *name, + const char *prev_owner, + const char *new_owner, + gpointer user_data) +{ + g_print ("(signal NameOwnerChanged) name owner changed for %s from %s to %s\n", + name, prev_owner, new_owner); + if (await_terminating_service && + !strcmp (name, await_terminating_service) + && !strcmp ("", new_owner)) + { + g_print ("Caught expected ownership loss for %s\n", name); + await_terminating_service = NULL; + if (proxy_destroy_and_nameowner && !proxy_destroy_and_nameowner_complete && proxy_destroyed) + { + g_main_loop_quit (loop); + proxy_destroy_and_nameowner_complete = TRUE; + } + else if (!proxy_destroy_and_nameowner) + { + g_main_loop_quit (loop); + } + } +} + static void foo_signal_handler (DBusGProxy *proxy, double d, @@ -31,6 +76,8 @@ foo_signal_handler (DBusGProxy *proxy, { n_times_foo_received += 1; + g_print ("Got Foo signal\n"); + g_main_loop_quit (loop); g_source_remove (exit_timeout); } @@ -43,11 +90,23 @@ frobnicate_signal_handler (DBusGProxy *proxy, n_times_frobnicate_received += 1; g_assert (val == 42); + g_print ("Got Frobnicate signal\n"); g_main_loop_quit (loop); g_source_remove (exit_timeout); } +static void +frobnicate_signal_handler_2 (DBusGProxy *proxy, + int val, + void *user_data) +{ + n_times_frobnicate_received_2 += 1; + + g_assert (val == 42); + g_print ("Got Frobnicate signal (again)\n"); +} + static void sig0_signal_handler (DBusGProxy *proxy, const char *str0, @@ -63,6 +122,8 @@ sig0_signal_handler (DBusGProxy *proxy, g_assert (!strcmp (str1, "moo")); + g_print ("Got Sig0 signal\n"); + g_main_loop_quit (loop); g_source_remove (exit_timeout); } @@ -81,6 +142,8 @@ sig1_signal_handler (DBusGProxy *proxy, g_assert (!strcmp (g_value_get_string (value), "bar")); + g_print ("Got Sig1 signal\n"); + g_main_loop_quit (loop); g_source_remove (exit_timeout); } @@ -99,6 +162,8 @@ sig2_signal_handler (DBusGProxy *proxy, g_assert (g_hash_table_lookup (table, "bar") != NULL); g_assert (!strcmp (g_hash_table_lookup (table, "bar"), "foo")); + g_print ("Got Sig2 signal\n"); + g_main_loop_quit (loop); g_source_remove (exit_timeout); } @@ -124,7 +189,22 @@ lose (const char *str, ...) static void lose_gerror (const char *prefix, GError *error) { - lose ("%s: %s", prefix, error->message); + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_REMOTE_EXCEPTION) + lose ("%s (%s): %s", prefix, dbus_g_error_get_name (error), + error->message); + else + lose ("%s: %s", prefix, error->message); +} + +static void +run_mainloop (void) +{ + GMainContext *ctx; + + ctx = g_main_loop_get_context (loop); + + while (g_main_context_pending (ctx)) + g_main_context_iteration (ctx, FALSE); } int @@ -134,16 +214,14 @@ main (int argc, char **argv) GError *error; DBusGProxy *driver; DBusGProxy *proxy; + DBusGProxy *proxy2; DBusGPendingCall *call; char **name_list; guint name_list_len; guint i; guint32 result; - const char *v_STRING; char *v_STRING_2; - guint32 v_UINT32; guint32 v_UINT32_2; - double v_DOUBLE; double v_DOUBLE_2; g_type_init (); @@ -166,10 +244,22 @@ main (int argc, char **argv) /* Create a proxy object for the "bus driver" */ driver = dbus_g_proxy_new_for_name (connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS); - + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS); + + dbus_g_proxy_add_signal (driver, + "NameOwnerChanged", + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_STRING, + G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (driver, + "NameOwnerChanged", + G_CALLBACK (name_owner_changed), + NULL, + NULL); /* Call ListNames method */ call = dbus_g_proxy_begin_call (driver, "ListNames", G_TYPE_INVALID); @@ -193,6 +283,7 @@ main (int argc, char **argv) g_strfreev (name_list); + g_print ("calling ThisMethodDoesNotExist\n"); /* Test handling of unknown method */ call = dbus_g_proxy_begin_call (driver, "ThisMethodDoesNotExist", G_TYPE_STRING, @@ -208,8 +299,11 @@ main (int argc, char **argv) g_print ("Got EXPECTED error from calling unknown method: %s\n", error->message); g_error_free (error); + + run_mainloop (); /* Activate a service */ + g_print ("Activating echo service\n"); call = dbus_g_proxy_begin_call (driver, "StartServiceByName", G_TYPE_STRING, "org.freedesktop.DBus.TestSuiteEchoService", @@ -226,6 +320,7 @@ main (int argc, char **argv) g_print ("Starting echo service result = 0x%x\n", result); /* Activate a service again */ + g_print ("Activating echo service again\n"); call = dbus_g_proxy_begin_call (driver, "StartServiceByName", G_TYPE_STRING, "org.freedesktop.DBus.TestSuiteEchoService", @@ -243,6 +338,7 @@ main (int argc, char **argv) /* Talk to the new service */ + g_print ("Creating proxy for echo service\n"); proxy = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.TestSuiteEchoService", "/org/freedesktop/TestSuite", @@ -252,6 +348,9 @@ main (int argc, char **argv) if (proxy == NULL) lose_gerror ("Failed to create proxy for name owner", error); + run_mainloop (); + + g_print ("Calling Echo\n"); call = dbus_g_proxy_begin_call (proxy, "Echo", G_TYPE_STRING, "my string hello", @@ -268,6 +367,7 @@ main (int argc, char **argv) /* Test oneway call and signal handling */ + g_print ("Testing Foo emission\n"); dbus_g_proxy_add_signal (proxy, "Foo", G_TYPE_DOUBLE, G_TYPE_INVALID); dbus_g_proxy_connect_signal (proxy, "Foo", @@ -305,6 +405,8 @@ main (int argc, char **argv) g_object_unref (G_OBJECT (proxy)); + run_mainloop (); + proxy = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.TestSuiteGLibService", "/org/freedesktop/DBus/Tests/MyTestObject", @@ -314,14 +416,14 @@ main (int argc, char **argv) if (proxy == NULL) lose_gerror ("Failed to create proxy for name owner", error); - g_print ("Beginning method calls\n"); - + g_print ("Calling DoNothing\n"); call = dbus_g_proxy_begin_call (proxy, "DoNothing", G_TYPE_INVALID); error = NULL; if (!dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID)) lose_gerror ("Failed to complete DoNothing call", error); + g_print ("Calling Increment\n"); error = NULL; if (!dbus_g_proxy_call (proxy, "Increment", &error, G_TYPE_UINT, 42, @@ -333,6 +435,7 @@ main (int argc, char **argv) if (v_UINT32_2 != 43) lose ("Increment call returned %d, should be 43", v_UINT32_2); + g_print ("Calling ThrowError\n"); call = dbus_g_proxy_begin_call (proxy, "ThrowError", G_TYPE_INVALID); error = NULL; if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID) != FALSE) @@ -343,6 +446,7 @@ main (int argc, char **argv) g_print ("ThrowError failed (as expected) returned error: %s\n", error->message); g_clear_error (&error); + g_print ("Calling Uppercase\n"); call = dbus_g_proxy_begin_call (proxy, "Uppercase", G_TYPE_STRING, "foobar", G_TYPE_INVALID); @@ -355,9 +459,9 @@ main (int argc, char **argv) lose ("Uppercase call returned unexpected string %s", v_STRING_2); g_free (v_STRING_2); - v_STRING = "bazwhee"; - v_UINT32 = 26; - v_DOUBLE = G_PI; + run_mainloop (); + + g_print ("Calling ManyArgs\n"); call = dbus_g_proxy_begin_call (proxy, "ManyArgs", G_TYPE_UINT, 26, G_TYPE_STRING, "bazwhee", @@ -375,27 +479,32 @@ main (int argc, char **argv) lose ("ManyArgs call returned unexpected string %s", v_STRING_2); g_free (v_STRING_2); + g_print ("Calling (wrapped) do_nothing\n"); if (!org_freedesktop_DBus_Tests_MyObject_do_nothing (proxy, &error)) lose_gerror ("Failed to complete (wrapped) DoNothing call", error); + g_print ("Calling (wrapped) increment\n"); if (!org_freedesktop_DBus_Tests_MyObject_increment (proxy, 42, &v_UINT32_2, &error)) lose_gerror ("Failed to complete (wrapped) Increment call", error); if (v_UINT32_2 != 43) lose ("(wrapped) increment call returned %d, should be 43", v_UINT32_2); + g_print ("Calling (wrapped) throw_error\n"); if (org_freedesktop_DBus_Tests_MyObject_throw_error (proxy, &error) != FALSE) lose ("(wrapped) ThrowError call unexpectedly succeeded!"); g_print ("(wrapped) ThrowError failed (as expected) returned error: %s\n", error->message); g_clear_error (&error); + g_print ("Calling (wrapped) uppercase\n"); if (!org_freedesktop_DBus_Tests_MyObject_uppercase (proxy, "foobar", &v_STRING_2, &error)) lose_gerror ("Failed to complete (wrapped) Uppercase call", error); if (strcmp ("FOOBAR", v_STRING_2) != 0) lose ("(wrapped) Uppercase call returned unexpected string %s", v_STRING_2); g_free (v_STRING_2); + g_print ("Calling (wrapped) many_args\n"); if (!org_freedesktop_DBus_Tests_MyObject_many_args (proxy, 26, "bazwhee", G_PI, &v_DOUBLE_2, &v_STRING_2, &error)) lose_gerror ("Failed to complete (wrapped) ManyArgs call", error); @@ -416,6 +525,7 @@ main (int argc, char **argv) guint32 arg4; char *arg5; + g_print ("Calling (wrapped) many_return\n"); if (!org_freedesktop_DBus_Tests_MyObject_many_return (proxy, &arg0, &arg1, &arg2, &arg3, &arg4, &arg5, &error)) lose_gerror ("Failed to complete (wrapped) ManyReturn call", error); @@ -440,12 +550,15 @@ main (int argc, char **argv) g_free (arg5); } + run_mainloop (); + { GValue value = {0, }; g_value_init (&value, G_TYPE_STRING); g_value_set_string (&value, "foo"); + g_print ("Calling (wrapped) stringify, with string\n"); if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy, &value, &v_STRING_2, @@ -459,6 +572,7 @@ main (int argc, char **argv) g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, 42); + g_print ("Calling (wrapped) stringify, with int\n"); if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy, &value, &v_STRING_2, @@ -471,6 +585,7 @@ main (int argc, char **argv) g_value_init (&value, G_TYPE_INT); g_value_set_int (&value, 88); + g_print ("Calling (wrapped) stringify, with another int\n"); if (!org_freedesktop_DBus_Tests_MyObject_stringify (proxy, &value, NULL, @@ -478,6 +593,7 @@ main (int argc, char **argv) lose_gerror ("Failed to complete (wrapped) stringify call 3", error); g_value_unset (&value); + g_print ("Calling (wrapped) unstringify, for string\n"); if (!org_freedesktop_DBus_Tests_MyObject_unstringify (proxy, "foo", &value, @@ -491,6 +607,7 @@ main (int argc, char **argv) g_value_unset (&value); + g_print ("Calling (wrapped) unstringify, for int\n"); if (!org_freedesktop_DBus_Tests_MyObject_unstringify (proxy, "10", &value, @@ -505,6 +622,8 @@ main (int argc, char **argv) g_value_unset (&value); } + run_mainloop (); + { GArray *array; guint32 val; @@ -523,6 +642,7 @@ main (int argc, char **argv) g_array_append_val (array, val); arraylen = 0; + g_print ("Calling (wrapped) recursive1\n"); if (!org_freedesktop_DBus_Tests_MyObject_recursive1 (proxy, array, &arraylen, &error)) lose_gerror ("Failed to complete (wrapped) recursive1 call", error); @@ -534,6 +654,7 @@ main (int argc, char **argv) GArray *array = NULL; guint32 *arrayvals; + g_print ("Calling (wrapped) recursive2\n"); if (!org_freedesktop_DBus_Tests_MyObject_recursive2 (proxy, 2, &array, &error)) lose_gerror ("Failed to complete (wrapped) Recursive2 call", error); @@ -553,6 +674,8 @@ main (int argc, char **argv) g_array_free (array, TRUE); } + run_mainloop (); + { char **strs; char **strs_ret; @@ -564,6 +687,7 @@ main (int argc, char **argv) strs[3] = NULL; strs_ret = NULL; + g_print ("Calling (wrapped) many_uppercase\n"); if (!org_freedesktop_DBus_Tests_MyObject_many_uppercase (proxy, strs, &strs_ret, &error)) lose_gerror ("Failed to complete (wrapped) ManyUppercase call", error); g_assert (strs_ret != NULL); @@ -574,6 +698,7 @@ main (int argc, char **argv) if (strcmp ("HELLO", strs_ret[2]) != 0) lose ("(wrapped) ManyUppercase call returned unexpected string %s", strs_ret[2]); + g_free (strs); g_strfreev (strs_ret); } @@ -586,6 +711,7 @@ main (int argc, char **argv) g_hash_table_insert (table, "xxx", "cow!"); len = 0; + g_print ("Calling (wrapped) str_hash_len\n"); if (!org_freedesktop_DBus_Tests_MyObject_str_hash_len (proxy, table, &len, &error)) lose_gerror ("(wrapped) StrHashLen call failed", error); if (len != 13) @@ -597,6 +723,7 @@ main (int argc, char **argv) GHashTable *table; const char *val; + g_print ("Calling (wrapped) get_hash\n"); if (!org_freedesktop_DBus_Tests_MyObject_get_hash (proxy, &table, &error)) lose_gerror ("(wrapped) GetHash call failed", error); val = g_hash_table_lookup (table, "foo"); @@ -618,10 +745,13 @@ main (int argc, char **argv) g_hash_table_destroy (table); } + run_mainloop (); + { guint val; DBusGProxy *ret_proxy; + g_print ("Calling (wrapped) objpath\n"); if (!org_freedesktop_DBus_Tests_MyObject_objpath (proxy, proxy, &ret_proxy, &error)) lose_gerror ("Failed to complete (wrapped) Objpath call", error); if (strcmp ("/org/freedesktop/DBus/Tests/MyTestObject2", @@ -629,6 +759,7 @@ main (int argc, char **argv) lose ("(wrapped) objpath call returned unexpected proxy %s", dbus_g_proxy_get_path (ret_proxy)); + g_print ("Doing get/increment val tests\n"); val = 1; if (!org_freedesktop_DBus_Tests_MyObject_get_val (ret_proxy, &val, &error)) lose_gerror ("Failed to complete (wrapped) GetVal call", error); @@ -669,6 +800,7 @@ main (int argc, char **argv) g_object_unref (G_OBJECT (ret_proxy)); + g_print ("Calling objpath again\n"); ret_proxy = NULL; if (!org_freedesktop_DBus_Tests_MyObject_objpath (proxy, proxy, &ret_proxy, &error)) lose_gerror ("Failed to complete (wrapped) Objpath call 2", error); @@ -691,14 +823,18 @@ main (int argc, char **argv) lose ("(wrapped) GetValue returned invalid value %d", val); } + run_mainloop (); + /* Signal handling tests */ + g_print ("Testing signal handling\n"); dbus_g_proxy_add_signal (proxy, "Frobnicate", G_TYPE_INT, G_TYPE_INVALID); dbus_g_proxy_connect_signal (proxy, "Frobnicate", G_CALLBACK (frobnicate_signal_handler), NULL, NULL); + g_print ("Calling EmitFrobnicate\n"); if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, G_TYPE_INVALID, G_TYPE_INVALID)) lose_gerror ("Failed to complete EmitFrobnicate call", error); @@ -711,6 +847,7 @@ main (int argc, char **argv) if (n_times_frobnicate_received != 1) lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received); + g_print ("Calling EmitFrobnicate again\n"); if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, G_TYPE_INVALID, G_TYPE_INVALID)) lose_gerror ("Failed to complete EmitFrobnicate call", error); @@ -724,6 +861,9 @@ main (int argc, char **argv) g_object_unref (G_OBJECT (proxy)); + run_mainloop (); + + g_print ("Creating proxy for FooObject interface\n"); proxy = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.TestSuiteGLibService", "/org/freedesktop/DBus/Tests/MyTestObject", @@ -753,6 +893,7 @@ main (int argc, char **argv) G_CALLBACK (sig2_signal_handler), NULL, NULL); + g_print ("Calling FooObject EmitSignals\n"); dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); dbus_g_connection_flush (connection); @@ -766,6 +907,7 @@ main (int argc, char **argv) if (n_times_sig1_received != 1) lose ("Sig1 signal received %d times, should have been 1", n_times_sig1_received); + g_print ("Calling FooObject EmitSignals and EmitSignal2\n"); dbus_g_proxy_call_no_reply (proxy, "EmitSignal2", G_TYPE_INVALID); dbus_g_connection_flush (connection); @@ -775,6 +917,7 @@ main (int argc, char **argv) if (n_times_sig2_received != 1) lose ("Sig2 signal received %d times, should have been 1", n_times_sig2_received); + g_print ("Calling FooObject EmitSignals two more times\n"); dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID); @@ -792,18 +935,171 @@ main (int argc, char **argv) lose ("Sig0 signal received %d times, should have been 3", n_times_sig0_received); if (n_times_sig1_received != 3) lose ("Sig1 signal received %d times, should have been 3", n_times_sig1_received); + + /* Terminate again */ + g_print ("Terminating service\n"); + await_terminating_service = "org.freedesktop.DBus.TestSuiteGLibService"; + dbus_g_proxy_call_no_reply (proxy, "Terminate", G_TYPE_INVALID); + + proxy_destroyed = FALSE; + proxy_destroy_and_nameowner = TRUE; + proxy_destroy_and_nameowner_complete = FALSE; + + g_signal_connect (G_OBJECT (proxy), + "destroy", + G_CALLBACK (proxy_destroyed_cb), + NULL); + + dbus_g_connection_flush (connection); + exit_timeout = g_timeout_add (5000, timed_exit, loop); + g_main_loop_run (loop); + + if (await_terminating_service != NULL) + lose ("Didn't see name loss for \"org.freedesktop.DBus.TestSuiteGLibService\""); + if (!proxy_destroyed) + lose ("Didn't get proxy_destroyed"); + g_print ("Proxy destroyed successfully\n"); + + g_object_unref (G_OBJECT (proxy)); + + run_mainloop (); + + /* Create a new proxy for the name; should not be associated */ + proxy = dbus_g_proxy_new_for_name (connection, + "org.freedesktop.DBus.TestSuiteGLibService", + "/org/freedesktop/DBus/Tests/MyTestObject", + "org.freedesktop.DBus.Tests.MyObject"); + g_assert (proxy != NULL); + + proxy_destroyed = FALSE; + proxy_destroy_and_nameowner = FALSE; + proxy_destroy_and_nameowner_complete = FALSE; + + g_signal_connect (G_OBJECT (proxy), + "destroy", + G_CALLBACK (proxy_destroyed_cb), + NULL); + if (!dbus_g_proxy_call (driver, "GetNameOwner", &error, + G_TYPE_STRING, + "org.freedesktop.DBus.TestSuiteGLibService", + G_TYPE_INVALID, + G_TYPE_STRING, + &v_STRING_2, + G_TYPE_INVALID)) { + if (error->domain == DBUS_GERROR && error->code == DBUS_GERROR_NAME_HAS_NO_OWNER) + g_print ("Got expected error \"org.freedesktop.DBus.Error.NameHasNoOwner\"\n"); + else + lose_gerror ("Unexpected error from GetNameOwner", error); + } else + lose ("GetNameOwner unexpectedly succeeded!"); + g_clear_error (&error); + + /* This will have the side-effect of activating the service, thus + * causing a NameOwnerChanged, which should let our name proxy + * get signals + */ + g_print ("Calling Uppercase for name proxy\n"); + if (!dbus_g_proxy_call (proxy, "Uppercase", &error, + G_TYPE_STRING, "bazwhee", + G_TYPE_INVALID, + G_TYPE_STRING, &v_STRING_2, + G_TYPE_INVALID)) + lose_gerror ("Failed to complete Uppercase call", error); + g_free (v_STRING_2); + + dbus_g_proxy_add_signal (proxy, "Frobnicate", G_TYPE_INT, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (proxy, "Frobnicate", + G_CALLBACK (frobnicate_signal_handler), + NULL, NULL); + + g_print ("Calling EmitFrobnicate\n"); + if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EmitFrobnicate call", error); + + n_times_frobnicate_received = 0; + + dbus_g_connection_flush (connection); + exit_timeout = g_timeout_add (5000, timed_exit, loop); + g_main_loop_run (loop); + + if (n_times_frobnicate_received != 1) + lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received); + + /* Now terminate the service, then start it again (implicitly) and wait for signals */ + g_print ("Terminating service (2)\n"); + await_terminating_service = "org.freedesktop.DBus.TestSuiteGLibService"; + dbus_g_proxy_call_no_reply (proxy, "Terminate", G_TYPE_INVALID); + dbus_g_connection_flush (connection); + exit_timeout = g_timeout_add (5000, timed_exit, loop); + g_main_loop_run (loop); + if (await_terminating_service != NULL) + lose ("Didn't see name loss for \"org.freedesktop.DBus.TestSuiteGLibService\""); + + if (proxy_destroyed) + lose ("Unexpectedly got proxy_destroyed!"); + + n_times_frobnicate_received = 0; + + g_print ("Calling EmitFrobnicate (2)\n"); + if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EmitFrobnicate call", error); + + dbus_g_connection_flush (connection); + exit_timeout = g_timeout_add (5000, timed_exit, loop); + g_main_loop_run (loop); + + if (n_times_frobnicate_received != 1) + lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received); + + if (proxy_destroyed) + lose ("Unexpectedly got proxy_destroyed!"); + + /* Create another proxy for the name; should be associated immediately */ + proxy2 = dbus_g_proxy_new_for_name (connection, + "org.freedesktop.DBus.TestSuiteGLibService", + "/org/freedesktop/DBus/Tests/MyTestObject", + "org.freedesktop.DBus.Tests.MyObject"); + g_assert (proxy2 != NULL); + + dbus_g_proxy_add_signal (proxy2, "Frobnicate", G_TYPE_INT, G_TYPE_INVALID); + + dbus_g_proxy_connect_signal (proxy2, "Frobnicate", + G_CALLBACK (frobnicate_signal_handler_2), + NULL, NULL); + + g_print ("Calling EmitFrobnicate (3)\n"); + if (!dbus_g_proxy_call (proxy, "EmitFrobnicate", &error, + G_TYPE_INVALID, G_TYPE_INVALID)) + lose_gerror ("Failed to complete EmitFrobnicate call", error); + + dbus_g_connection_flush (connection); + exit_timeout = g_timeout_add (5000, timed_exit, loop); + g_main_loop_run (loop); + + if (n_times_frobnicate_received != 2) + lose ("Frobnicate signal received %d times for 1st proxy, should have been 2", n_times_frobnicate_received); + if (n_times_frobnicate_received_2 != 1) + lose ("Frobnicate signal received %d times for 2nd proxy, should have been 1", n_times_frobnicate_received_2); + g_object_unref (G_OBJECT (proxy)); + g_object_unref (G_OBJECT (proxy2)); + + run_mainloop (); + /* Test introspection */ proxy = dbus_g_proxy_new_for_name_owner (connection, "org.freedesktop.DBus.TestSuiteGLibService", "/org/freedesktop/DBus/Tests/MyTestObject", "org.freedesktop.DBus.Introspectable", &error); - if (proxy == NULL) lose_gerror ("Failed to create proxy for name owner", error); + g_print ("Testing introspect\n"); call = dbus_g_proxy_begin_call (proxy, "Introspect", G_TYPE_INVALID); error = NULL; diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c index 46421d70..315f1d65 100644 --- a/test/glib/test-service-glib.c +++ b/test/glib/test-service-glib.c @@ -83,6 +83,8 @@ gboolean my_object_emit_signal2 (MyObject *obj, GError **error); gboolean my_object_emit_frobnicate (MyObject *obj, GError **error); +gboolean my_object_terminate (MyObject *obj, GError **error); + #include "test-service-glib-glue.h" GQuark my_object_error_quark (void); @@ -464,6 +466,13 @@ my_object_emit_signal2 (MyObject *obj, GError **error) static GMainLoop *loop; +gboolean +my_object_terminate (MyObject *obj, GError **error) +{ + g_main_loop_quit (loop); + return TRUE; +} + #define TEST_SERVICE_NAME "org.freedesktop.DBus.TestSuiteGLibService" int diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml index e2197ec3..83240b47 100644 --- a/test/glib/test-service-glib.xml +++ b/test/glib/test-service-glib.xml @@ -86,6 +86,9 @@ + + + @@ -107,6 +110,9 @@ + + + diff --git a/tools/dbus-send.c b/tools/dbus-send.c index 4c7a3666..37b72067 100644 --- a/tools/dbus-send.c +++ b/tools/dbus-send.c @@ -428,7 +428,8 @@ main (int argc, char *argv[]) &error); if (dbus_error_is_set (&error)) { - fprintf (stderr, "Error: %s\n", + fprintf (stderr, "Error %s: %s\n", + error.name, error.message); exit (1); } -- cgit