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