diff options
| author | Colin Walters <walters@verbum.org> | 2005-06-29 16:59:00 +0000 | 
|---|---|---|
| committer | Colin Walters <walters@verbum.org> | 2005-06-29 16:59:00 +0000 | 
| commit | ab1ae1f4e204e0ee36690c828ea4a66fb9427633 (patch) | |
| tree | 9ae8c16976df625b3243fefc3cd75b24ebe4a654 | |
| parent | a3406a82793298943c02f4b4088a9ef5b35f0279 (diff) | |
2005-06-29  Colin Walters  <walters@verbum.org>
	* 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.
| -rw-r--r-- | ChangeLog | 60 | ||||
| -rw-r--r-- | glib/dbus-gobject.c | 14 | ||||
| -rw-r--r-- | glib/dbus-gproxy.c | 780 | ||||
| -rw-r--r-- | glib/examples/example-signal-recipient.c | 9 | ||||
| -rw-r--r-- | test/glib/test-dbus-glib.c | 324 | ||||
| -rw-r--r-- | test/glib/test-service-glib.c | 9 | ||||
| -rw-r--r-- | test/glib/test-service-glib.xml | 6 | ||||
| -rw-r--r-- | tools/dbus-send.c | 3 | 
8 files changed, 1076 insertions, 129 deletions
| @@ -1,3 +1,63 @@ +2005-06-29  Colin Walters  <walters@verbum.org> + +	* 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  <johnp@redhat.com>  	* 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,31 +6,78 @@  #include "test-service-glib-bindings.h"  #include <glib/dbus-gidl.h>  #include <glib/dbus-gparser.h> +#include <glib.h>  #include <glib-object.h>  #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,                      void        *user_data)  {    n_times_foo_received += 1; +  g_print ("Got Foo signal\n"); +    g_main_loop_quit (loop);    g_source_remove (exit_timeout);  } @@ -43,12 +90,24 @@ 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,  		     int          val, @@ -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 @@      <!-- Export signals -->      <signal name="Frobnicate"/> + +    <method name="Terminate"> +    </method>    </interface>    <!-- Test multiple interfaces on the same object --> @@ -107,6 +110,9 @@      <signal name="Sig2"/> +    <method name="Terminate"> +    </method> +    </interface>  </node> 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);          } | 
