gproxyaddressenumerator.c 20.6 KB
Newer Older
1 2 3 4 5 6 7
/* GIO - GLib Input, Output and Streaming Library
 *
 * Copyright (C) 2010 Collabora, Ltd.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * 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 11 12 13 14 15
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * 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 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
 *
 * Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
 */

#include "config.h"
#include "gproxyaddressenumerator.h"

#include <string.h>

#include "gasyncresult.h"
#include "ginetaddress.h"
#include "glibintl.h"
#include "gnetworkaddress.h"
#include "gnetworkingprivate.h"
#include "gproxy.h"
#include "gproxyaddress.h"
#include "gproxyresolver.h"
34
#include "gtask.h"
35 36 37 38 39
#include "gresolver.h"
#include "gsocketaddress.h"
#include "gsocketaddressenumerator.h"
#include "gsocketconnectable.h"

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
/**
 * SECTION:gproxyaddressenumerator
 * @short_description: Proxy wrapper enumerator for socket addresses
 * @include: gio/gio.h
 *
 * #GProxyAddressEnumerator is a wrapper around #GSocketAddressEnumerator which
 * takes the #GSocketAddress instances returned by the #GSocketAddressEnumerator
 * and wraps them in #GProxyAddress instances, using the given
 * #GProxyAddressEnumerator:proxy-resolver.
 *
 * This enumerator will be returned (for example, by
 * g_socket_connectable_enumerate()) as appropriate when a proxy is configured;
 * there should be no need to manually wrap a #GSocketAddressEnumerator instance
 * with one.
 */

56 57 58 59 60 61
#define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv)

enum
{
  PROP_0,
  PROP_URI,
62
  PROP_DEFAULT_PORT,
63 64
  PROP_CONNECTABLE,
  PROP_PROXY_RESOLVER
65 66 67 68 69 70
};

struct _GProxyAddressEnumeratorPrivate
{
  /* Destination address */
  GSocketConnectable *connectable;
71 72 73 74
  gchar              *dest_uri;
  guint16             default_port;
  gchar              *dest_hostname;
  guint16             dest_port;
75 76 77
  GList              *dest_ips;

  /* Proxy enumeration */
78
  GProxyResolver           *proxy_resolver;
79 80
  gchar                   **proxies;
  gchar                   **next_proxy;
81 82
  GSocketAddressEnumerator *addr_enum;
  GSocketAddress           *proxy_address;
83
  const gchar              *proxy_uri;
84 85 86
  gchar                    *proxy_type;
  gchar                    *proxy_username;
  gchar                    *proxy_password;
87
  gboolean                  supports_hostname;
88
  GList                    *next_dest_ip;
89
  GError                   *last_error;
90 91
};

92 93
G_DEFINE_TYPE_WITH_PRIVATE (GProxyAddressEnumerator, g_proxy_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)

94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
static void
save_userinfo (GProxyAddressEnumeratorPrivate *priv,
	       const gchar *proxy)
{
  gchar *userinfo;

  if (priv->proxy_username)
    {
      g_free (priv->proxy_username);
      priv->proxy_username = NULL;
    }

  if (priv->proxy_password)
    {
      g_free (priv->proxy_password);
      priv->proxy_password = NULL;
    }
  
112
  if (_g_uri_parse_authority (proxy, NULL, NULL, &userinfo, NULL))
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141
    {
      if (userinfo)
	{
	  gchar **split = g_strsplit (userinfo, ":", 2);

	  if (split[0] != NULL)
	    {
	      priv->proxy_username = g_uri_unescape_string (split[0], NULL);
	      if (split[1] != NULL)
		priv->proxy_password = g_uri_unescape_string (split[1], NULL);
	    }

	  g_strfreev (split);
	  g_free (userinfo);
	}
    }
}

