(root)/
glib-2.79.0/
gio/
gproxyaddressenumerator.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   *
       3   * Copyright (C) 2010 Collabora, Ltd.
       4   *
       5   * SPDX-License-Identifier: LGPL-2.1-or-later
       6   *
       7   * This library is free software; you can redistribute it and/or
       8   * modify it under the terms of the GNU Lesser General Public
       9   * License as published by the Free Software Foundation; either
      10   * version 2.1 of the License, or (at your option) any later version.
      11   *
      12   * This library is distributed in the hope that it will be useful,
      13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15   * Lesser General Public License for more details.
      16   *
      17   * You should have received a copy of the GNU Lesser General
      18   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      19   *
      20   * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
      21   */
      22  
      23  #include "config.h"
      24  #include "gproxyaddressenumerator.h"
      25  
      26  #include <string.h>
      27  
      28  #include "gasyncresult.h"
      29  #include "ginetaddress.h"
      30  #include "gioerror.h"
      31  #include "glibintl.h"
      32  #include "glib-private.h"
      33  #include "gnetworkaddress.h"
      34  #include "gnetworkingprivate.h"
      35  #include "gproxy.h"
      36  #include "gproxyaddress.h"
      37  #include "gproxyresolver.h"
      38  #include "gtask.h"
      39  #include "gresolver.h"
      40  #include "gsocketaddress.h"
      41  #include "gsocketaddressenumerator.h"
      42  #include "gsocketconnectable.h"
      43  
      44  /**
      45   * GProxyAddressEnumerator:
      46   *
      47   * `GProxyAddressEnumerator` is a wrapper around
      48   * [class@Gio.SocketAddressEnumerator] which takes the [class@Gio.SocketAddress]
      49   * instances returned by the [class@Gio.SocketAddressEnumerator]
      50   * and wraps them in [class@Gio.ProxyAddress] instances, using the given
      51   * [property@Gio.ProxyAddressEnumerator:proxy-resolver].
      52   *
      53   * This enumerator will be returned (for example, by
      54   * [method@Gio.SocketConnectable.enumerate]) as appropriate when a proxy is
      55   * configured; there should be no need to manually wrap a
      56   * [class@Gio.SocketAddressEnumerator] instance with one.
      57   */
      58  
      59  #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)
      60  
      61  enum
      62  {
      63    PROP_0,
      64    PROP_URI,
      65    PROP_DEFAULT_PORT,
      66    PROP_CONNECTABLE,
      67    PROP_PROXY_RESOLVER
      68  };
      69  
      70  struct _GProxyAddressEnumeratorPrivate
      71  {
      72    /* Destination address */
      73    GSocketConnectable *connectable;
      74    gchar              *dest_uri;
      75    guint16             default_port;
      76    gchar              *dest_hostname;
      77    guint16             dest_port;
      78    GList              *dest_ips;
      79  
      80    /* Proxy enumeration */
      81    GProxyResolver           *proxy_resolver;
      82    gchar                   **proxies;
      83    gchar                   **next_proxy;
      84    GSocketAddressEnumerator *addr_enum;
      85    GSocketAddress           *proxy_address;
      86    const gchar              *proxy_uri;
      87    gchar                    *proxy_type;
      88    gchar                    *proxy_username;
      89    gchar                    *proxy_password;
      90    gboolean                  supports_hostname;
      91    GList                    *next_dest_ip;
      92    GError                   *last_error;
      93  
      94    /* ever_enumerated is TRUE after we've returned a result for the first time
      95     * via g_proxy_address_enumerator_next() or _next_async(). If FALSE, we have
      96     * never returned yet, and should return an error if returning NULL because
      97     * it does not make sense for a proxy resolver to return NULL except on error.
      98     * (Whereas a DNS resolver would return NULL with no error to indicate "no
      99     * results", a proxy resolver would want to return "direct://" instead, so
     100     * NULL without error does not make sense for us.)
     101     *
     102     * But if ever_enumerated is TRUE, then we must not report any further errors
     103     * (except for G_IO_ERROR_CANCELLED), because this is an API contract of
     104     * GSocketAddressEnumerator.
     105     */
     106    gboolean                  ever_enumerated;
     107  };
     108  
     109  G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
     110  
     111  static void
     112  save_userinfo (GProxyAddressEnumeratorPrivate *priv,
     113                 const gchar *proxy)
     114  {
     115    g_clear_pointer (&priv->proxy_username, g_free);
     116    g_clear_pointer (&priv->proxy_password, g_free);
     117  
     118    g_uri_split_with_user (proxy, G_URI_FLAGS_HAS_PASSWORD, NULL,
     119                           &priv->proxy_username, &priv->proxy_password,
     120                           NULL, NULL, NULL, NULL, NULL, NULL, NULL);
     121  }
     122  
     123  static void
     124  next_enumerator (GProxyAddressEnumeratorPrivate *priv)
     125  {
     126    if (priv->proxy_address)
     127      return;
     128  
     129    while (priv->addr_enum == NULL && *priv->next_proxy)
     130      {
     131        GSocketConnectable *connectable = NULL;
     132        GProxy *proxy;
     133  
     134        priv->proxy_uri = *priv->next_proxy++;
     135        g_free (priv->proxy_type);
     136        priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
     137  
     138        if (priv->proxy_type == NULL)
     139  	continue;
     140  
     141        /* Assumes hostnames are supported for unknown protocols */
     142        priv->supports_hostname = TRUE;
     143        proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
     144        if (proxy)
     145          {
     146  	  priv->supports_hostname = g_proxy_supports_hostname (proxy);
     147  	  g_object_unref (proxy);
     148          }
     149  
     150        if (strcmp ("direct", priv->proxy_type) == 0)
     151  	{
     152  	  if (priv->connectable)
     153  	    connectable = g_object_ref (priv->connectable);
     154  	  else
     155  	    connectable = g_network_address_new (priv->dest_hostname,
     156  						 priv->dest_port);
     157  	}
     158        else
     159  	{
     160  	  GError *error = NULL;
     161  	  int default_port;
     162  
     163  	  default_port = GLIB_PRIVATE_CALL (g_uri_get_default_scheme_port) (priv->proxy_type);
     164  	  if (default_port == -1)
     165  	    default_port = 0;
     166  
     167  	  connectable = g_network_address_parse_uri (priv->proxy_uri, default_port, &error);
     168  	  if (error)
     169  	    {
     170  	      g_warning ("Invalid proxy URI '%s': %s",
     171  			 priv->proxy_uri, error->message);
     172  	      g_error_free (error);
     173  	    }
     174  
     175  	  save_userinfo (priv, priv->proxy_uri);
     176  	}
     177  
     178        if (connectable)
     179  	{
     180  	  priv->addr_enum = g_socket_connectable_enumerate (connectable);
     181  	  g_object_unref (connectable);
     182  	}
     183      }
     184  }
     185  
     186  static GSocketAddress *
     187  g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
     188  				 GCancellable              *cancellable,
     189  				 GError                   **error)
     190  {
     191    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
     192    GSocketAddress *result = NULL;
     193    GError *first_error = NULL;
     194  
     195    if (!priv->ever_enumerated)
     196      {
     197        g_assert (priv->proxies == NULL);
     198        priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
     199  					       priv->dest_uri,
     200  					       cancellable,
     201  					       error);
     202        priv->next_proxy = priv->proxies;
     203  
     204        if (priv->proxies == NULL)
     205  	{
     206  	  priv->ever_enumerated = TRUE;
     207  	  return NULL;
     208  	}
     209      }
     210  
     211    while (result == NULL && (*priv->next_proxy || priv->addr_enum))
     212      {
     213        gchar *dest_hostname;
     214        gchar *dest_protocol;
     215        GInetSocketAddress *inetsaddr;
     216        GInetAddress *inetaddr;
     217        guint16 port;
     218  
     219        next_enumerator (priv);
     220  
     221        if (!priv->addr_enum)
     222  	continue;
     223  
     224        if (priv->proxy_address == NULL)
     225  	{
     226  	  priv->proxy_address = g_socket_address_enumerator_next (
     227  				    priv->addr_enum,
     228  				    cancellable,
     229  				    first_error ? NULL : &first_error);
     230  	}
     231  
     232        if (priv->proxy_address == NULL)
     233  	{
     234  	  g_object_unref (priv->addr_enum);
     235  	  priv->addr_enum = NULL;
     236  
     237  	  if (priv->dest_ips)
     238  	    {
     239  	      g_resolver_free_addresses (priv->dest_ips);
     240  	      priv->dest_ips = NULL;
     241  	    }
     242  
     243  	  continue;
     244  	}
     245  
     246        if (strcmp ("direct", priv->proxy_type) == 0)
     247  	{
     248  	  result = priv->proxy_address;
     249  	  priv->proxy_address = NULL;
     250  	  continue;
     251  	}
     252  
     253        if (!priv->supports_hostname)
     254  	{
     255  	  GInetAddress *dest_ip;
     256  
     257  	  if (!priv->dest_ips)
     258  	    {
     259  	      GResolver *resolver;
     260  
     261  	      resolver = g_resolver_get_default();
     262  	      priv->dest_ips = g_resolver_lookup_by_name (resolver,
     263  							  priv->dest_hostname,
     264  							  cancellable,
     265  							  first_error ? NULL : &first_error);
     266  	      g_object_unref (resolver);
     267  
     268  	      if (!priv->dest_ips)
     269  		{
     270  		  g_object_unref (priv->proxy_address);
     271  		  priv->proxy_address = NULL;
     272  		  continue;
     273  		}
     274  	    }
     275  
     276  	  if (!priv->next_dest_ip)
     277  	    priv->next_dest_ip = priv->dest_ips;
     278  	
     279  	  dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
     280  	  dest_hostname = g_inet_address_to_string (dest_ip);
     281  
     282  	  priv->next_dest_ip = g_list_next (priv->next_dest_ip);
     283  	}
     284        else
     285  	{
     286  	  dest_hostname = g_strdup (priv->dest_hostname);
     287  	}
     288        dest_protocol = g_uri_parse_scheme (priv->dest_uri);
     289  		 		  
     290        if (!G_IS_INET_SOCKET_ADDRESS (priv->proxy_address))
     291          {
     292  	  g_free (dest_hostname);
     293  	  g_free (dest_protocol);
     294          }
     295        g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address), NULL);
     296  
     297        inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
     298        inetaddr = g_inet_socket_address_get_address (inetsaddr);
     299        port = g_inet_socket_address_get_port (inetsaddr);
     300  
     301        result = g_object_new (G_TYPE_PROXY_ADDRESS,
     302  			     "address", inetaddr,
     303  			     "port", port,
     304  			     "protocol", priv->proxy_type,
     305  			     "destination-protocol", dest_protocol,
     306  			     "destination-hostname", dest_hostname,
     307  			     "destination-port", priv->dest_port,
     308  			     "username", priv->proxy_username,
     309  			     "password", priv->proxy_password,
     310  			     "uri", priv->proxy_uri,
     311  			     NULL);
     312        g_free (dest_hostname);
     313        g_free (dest_protocol);
     314  
     315        if (priv->supports_hostname || priv->next_dest_ip == NULL)
     316  	{
     317  	  g_object_unref (priv->proxy_address);
     318  	  priv->proxy_address = NULL;
     319  	}
     320      }
     321  
     322    if (result == NULL && first_error && (!priv->ever_enumerated || g_error_matches (first_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
     323      g_propagate_error (error, first_error);
     324    else if (first_error)
     325      g_error_free (first_error);
     326  
     327    if (result == NULL && error != NULL && *error == NULL && !priv->ever_enumerated)
     328      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unspecified proxy lookup failure"));
     329  
     330    priv->ever_enumerated = TRUE;
     331  
     332    return result;
     333  }
     334  
     335  static void
     336  complete_async (GTask *task)
     337  {
     338    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     339  
     340    if (priv->last_error && (!priv->ever_enumerated || g_error_matches (priv->last_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
     341      {
     342        g_task_return_error (task, priv->last_error);
     343        priv->last_error = NULL;
     344      }
     345    else if (!priv->ever_enumerated)
     346      {
     347        g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED,
     348                                         _("Unspecified proxy lookup failure"));
     349      }
     350    else
     351      {
     352        g_task_return_pointer (task, NULL, NULL);
     353      }
     354  
     355    priv->ever_enumerated = TRUE;
     356  
     357    g_clear_error (&priv->last_error);
     358    g_object_unref (task);
     359  }
     360  
     361  static void
     362  return_result (GTask *task)
     363  {
     364    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     365    GSocketAddress *result;
     366    gboolean is_inet_socket_address;
     367  
     368    if (strcmp ("direct", priv->proxy_type) == 0)
     369      {
     370        result = priv->proxy_address;
     371        priv->proxy_address = NULL;
     372      }
     373    else
     374      {
     375        gchar *dest_hostname, *dest_protocol;
     376        GInetSocketAddress *inetsaddr;
     377        GInetAddress *inetaddr;
     378        guint16 port;
     379  
     380        if (!priv->supports_hostname)
     381  	{
     382  	  GInetAddress *dest_ip;
     383  
     384  	  if (!priv->next_dest_ip)
     385  	    priv->next_dest_ip = priv->dest_ips;
     386  
     387  	  dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
     388  	  dest_hostname = g_inet_address_to_string (dest_ip);
     389  
     390  	  priv->next_dest_ip = g_list_next (priv->next_dest_ip);
     391  	}
     392        else
     393  	{
     394  	  dest_hostname = g_strdup (priv->dest_hostname);
     395  	}
     396        dest_protocol = g_uri_parse_scheme (priv->dest_uri);
     397  
     398        is_inet_socket_address = G_IS_INET_SOCKET_ADDRESS (priv->proxy_address);
     399        if (!is_inet_socket_address)
     400          {
     401  	  g_free (dest_hostname);
     402  	  g_free (dest_protocol);
     403          }
     404        g_return_if_fail (is_inet_socket_address);
     405  
     406        inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
     407        inetaddr = g_inet_socket_address_get_address (inetsaddr);
     408        port = g_inet_socket_address_get_port (inetsaddr);
     409  
     410        result = g_object_new (G_TYPE_PROXY_ADDRESS,
     411  			     "address", inetaddr,
     412  			     "port", port,
     413  			     "protocol", priv->proxy_type,
     414  			     "destination-protocol", dest_protocol,
     415  			     "destination-hostname", dest_hostname,
     416  			     "destination-port", priv->dest_port,
     417  			     "username", priv->proxy_username,
     418  			     "password", priv->proxy_password,
     419  			     "uri", priv->proxy_uri,
     420  			     NULL);
     421        g_free (dest_hostname);
     422        g_free (dest_protocol);
     423  
     424        if (priv->supports_hostname || priv->next_dest_ip == NULL)
     425  	{
     426  	  g_object_unref (priv->proxy_address);
     427  	  priv->proxy_address = NULL;
     428  	}
     429      }
     430  
     431    priv->ever_enumerated = TRUE;
     432    g_task_return_pointer (task, result, g_object_unref);
     433    g_object_unref (task);
     434  }
     435  
     436  static void address_enumerate_cb (GObject      *object,
     437  				  GAsyncResult *result,
     438  				  gpointer	user_data);
     439  
     440  static void
     441  next_proxy (GTask *task)
     442  {
     443    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     444  
     445    if (*priv->next_proxy)
     446      {
     447        g_object_unref (priv->addr_enum);
     448        priv->addr_enum = NULL;
     449  
     450        if (priv->dest_ips)
     451  	{
     452  	  g_resolver_free_addresses (priv->dest_ips);
     453  	  priv->dest_ips = NULL;
     454  	}
     455  
     456        next_enumerator (priv);
     457  
     458        if (priv->addr_enum)
     459  	{
     460  	  g_socket_address_enumerator_next_async (priv->addr_enum,
     461  						  g_task_get_cancellable (task),
     462  						  address_enumerate_cb,
     463  						  task);
     464  	  return;
     465  	}
     466      }
     467  
     468    complete_async (task);
     469  }
     470  
     471  static void
     472  dest_hostname_lookup_cb (GObject           *object,
     473  			 GAsyncResult      *result,
     474  			 gpointer           user_data)
     475  {
     476    GTask *task = user_data;
     477    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     478  
     479    g_clear_error (&priv->last_error);
     480    priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
     481  						     result,
     482  						     &priv->last_error);
     483    if (priv->dest_ips)
     484      return_result (task);
     485    else
     486      {
     487        g_clear_object (&priv->proxy_address);
     488        next_proxy (task);
     489      }
     490  }
     491  
     492  static void
     493  address_enumerate_cb (GObject	   *object,
     494  		      GAsyncResult *result,
     495  		      gpointer	    user_data)
     496  {
     497    GTask *task = user_data;
     498    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     499  
     500    g_clear_error (&priv->last_error);
     501    priv->proxy_address =
     502      g_socket_address_enumerator_next_finish (priv->addr_enum,
     503  					     result,
     504  					     &priv->last_error);
     505    if (priv->proxy_address)
     506      {
     507        if (!priv->supports_hostname && !priv->dest_ips)
     508  	{
     509  	  GResolver *resolver;
     510  	  resolver = g_resolver_get_default();
     511  	  g_resolver_lookup_by_name_async (resolver,
     512  					   priv->dest_hostname,
     513  					   g_task_get_cancellable (task),
     514  					   dest_hostname_lookup_cb,
     515  					   task);
     516  	  g_object_unref (resolver);
     517  	  return;
     518  	}
     519  
     520        return_result (task);
     521      }
     522    else
     523      next_proxy (task);
     524  }
     525  
     526  static void
     527  proxy_lookup_cb (GObject      *object,
     528  		 GAsyncResult *result,
     529  		 gpointer      user_data)
     530  {
     531    GTask *task = user_data;
     532    GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
     533  
     534    g_clear_error (&priv->last_error);
     535    priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
     536  						  result,
     537  						  &priv->last_error);
     538    priv->next_proxy = priv->proxies;
     539  
     540    if (priv->last_error)
     541      {
     542        complete_async (task);
     543        return;
     544      }
     545    else
     546      {
     547        next_enumerator (priv);
     548        if (priv->addr_enum)
     549  	{
     550  	  g_socket_address_enumerator_next_async (priv->addr_enum,
     551  						  g_task_get_cancellable (task),
     552  						  address_enumerate_cb,
     553  						  task);
     554  	  return;
     555  	}
     556      }
     557  
     558    complete_async (task);
     559  }
     560  
     561  static void
     562  g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
     563  				       GCancellable             *cancellable,
     564  				       GAsyncReadyCallback       callback,
     565  				       gpointer                  user_data)
     566  {
     567    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
     568    GTask *task;
     569  
     570    task = g_task_new (enumerator, cancellable, callback, user_data);
     571    g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
     572    g_task_set_task_data (task, priv, NULL);
     573  
     574    if (priv->proxies == NULL)
     575      {
     576        g_proxy_resolver_lookup_async (priv->proxy_resolver,
     577  				     priv->dest_uri,
     578  				     cancellable,
     579  				     proxy_lookup_cb,
     580  				     task);
     581        return;
     582      }
     583  
     584    if (priv->addr_enum)
     585      {
     586        if (priv->proxy_address)
     587  	{
     588  	  return_result (task);
     589  	  return;
     590  	}
     591        else
     592  	{
     593  	  g_socket_address_enumerator_next_async (priv->addr_enum,
     594  						  cancellable,
     595  						  address_enumerate_cb,
     596  						  task);
     597  	  return;
     598  	}
     599      }
     600  
     601    complete_async (task);
     602  }
     603  
     604  static GSocketAddress *
     605  g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
     606  					GAsyncResult              *result,
     607  					GError                   **error)
     608  {
     609    g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
     610  
     611    return g_task_propagate_pointer (G_TASK (result), error);
     612  }
     613  
     614  static void
     615  g_proxy_address_enumerator_constructed (GObject *object)
     616  {
     617    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
     618    GSocketConnectable *conn;
     619    guint port;
     620  
     621    if (priv->dest_uri)
     622      {
     623        conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
     624        if (conn)
     625          {
     626            g_object_get (conn,
     627                          "hostname", &priv->dest_hostname,
     628                          "port", &port,
     629                          NULL);
     630            priv->dest_port = port;
     631  
     632            g_object_unref (conn);
     633          }
     634        else
     635          g_warning ("Invalid URI '%s'", priv->dest_uri);
     636      }
     637  
     638    G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
     639  }
     640  
     641  static void
     642  g_proxy_address_enumerator_get_property (GObject        *object,
     643                                           guint           property_id,
     644                                           GValue         *value,
     645                                           GParamSpec     *pspec)
     646  {
     647    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
     648    switch (property_id)
     649      {
     650      case PROP_URI:
     651        g_value_set_string (value, priv->dest_uri);
     652        break;
     653  
     654      case PROP_DEFAULT_PORT:
     655        g_value_set_uint (value, priv->default_port);
     656        break;
     657  
     658      case PROP_CONNECTABLE:
     659        g_value_set_object (value, priv->connectable);
     660        break;
     661  
     662      case PROP_PROXY_RESOLVER:
     663        g_value_set_object (value, priv->proxy_resolver);
     664        break;
     665  
     666      default:
     667        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     668      }
     669  }
     670  
     671  static void
     672  g_proxy_address_enumerator_set_property (GObject        *object,
     673                                           guint           property_id,
     674                                           const GValue   *value,
     675                                           GParamSpec     *pspec)
     676  {
     677    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
     678    switch (property_id)
     679      {
     680      case PROP_URI:
     681        priv->dest_uri = g_value_dup_string (value);
     682        break;
     683  
     684      case PROP_DEFAULT_PORT:
     685        priv->default_port = g_value_get_uint (value);
     686        break;
     687  
     688      case PROP_CONNECTABLE:
     689        priv->connectable = g_value_dup_object (value);
     690        break;
     691  
     692      case PROP_PROXY_RESOLVER:
     693        if (priv->proxy_resolver)
     694          g_object_unref (priv->proxy_resolver);
     695        priv->proxy_resolver = g_value_get_object (value);
     696        if (!priv->proxy_resolver)
     697          priv->proxy_resolver = g_proxy_resolver_get_default ();
     698        g_object_ref (priv->proxy_resolver);
     699        break;
     700  
     701      default:
     702        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
     703      }
     704  }
     705  
     706  static void
     707  g_proxy_address_enumerator_finalize (GObject *object)
     708  {
     709    GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
     710  
     711    if (priv->connectable)
     712      g_object_unref (priv->connectable);
     713  
     714    if (priv->proxy_resolver)
     715      g_object_unref (priv->proxy_resolver);
     716  
     717    g_free (priv->dest_uri);
     718    g_free (priv->dest_hostname);
     719  
     720    if (priv->dest_ips)
     721      g_resolver_free_addresses (priv->dest_ips);
     722  
     723    g_strfreev (priv->proxies);
     724  
     725    if (priv->addr_enum)
     726      g_object_unref (priv->addr_enum);
     727  
     728    g_free (priv->proxy_type);
     729    g_free (priv->proxy_username);
     730    g_free (priv->proxy_password);
     731  
     732    g_clear_error (&priv->last_error);
     733  
     734    G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
     735  }
     736  
     737  static void
     738  g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
     739  {
     740    self->priv = g_proxy_address_enumerator_get_instance_private (self);
     741  }
     742  
     743  static void
     744  g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
     745  {
     746    GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
     747    GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
     748  
     749    object_class->constructed = g_proxy_address_enumerator_constructed;
     750    object_class->set_property = g_proxy_address_enumerator_set_property;
     751    object_class->get_property = g_proxy_address_enumerator_get_property;
     752    object_class->finalize = g_proxy_address_enumerator_finalize;
     753  
     754    enumerator_class->next = g_proxy_address_enumerator_next;
     755    enumerator_class->next_async = g_proxy_address_enumerator_next_async;
     756    enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
     757  
     758    /**
     759     * GProxyAddressEnumerator:uri:
     760     *
     761     * The destination URI. Use `none://` for a generic socket.
     762     */
     763    g_object_class_install_property (object_class,
     764  				   PROP_URI,
     765  				   g_param_spec_string ("uri", NULL, NULL,
     766  							NULL,
     767  							G_PARAM_READWRITE |
     768  							G_PARAM_CONSTRUCT_ONLY |
     769  							G_PARAM_STATIC_STRINGS));
     770  
     771    /**
     772     * GProxyAddressEnumerator:default-port:
     773     *
     774     * The default port to use if #GProxyAddressEnumerator:uri does not
     775     * specify one.
     776     *
     777     * Since: 2.38
     778     */
     779    g_object_class_install_property (object_class,
     780  				   PROP_DEFAULT_PORT,
     781  				   g_param_spec_uint ("default-port", NULL, NULL,
     782                                                        0, 65535, 0,
     783                                                        G_PARAM_READWRITE |
     784                                                        G_PARAM_CONSTRUCT_ONLY |
     785                                                        G_PARAM_STATIC_STRINGS));
     786  
     787    /**
     788     * GProxyAddressEnumerator:connectable:
     789     *
     790     * The connectable being enumerated.
     791     */
     792    g_object_class_install_property (object_class,
     793  				   PROP_CONNECTABLE,
     794  				   g_param_spec_object ("connectable", NULL, NULL,
     795  							G_TYPE_SOCKET_CONNECTABLE,
     796  							G_PARAM_READWRITE |
     797  							G_PARAM_CONSTRUCT_ONLY |
     798  							G_PARAM_STATIC_STRINGS));
     799  
     800    /**
     801     * GProxyAddressEnumerator:proxy-resolver:
     802     *
     803     * The proxy resolver to use.
     804     *
     805     * Since: 2.36
     806     */
     807    g_object_class_install_property (object_class,
     808                                     PROP_PROXY_RESOLVER,
     809                                     g_param_spec_object ("proxy-resolver", NULL, NULL,
     810                                                          G_TYPE_PROXY_RESOLVER,
     811                                                          G_PARAM_READWRITE |
     812                                                          G_PARAM_CONSTRUCT |
     813                                                          G_PARAM_STATIC_STRINGS));
     814  }