static void
next_enumerator (GProxyAddressEnumeratorPrivate *priv)
{
  if (priv->proxy_address)
    return;

  while (priv->addr_enum == NULL && *priv->next_proxy)
    {
      GSocketConnectable *connectable = NULL;
      GProxy *proxy;

142
      priv->proxy_uri = *priv->next_proxy++;
143
      g_free (priv->proxy_type);
144
      priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
145 146 147 148

      if (priv->proxy_type == NULL)
	continue;

Matthias Clasen's avatar
Matthias Clasen committed
149
      /* Assumes hostnames are supported for unknown protocols */
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
      priv->supports_hostname = TRUE;
      proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
      if (proxy)
        {
	  priv->supports_hostname = g_proxy_supports_hostname (proxy);
	  g_object_unref (proxy);
        }

      if (strcmp ("direct", priv->proxy_type) == 0)
	{
	  if (priv->connectable)
	    connectable = g_object_ref (priv->connectable);
	  else
	    connectable = g_network_address_new (priv->dest_hostname,
						 priv->dest_port);
	}
      else
	{
	  GError *error = NULL;

170
	  connectable = g_network_address_parse_uri (priv->proxy_uri, 0, &error);
171 172 173 174

	  if (error)
	    {
	      g_warning ("Invalid proxy URI '%s': %s",
175
			 priv->proxy_uri, error->message);
176 177 178
	      g_error_free (error);
	    }

179
	  save_userinfo (priv, priv->proxy_uri);
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200
	}

      if (connectable)
	{
	  priv->addr_enum = g_socket_connectable_enumerate (connectable);
	  g_object_unref (connectable);
	}
    }
}

static GSocketAddress *
g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
				 GCancellable              *cancellable,
				 GError                   **error)
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
  GSocketAddress *result = NULL;
  GError *first_error = NULL;

  if (priv->proxies == NULL)
    {
201
      priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
202 203 204 205 206 207 208 209 210 211 212 213
					       priv->dest_uri,
					       cancellable,
					       error);
      priv->next_proxy = priv->proxies;

      if (priv->proxies == NULL)
	return NULL;
    }

  while (result == NULL && (*priv->next_proxy || priv->addr_enum))
    {
      gchar *dest_hostname;
214
      gchar *dest_protocol;
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
      GInetSocketAddress *inetsaddr;
      GInetAddress *inetaddr;
      guint16 port;

      next_enumerator (priv);

      if (!priv->addr_enum)
	continue;

      if (priv->proxy_address == NULL)
	{
	  priv->proxy_address = g_socket_address_enumerator_next (
				    priv->addr_enum,
				    cancellable,
				    first_error ? NULL : &first_error);
	}

      if (priv->proxy_address == NULL)
	{
	  g_object_unref (priv->addr_enum);
	  priv->addr_enum = NULL;

	  if (priv->dest_ips)
	    {
	      g_resolver_free_addresses (priv->dest_ips);
	      priv->dest_ips = NULL;
	    }

	  continue;
	}

      if (strcmp ("direct", priv->proxy_type) == 0)
	{
	  result = priv->proxy_address;
	  priv->proxy_address = NULL;
	  continue;
	}

      if (!priv->supports_hostname)
	{
	  GInetAddress *dest_ip;

	  if (!priv->dest_ips)
	    {
	      GResolver *resolver;

	      resolver = g_resolver_get_default();
	      priv->dest_ips = g_resolver_lookup_by_name (resolver,
							  priv->dest_hostname,
							  cancellable,
							  first_error ? NULL : &first_error);
	      g_object_unref (resolver);

	      if (!priv->dest_ips)
		{
		  g_object_unref (priv->proxy_address);
		  priv->proxy_address = NULL;
		  continue;
		}
	    }

	  if (!priv->next_dest_ip)
	    priv->next_dest_ip = priv->dest_ips;
	
	  dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
	  dest_hostname = g_inet_address_to_string (dest_ip);

	  priv->next_dest_ip = g_list_next (priv->next_dest_ip);
	}
      else
	{
	  dest_hostname = g_strdup (priv->dest_hostname);
	}
288
      dest_protocol = g_uri_parse_scheme (priv->dest_uri);
289 290 291 292 293 294 295 296
		 		  
      g_return_val_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address),
			    NULL);

      inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
      inetaddr = g_inet_socket_address_get_address (inetsaddr);
      port = g_inet_socket_address_get_port (inetsaddr);

297 298 299 300 301 302 303 304 305 306 307
      result = g_object_new (G_TYPE_PROXY_ADDRESS,
			     "address", inetaddr,
			     "port", port,
			     "protocol", priv->proxy_type,
			     "destination-protocol", dest_protocol,
			     "destination-hostname", dest_hostname,
			     "destination-port", priv->dest_port,
			     "username", priv->proxy_username,
			     "password", priv->proxy_password,
			     "uri", priv->proxy_uri,
			     NULL);
308
      g_free (dest_hostname);
309
      g_free (dest_protocol);
310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328

      if (priv->supports_hostname || priv->next_dest_ip == NULL)
	{
	  g_object_unref (priv->proxy_address);
	  priv->proxy_address = NULL;
	}
    }

  if (result == NULL && first_error)
    g_propagate_error (error, first_error);
  else if (first_error)
    g_error_free (first_error);

  return result;
}



static void
329
complete_async (GTask *task)
330
{
331
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
332 333 334

  if (priv->last_error)
    {
335
      g_task_return_error (task, priv->last_error);
336 337
      priv->last_error = NULL;
    }
338 339
  else
    g_task_return_pointer (task, NULL, NULL);
340

341
  g_object_unref (task);
342 343 344
}

static void
345
return_result (GTask *task)
346
{
347
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
348 349 350 351 352 353 354 355 356
  GSocketAddress *result;

  if (strcmp ("direct", priv->proxy_type) == 0)
    {
      result = priv->proxy_address;
      priv->proxy_address = NULL;
    }
  else
    {
357
      gchar *dest_hostname, *dest_protocol;
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377
      GInetSocketAddress *inetsaddr;
      GInetAddress *inetaddr;
      guint16 port;

      if (!priv->supports_hostname)
	{
	  GInetAddress *dest_ip;

	  if (!priv->next_dest_ip)
	    priv->next_dest_ip = priv->dest_ips;

	  dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
	  dest_hostname = g_inet_address_to_string (dest_ip);

	  priv->next_dest_ip = g_list_next (priv->next_dest_ip);
	}
      else
	{
	  dest_hostname = g_strdup (priv->dest_hostname);
	}
378
      dest_protocol = g_uri_parse_scheme (priv->dest_uri);
379 380 381 382 383 384 385

      g_return_if_fail (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));

      inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
      inetaddr = g_inet_socket_address_get_address (inetsaddr);
      port = g_inet_socket_address_get_port (inetsaddr);

386 387 388 389 390 391 392 393 394 395 396
      result = g_object_new (G_TYPE_PROXY_ADDRESS,
			     "address", inetaddr,
			     "port", port,
			     "protocol", priv->proxy_type,
			     "destination-protocol", dest_protocol,
			     "destination-hostname", dest_hostname,
			     "destination-port", priv->dest_port,
			     "username", priv->proxy_username,
			     "password", priv->proxy_password,
			     "uri", priv->proxy_uri,
			     NULL);
397
      g_free (dest_hostname);
398
      g_free (dest_protocol);
399 400 401 402 403 404 405 406

      if (priv->supports_hostname || priv->next_dest_ip == NULL)
	{
	  g_object_unref (priv->proxy_address);
	  priv->proxy_address = NULL;
	}
    }

407 408
  g_task_return_pointer (task, result, g_object_unref);
  g_object_unref (task);
409 410
}

411 412 413 414 415
static void address_enumerate_cb (GObject      *object,
				  GAsyncResult *result,
				  gpointer	user_data);

static void
416
next_proxy (GTask *task)
417
{
418 419
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);

420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
  if (*priv->next_proxy)
    {
      g_object_unref (priv->addr_enum);
      priv->addr_enum = NULL;

      if (priv->dest_ips)
	{
	  g_resolver_free_addresses (priv->dest_ips);
	  priv->dest_ips = NULL;
	}

      next_enumerator (priv);

      if (priv->addr_enum)
	{
	  g_socket_address_enumerator_next_async (priv->addr_enum,
436
						  g_task_get_cancellable (task),
437
						  address_enumerate_cb,
438
						  task);
439 440 441 442
	  return;
	}
    }

443
  complete_async (task);
444 445
}

446 447 448 449 450
static void
dest_hostname_lookup_cb (GObject           *object,
			 GAsyncResult      *result,
			 gpointer           user_data)
{
451 452
  GTask *task = user_data;
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
453

454
  g_clear_error (&priv->last_error);
455 456
  priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
						     result,
457
						     &priv->last_error);
458
  if (priv->dest_ips)
459
    return_result (task);
460
  else
461 462
    {
      g_clear_object (&priv->proxy_address);
463
      next_proxy (task);
464
    }
465 466 467 468 469 470 471
}

static void
address_enumerate_cb (GObject	   *object,
		      GAsyncResult *result,
		      gpointer	    user_data)
{
472 473
  GTask *task = user_data;
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
474

475
  g_clear_error (&priv->last_error);
476 477 478
  priv->proxy_address =
    g_socket_address_enumerator_next_finish (priv->addr_enum,
					     result,
479
					     &priv->last_error);
480 481 482 483 484 485 486 487
  if (priv->proxy_address)
    {
      if (!priv->supports_hostname && !priv->dest_ips)
	{
	  GResolver *resolver;
	  resolver = g_resolver_get_default();
	  g_resolver_lookup_by_name_async (resolver,
					   priv->dest_hostname,
488
					   g_task_get_cancellable (task),
489
					   dest_hostname_lookup_cb,
490
					   task);
491 492 493 494
	  g_object_unref (resolver);
	  return;
	}

495
      return_result (task);
496
    }
497
  else
498
    next_proxy (task);
499 500 501 502 503 504 505
}

static void
proxy_lookup_cb (GObject      *object,
		 GAsyncResult *result,
		 gpointer      user_data)
{
506 507
  GTask *task = user_data;
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
508

509
  g_clear_error (&priv->last_error);
510 511
  priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
						  result,
512
						  &priv->last_error);
513 514
  priv->next_proxy = priv->proxies;

515
  if (priv->last_error)
516
    {
517 518
      complete_async (task);
      return;
519 520 521 522 523 524 525
    }
  else
    {
      next_enumerator (priv);
      if (priv->addr_enum)
	{
	  g_socket_address_enumerator_next_async (priv->addr_enum,
526
						  g_task_get_cancellable (task),
527
						  address_enumerate_cb,
528
						  task);
529 530 531 532
	  return;
	}
    }

533
  complete_async (task);
534 535 536 537 538 539 540 541 542
}

static void
g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
				       GCancellable             *cancellable,
				       GAsyncReadyCallback       callback,
				       gpointer                  user_data)
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
543
  GTask *task;
544

545
  task = g_task_new (enumerator, cancellable, callback, user_data);
546
  g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
547
  g_task_set_task_data (task, priv, NULL);
548 549 550

  if (priv->proxies == NULL)
    {
551
      g_proxy_resolver_lookup_async (priv->proxy_resolver,
552 553 554
				     priv->dest_uri,
				     cancellable,
				     proxy_lookup_cb,
555
				     task);
556 557 558 559 560 561 562
      return;
    }

  if (priv->addr_enum)
    {
      if (priv->proxy_address)
	{
563 564
	  return_result (task);
	  return;
565 566 567 568 569 570
	}
      else
	{
	  g_socket_address_enumerator_next_async (priv->addr_enum,
						  cancellable,
						  address_enumerate_cb,
571
						  task);
572 573 574 575
	  return;
	}
    }

576
  complete_async (task);
577 578 579 580 581 582 583
}

static GSocketAddress *
g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
					GAsyncResult              *result,
					GError                   **error)
{
584
  g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
585

586
  return g_task_propagate_pointer (G_TASK (result), error);
587 588
}

589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615
static void
g_proxy_address_enumerator_constructed (GObject *object)
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
  GSocketConnectable *conn;
  guint port;

  if (priv->dest_uri)
    {
      conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
      if (conn)
        {
          g_object_get (conn,
                        "hostname", &priv->dest_hostname,
                        "port", &port,
                        NULL);
          priv->dest_port = port;

          g_object_unref (conn);
        }
      else
        g_warning ("Invalid URI '%s'", priv->dest_uri);
    }

  G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
}

616 617
static void
g_proxy_address_enumerator_get_property (GObject        *object,
618 619 620
                                         guint           property_id,
                                         GValue         *value,
                                         GParamSpec     *pspec)
621 622 623 624
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
  switch (property_id)
    {
625 626 627 628 629 630 631
    case PROP_URI:
      g_value_set_string (value, priv->dest_uri);
      break;

    case PROP_DEFAULT_PORT:
      g_value_set_uint (value, priv->default_port);
      break;
632

633 634 635
    case PROP_CONNECTABLE:
      g_value_set_object (value, priv->connectable);
      break;
636

637 638 639
    case PROP_PROXY_RESOLVER:
      g_value_set_object (value, priv->proxy_resolver);
      break;
640

641 642
    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
643 644 645 646 647
    }
}

static void
g_proxy_address_enumerator_set_property (GObject        *object,
648 649 650
                                         guint           property_id,
                                         const GValue   *value,
                                         GParamSpec     *pspec)
651 652 653 654
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
  switch (property_id)
    {
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677
    case PROP_URI:
      priv->dest_uri = g_value_dup_string (value);
      break;

    case PROP_DEFAULT_PORT:
      priv->default_port = g_value_get_uint (value);
      break;

    case PROP_CONNECTABLE:
      priv->connectable = g_value_dup_object (value);
      break;

    case PROP_PROXY_RESOLVER:
      if (priv->proxy_resolver)
        g_object_unref (priv->proxy_resolver);
      priv->proxy_resolver = g_value_get_object (value);
      if (!priv->proxy_resolver)
        priv->proxy_resolver = g_proxy_resolver_get_default ();
      g_object_ref (priv->proxy_resolver);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
678 679 680 681 682 683 684 685 686 687 688
    }
}

static void
g_proxy_address_enumerator_finalize (GObject *object)
{
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);

  if (priv->connectable)
    g_object_unref (priv->connectable);

689 690 691
  if (priv->proxy_resolver)
    g_object_unref (priv->proxy_resolver);

692 693 694 695 696 697 698 699 700 701 702 703 704 705 706
  g_free (priv->dest_uri);
  g_free (priv->dest_hostname);

  if (priv->dest_ips)
    g_resolver_free_addresses (priv->dest_ips);

  g_strfreev (priv->proxies);

  if (priv->addr_enum)
    g_object_unref (priv->addr_enum);

  g_free (priv->proxy_type);
  g_free (priv->proxy_username);
  g_free (priv->proxy_password);

707 708
  g_clear_error (&priv->last_error);

709 710 711 712 713 714
  G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
}

static void
g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
{
715
  self->priv = g_proxy_address_enumerator_get_instance_private (self);
716 717 718 719 720 721 722 723
}

static void
g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
{
  GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
  GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);

724
  object_class->constructed = g_proxy_address_enumerator_constructed;
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742
  object_class->set_property = g_proxy_address_enumerator_set_property;
  object_class->get_property = g_proxy_address_enumerator_get_property;
  object_class->finalize = g_proxy_address_enumerator_finalize;

  enumerator_class->next = g_proxy_address_enumerator_next;
  enumerator_class->next_async = g_proxy_address_enumerator_next_async;
  enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;

  g_object_class_install_property (object_class,
				   PROP_URI,
				   g_param_spec_string ("uri",
							P_("URI"),
							P_("The destination URI, use none:// for generic socket"),
							NULL,
							G_PARAM_READWRITE |
							G_PARAM_CONSTRUCT_ONLY |
							G_PARAM_STATIC_STRINGS));

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760
  /**
   * GProxyAddressEnumerator:default-port:
   *
   * The default port to use if #GProxyAddressEnumerator:uri does not
   * specify one.
   *
   * Since: 2.38
   */
  g_object_class_install_property (object_class,
				   PROP_DEFAULT_PORT,
				   g_param_spec_uint ("default-port",
                                                      P_("Default port"),
                                                      P_("The default port to use if uri does not specify one"),
                                                      0, 65535, 0,
                                                      G_PARAM_READWRITE |
                                                      G_PARAM_CONSTRUCT_ONLY |
                                                      G_PARAM_STATIC_STRINGS));

761 762 763 764 765 766 767 768 769
  g_object_class_install_property (object_class,
				   PROP_CONNECTABLE,
				   g_param_spec_object ("connectable",
							P_("Connectable"),
							P_("The connectable being enumerated."),
							G_TYPE_SOCKET_CONNECTABLE,
							G_PARAM_READWRITE |
							G_PARAM_CONSTRUCT_ONLY |
							G_PARAM_STATIC_STRINGS));
770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786

  /**
   * GProxyAddressEnumerator:proxy-resolver:
   *
   * The proxy resolver to use.
   *
   * Since: 2.36
   */
  g_object_class_install_property (object_class,
                                   PROP_PROXY_RESOLVER,
                                   g_param_spec_object ("proxy-resolver",
                                                        P_("Proxy resolver"),
                                                        P_("The proxy resolver to use."),
                                                        G_TYPE_PROXY_RESOLVER,
                                                        G_PARAM_READWRITE |
                                                        G_PARAM_CONSTRUCT |
                                                        G_PARAM_STATIC_STRINGS));
787
}