Coverage Report

Created: 2025-07-23 08:13

/src/pango/subprojects/glib/gio/gproxyaddressenumerator.c
Line
Count
Source (jump to first uncovered line)
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
0
#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
0
{
115
0
  g_clear_pointer (&priv->proxy_username, g_free);
116
0
  g_clear_pointer (&priv->proxy_password, g_free);
117
118
0
  g_uri_split_with_user (proxy, G_URI_FLAGS_HAS_PASSWORD, NULL,
119
0
                         &priv->proxy_username, &priv->proxy_password,
120
0
                         NULL, NULL, NULL, NULL, NULL, NULL, NULL);
121
0
}
122
123
static void
124
next_enumerator (GProxyAddressEnumeratorPrivate *priv)
125
0
{
126
0
  if (priv->proxy_address)
127
0
    return;
128
129
0
  while (priv->addr_enum == NULL && *priv->next_proxy)
130
0
    {
131
0
      GSocketConnectable *connectable = NULL;
132
0
      GProxy *proxy;
133
134
0
      priv->proxy_uri = *priv->next_proxy++;
135
0
      g_free (priv->proxy_type);
136
0
      priv->proxy_type = g_uri_parse_scheme (priv->proxy_uri);
137
138
0
      if (priv->proxy_type == NULL)
139
0
  continue;
140
141
      /* Assumes hostnames are supported for unknown protocols */
142
0
      priv->supports_hostname = TRUE;
143
0
      proxy = g_proxy_get_default_for_protocol (priv->proxy_type);
144
0
      if (proxy)
145
0
        {
146
0
    priv->supports_hostname = g_proxy_supports_hostname (proxy);
147
0
    g_object_unref (proxy);
148
0
        }
149
150
0
      if (strcmp ("direct", priv->proxy_type) == 0)
151
0
  {
152
0
    if (priv->connectable)
153
0
      connectable = g_object_ref (priv->connectable);
154
0
    else
155
0
      connectable = g_network_address_new (priv->dest_hostname,
156
0
             priv->dest_port);
157
0
  }
158
0
      else
159
0
  {
160
0
    GError *error = NULL;
161
0
    int default_port;
162
163
0
    default_port = GLIB_PRIVATE_CALL (g_uri_get_default_scheme_port) (priv->proxy_type);
164
0
    if (default_port == -1)
165
0
      default_port = 0;
166
167
0
    connectable = g_network_address_parse_uri (priv->proxy_uri, default_port, &error);
168
0
    if (error)
169
0
      {
170
0
        g_warning ("Invalid proxy URI '%s': %s",
171
0
       priv->proxy_uri, error->message);
172
0
        g_error_free (error);
173
0
      }
174
175
0
    save_userinfo (priv, priv->proxy_uri);
176
0
  }
177
178
0
      if (connectable)
179
0
  {
180
0
    priv->addr_enum = g_socket_connectable_enumerate (connectable);
181
0
    g_object_unref (connectable);
182
0
  }
183
0
    }
184
0
}
185
186
static GSocketAddress *
187
g_proxy_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
188
         GCancellable              *cancellable,
189
         GError                   **error)
190
0
{
191
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
192
0
  GSocketAddress *result = NULL;
193
0
  GError *first_error = NULL;
194
195
0
  if (!priv->ever_enumerated)
196
0
    {
197
0
      g_assert (priv->proxies == NULL);
198
0
      priv->proxies = g_proxy_resolver_lookup (priv->proxy_resolver,
199
0
                 priv->dest_uri,
200
0
                 cancellable,
201
0
                 error);
202
0
      priv->next_proxy = priv->proxies;
203
204
0
      if (priv->proxies == NULL)
205
0
  {
206
0
    priv->ever_enumerated = TRUE;
207
0
    return NULL;
208
0
  }
209
0
    }
210
211
0
  while (result == NULL && (*priv->next_proxy || priv->addr_enum))
212
0
    {
213
0
      gchar *dest_hostname;
214
0
      gchar *dest_protocol;
215
0
      GInetSocketAddress *inetsaddr;
216
0
      GInetAddress *inetaddr;
217
0
      guint16 port;
218
219
0
      next_enumerator (priv);
220
221
0
      if (!priv->addr_enum)
222
0
  continue;
223
224
0
      if (priv->proxy_address == NULL)
225
0
  {
226
0
    priv->proxy_address = g_socket_address_enumerator_next (
227
0
            priv->addr_enum,
228
0
            cancellable,
229
0
            first_error ? NULL : &first_error);
230
0
  }
231
232
0
      if (priv->proxy_address == NULL)
233
0
  {
234
0
    g_object_unref (priv->addr_enum);
235
0
    priv->addr_enum = NULL;
236
237
0
    if (priv->dest_ips)
238
0
      {
239
0
        g_resolver_free_addresses (priv->dest_ips);
240
0
        priv->dest_ips = NULL;
241
0
      }
242
243
0
    continue;
244
0
  }
245
246
0
      if (strcmp ("direct", priv->proxy_type) == 0)
247
0
  {
248
0
    result = priv->proxy_address;
249
0
    priv->proxy_address = NULL;
250
0
    continue;
251
0
  }
252
253
0
      if (!priv->supports_hostname)
254
0
  {
255
0
    GInetAddress *dest_ip;
256
257
0
    if (!priv->dest_ips)
258
0
      {
259
0
        GResolver *resolver;
260
261
0
        resolver = g_resolver_get_default();
262
0
        priv->dest_ips = g_resolver_lookup_by_name (resolver,
263
0
                priv->dest_hostname,
264
0
                cancellable,
265
0
                first_error ? NULL : &first_error);
266
0
        g_object_unref (resolver);
267
268
0
        if (!priv->dest_ips)
269
0
    {
270
0
      g_object_unref (priv->proxy_address);
271
0
      priv->proxy_address = NULL;
272
0
      continue;
273
0
    }
274
0
      }
275
276
0
    if (!priv->next_dest_ip)
277
0
      priv->next_dest_ip = priv->dest_ips;
278
  
279
0
    dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
280
0
    dest_hostname = g_inet_address_to_string (dest_ip);
281
282
0
    priv->next_dest_ip = g_list_next (priv->next_dest_ip);
283
0
  }
284
0
      else
285
0
  {
286
0
    dest_hostname = g_strdup (priv->dest_hostname);
287
0
  }
288
289
0
      g_assert (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
290
291
0
      dest_protocol = g_uri_parse_scheme (priv->dest_uri);
292
293
0
      inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
294
0
      inetaddr = g_inet_socket_address_get_address (inetsaddr);
295
0
      port = g_inet_socket_address_get_port (inetsaddr);
296
297
0
      result = g_object_new (G_TYPE_PROXY_ADDRESS,
298
0
           "address", inetaddr,
299
0
           "port", port,
300
0
           "protocol", priv->proxy_type,
301
0
           "destination-protocol", dest_protocol,
302
0
           "destination-hostname", dest_hostname,
303
0
           "destination-port", priv->dest_port,
304
0
           "username", priv->proxy_username,
305
0
           "password", priv->proxy_password,
306
0
           "uri", priv->proxy_uri,
307
0
           NULL);
308
0
      g_free (dest_hostname);
309
0
      g_free (dest_protocol);
310
311
0
      if (priv->supports_hostname || priv->next_dest_ip == NULL)
312
0
  {
313
0
    g_object_unref (priv->proxy_address);
314
0
    priv->proxy_address = NULL;
315
0
  }
316
0
    }
317
318
0
  if (result == NULL && first_error && (!priv->ever_enumerated || g_error_matches (first_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
319
0
    g_propagate_error (error, first_error);
320
0
  else if (first_error)
321
0
    g_error_free (first_error);
322
323
0
  if (result == NULL && error != NULL && *error == NULL && !priv->ever_enumerated)
324
0
    g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unspecified proxy lookup failure"));
325
326
0
  priv->ever_enumerated = TRUE;
327
328
0
  return result;
329
0
}
330
331
static void
332
complete_async (GTask *task)
333
0
{
334
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
335
336
0
  if (priv->last_error && (!priv->ever_enumerated || g_error_matches (priv->last_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)))
337
0
    {
338
0
      g_task_return_error (task, priv->last_error);
339
0
      priv->last_error = NULL;
340
0
    }
341
0
  else if (!priv->ever_enumerated)
342
0
    {
343
0
      g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED,
344
0
                                       _("Unspecified proxy lookup failure"));
345
0
    }
346
0
  else
347
0
    {
348
0
      g_task_return_pointer (task, NULL, NULL);
349
0
    }
350
351
0
  priv->ever_enumerated = TRUE;
352
353
0
  g_clear_error (&priv->last_error);
354
0
  g_object_unref (task);
355
0
}
356
357
static void
358
return_result (GTask *task)
359
0
{
360
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
361
0
  GSocketAddress *result;
362
363
0
  if (strcmp ("direct", priv->proxy_type) == 0)
364
0
    {
365
0
      result = priv->proxy_address;
366
0
      priv->proxy_address = NULL;
367
0
    }
368
0
  else
369
0
    {
370
0
      gchar *dest_hostname, *dest_protocol;
371
0
      GInetSocketAddress *inetsaddr;
372
0
      GInetAddress *inetaddr;
373
0
      guint16 port;
374
375
0
      if (!priv->supports_hostname)
376
0
  {
377
0
    GInetAddress *dest_ip;
378
379
0
    if (!priv->next_dest_ip)
380
0
      priv->next_dest_ip = priv->dest_ips;
381
382
0
    dest_ip = G_INET_ADDRESS (priv->next_dest_ip->data);
383
0
    dest_hostname = g_inet_address_to_string (dest_ip);
384
385
0
    priv->next_dest_ip = g_list_next (priv->next_dest_ip);
386
0
  }
387
0
      else
388
0
  {
389
0
    dest_hostname = g_strdup (priv->dest_hostname);
390
0
  }
391
0
      dest_protocol = g_uri_parse_scheme (priv->dest_uri);
392
393
0
      g_assert (G_IS_INET_SOCKET_ADDRESS (priv->proxy_address));
394
395
0
      inetsaddr = G_INET_SOCKET_ADDRESS (priv->proxy_address);
396
0
      inetaddr = g_inet_socket_address_get_address (inetsaddr);
397
0
      port = g_inet_socket_address_get_port (inetsaddr);
398
399
0
      result = g_object_new (G_TYPE_PROXY_ADDRESS,
400
0
           "address", inetaddr,
401
0
           "port", port,
402
0
           "protocol", priv->proxy_type,
403
0
           "destination-protocol", dest_protocol,
404
0
           "destination-hostname", dest_hostname,
405
0
           "destination-port", priv->dest_port,
406
0
           "username", priv->proxy_username,
407
0
           "password", priv->proxy_password,
408
0
           "uri", priv->proxy_uri,
409
0
           NULL);
410
0
      g_free (dest_hostname);
411
0
      g_free (dest_protocol);
412
413
0
      if (priv->supports_hostname || priv->next_dest_ip == NULL)
414
0
  {
415
0
    g_object_unref (priv->proxy_address);
416
0
    priv->proxy_address = NULL;
417
0
  }
418
0
    }
419
420
0
  priv->ever_enumerated = TRUE;
421
0
  g_task_return_pointer (task, result, g_object_unref);
422
0
  g_object_unref (task);
423
0
}
424
425
static void address_enumerate_cb (GObject      *object,
426
          GAsyncResult *result,
427
          gpointer  user_data);
428
429
static void
430
next_proxy (GTask *task)
431
0
{
432
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
433
434
0
  if (*priv->next_proxy)
435
0
    {
436
0
      g_object_unref (priv->addr_enum);
437
0
      priv->addr_enum = NULL;
438
439
0
      if (priv->dest_ips)
440
0
  {
441
0
    g_resolver_free_addresses (priv->dest_ips);
442
0
    priv->dest_ips = NULL;
443
0
  }
444
445
0
      next_enumerator (priv);
446
447
0
      if (priv->addr_enum)
448
0
  {
449
0
    g_socket_address_enumerator_next_async (priv->addr_enum,
450
0
              g_task_get_cancellable (task),
451
0
              address_enumerate_cb,
452
0
              task);
453
0
    return;
454
0
  }
455
0
    }
456
457
0
  complete_async (task);
458
0
}
459
460
static void
461
dest_hostname_lookup_cb (GObject           *object,
462
       GAsyncResult      *result,
463
       gpointer           user_data)
464
0
{
465
0
  GTask *task = user_data;
466
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
467
468
0
  g_clear_error (&priv->last_error);
469
0
  priv->dest_ips = g_resolver_lookup_by_name_finish (G_RESOLVER (object),
470
0
                 result,
471
0
                 &priv->last_error);
472
0
  if (priv->dest_ips)
473
0
    return_result (task);
474
0
  else
475
0
    {
476
0
      g_clear_object (&priv->proxy_address);
477
0
      next_proxy (task);
478
0
    }
479
0
}
480
481
static void
482
address_enumerate_cb (GObject    *object,
483
          GAsyncResult *result,
484
          gpointer      user_data)
485
0
{
486
0
  GTask *task = user_data;
487
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
488
489
0
  g_clear_error (&priv->last_error);
490
0
  priv->proxy_address =
491
0
    g_socket_address_enumerator_next_finish (priv->addr_enum,
492
0
               result,
493
0
               &priv->last_error);
494
0
  if (priv->proxy_address)
495
0
    {
496
0
      if (!priv->supports_hostname && !priv->dest_ips)
497
0
  {
498
0
    GResolver *resolver;
499
0
    resolver = g_resolver_get_default();
500
0
    g_resolver_lookup_by_name_async (resolver,
501
0
             priv->dest_hostname,
502
0
             g_task_get_cancellable (task),
503
0
             dest_hostname_lookup_cb,
504
0
             task);
505
0
    g_object_unref (resolver);
506
0
    return;
507
0
  }
508
509
0
      return_result (task);
510
0
    }
511
0
  else
512
0
    next_proxy (task);
513
0
}
514
515
static void
516
proxy_lookup_cb (GObject      *object,
517
     GAsyncResult *result,
518
     gpointer      user_data)
519
0
{
520
0
  GTask *task = user_data;
521
0
  GProxyAddressEnumeratorPrivate *priv = g_task_get_task_data (task);
522
523
0
  g_clear_error (&priv->last_error);
524
0
  priv->proxies = g_proxy_resolver_lookup_finish (G_PROXY_RESOLVER (object),
525
0
              result,
526
0
              &priv->last_error);
527
0
  priv->next_proxy = priv->proxies;
528
529
0
  if (priv->last_error)
530
0
    {
531
0
      complete_async (task);
532
0
      return;
533
0
    }
534
0
  else
535
0
    {
536
0
      next_enumerator (priv);
537
0
      if (priv->addr_enum)
538
0
  {
539
0
    g_socket_address_enumerator_next_async (priv->addr_enum,
540
0
              g_task_get_cancellable (task),
541
0
              address_enumerate_cb,
542
0
              task);
543
0
    return;
544
0
  }
545
0
    }
546
547
0
  complete_async (task);
548
0
}
549
550
static void
551
g_proxy_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
552
               GCancellable             *cancellable,
553
               GAsyncReadyCallback       callback,
554
               gpointer                  user_data)
555
0
{
556
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (enumerator);
557
0
  GTask *task;
558
559
0
  task = g_task_new (enumerator, cancellable, callback, user_data);
560
0
  g_task_set_source_tag (task, g_proxy_address_enumerator_next_async);
561
0
  g_task_set_task_data (task, priv, NULL);
562
563
0
  if (priv->proxies == NULL)
564
0
    {
565
0
      g_proxy_resolver_lookup_async (priv->proxy_resolver,
566
0
             priv->dest_uri,
567
0
             cancellable,
568
0
             proxy_lookup_cb,
569
0
             task);
570
0
      return;
571
0
    }
572
573
0
  if (priv->addr_enum)
574
0
    {
575
0
      if (priv->proxy_address)
576
0
  {
577
0
    return_result (task);
578
0
    return;
579
0
  }
580
0
      else
581
0
  {
582
0
    g_socket_address_enumerator_next_async (priv->addr_enum,
583
0
              cancellable,
584
0
              address_enumerate_cb,
585
0
              task);
586
0
    return;
587
0
  }
588
0
    }
589
590
0
  complete_async (task);
591
0
}
592
593
static GSocketAddress *
594
g_proxy_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
595
          GAsyncResult              *result,
596
          GError                   **error)
597
0
{
598
0
  g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL);
599
600
0
  return g_task_propagate_pointer (G_TASK (result), error);
601
0
}
602
603
static void
604
g_proxy_address_enumerator_constructed (GObject *object)
605
0
{
606
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
607
0
  GSocketConnectable *conn;
608
0
  guint port;
609
610
0
  if (priv->dest_uri)
611
0
    {
612
0
      conn = g_network_address_parse_uri (priv->dest_uri, priv->default_port, NULL);
613
0
      if (conn)
614
0
        {
615
0
          g_object_get (conn,
616
0
                        "hostname", &priv->dest_hostname,
617
0
                        "port", &port,
618
0
                        NULL);
619
0
          priv->dest_port = port;
620
621
0
          g_object_unref (conn);
622
0
        }
623
0
      else
624
0
        g_warning ("Invalid URI '%s'", priv->dest_uri);
625
0
    }
626
627
0
  G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->constructed (object);
628
0
}
629
630
static void
631
g_proxy_address_enumerator_get_property (GObject        *object,
632
                                         guint           property_id,
633
                                         GValue         *value,
634
                                         GParamSpec     *pspec)
635
0
{
636
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
637
0
  switch (property_id)
638
0
    {
639
0
    case PROP_URI:
640
0
      g_value_set_string (value, priv->dest_uri);
641
0
      break;
642
643
0
    case PROP_DEFAULT_PORT:
644
0
      g_value_set_uint (value, priv->default_port);
645
0
      break;
646
647
0
    case PROP_CONNECTABLE:
648
0
      g_value_set_object (value, priv->connectable);
649
0
      break;
650
651
0
    case PROP_PROXY_RESOLVER:
652
0
      g_value_set_object (value, priv->proxy_resolver);
653
0
      break;
654
655
0
    default:
656
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
657
0
    }
658
0
}
659
660
static void
661
g_proxy_address_enumerator_set_property (GObject        *object,
662
                                         guint           property_id,
663
                                         const GValue   *value,
664
                                         GParamSpec     *pspec)
665
0
{
666
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
667
0
  switch (property_id)
668
0
    {
669
0
    case PROP_URI:
670
0
      priv->dest_uri = g_value_dup_string (value);
671
0
      break;
672
673
0
    case PROP_DEFAULT_PORT:
674
0
      priv->default_port = g_value_get_uint (value);
675
0
      break;
676
677
0
    case PROP_CONNECTABLE:
678
0
      priv->connectable = g_value_dup_object (value);
679
0
      break;
680
681
0
    case PROP_PROXY_RESOLVER:
682
0
      if (priv->proxy_resolver)
683
0
        g_object_unref (priv->proxy_resolver);
684
0
      priv->proxy_resolver = g_value_get_object (value);
685
0
      if (!priv->proxy_resolver)
686
0
        priv->proxy_resolver = g_proxy_resolver_get_default ();
687
0
      g_object_ref (priv->proxy_resolver);
688
0
      break;
689
690
0
    default:
691
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
692
0
    }
693
0
}
694
695
static void
696
g_proxy_address_enumerator_finalize (GObject *object)
697
0
{
698
0
  GProxyAddressEnumeratorPrivate *priv = GET_PRIVATE (object);
699
700
0
  if (priv->connectable)
701
0
    g_object_unref (priv->connectable);
702
703
0
  if (priv->proxy_resolver)
704
0
    g_object_unref (priv->proxy_resolver);
705
706
0
  g_free (priv->dest_uri);
707
0
  g_free (priv->dest_hostname);
708
709
0
  if (priv->dest_ips)
710
0
    g_resolver_free_addresses (priv->dest_ips);
711
712
0
  g_strfreev (priv->proxies);
713
714
0
  if (priv->addr_enum)
715
0
    g_object_unref (priv->addr_enum);
716
717
0
  g_free (priv->proxy_type);
718
0
  g_free (priv->proxy_username);
719
0
  g_free (priv->proxy_password);
720
721
0
  g_clear_error (&priv->last_error);
722
723
0
  G_OBJECT_CLASS (g_proxy_address_enumerator_parent_class)->finalize (object);
724
0
}
725
726
static void
727
g_proxy_address_enumerator_init (GProxyAddressEnumerator *self)
728
0
{
729
0
  self->priv = g_proxy_address_enumerator_get_instance_private (self);
730
0
}
731
732
static void
733
g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enumerator_class)
734
0
{
735
0
  GObjectClass *object_class = G_OBJECT_CLASS (proxy_enumerator_class);
736
0
  GSocketAddressEnumeratorClass *enumerator_class = G_SOCKET_ADDRESS_ENUMERATOR_CLASS (proxy_enumerator_class);
737
738
0
  object_class->constructed = g_proxy_address_enumerator_constructed;
739
0
  object_class->set_property = g_proxy_address_enumerator_set_property;
740
0
  object_class->get_property = g_proxy_address_enumerator_get_property;
741
0
  object_class->finalize = g_proxy_address_enumerator_finalize;
742
743
0
  enumerator_class->next = g_proxy_address_enumerator_next;
744
0
  enumerator_class->next_async = g_proxy_address_enumerator_next_async;
745
0
  enumerator_class->next_finish = g_proxy_address_enumerator_next_finish;
746
747
  /**
748
   * GProxyAddressEnumerator:uri:
749
   *
750
   * The destination URI. Use `none://` for a generic socket.
751
   */
752
0
  g_object_class_install_property (object_class,
753
0
           PROP_URI,
754
0
           g_param_spec_string ("uri", NULL, NULL,
755
0
              NULL,
756
0
              G_PARAM_READWRITE |
757
0
              G_PARAM_CONSTRUCT_ONLY |
758
0
              G_PARAM_STATIC_STRINGS));
759
760
  /**
761
   * GProxyAddressEnumerator:default-port:
762
   *
763
   * The default port to use if #GProxyAddressEnumerator:uri does not
764
   * specify one.
765
   *
766
   * Since: 2.38
767
   */
768
0
  g_object_class_install_property (object_class,
769
0
           PROP_DEFAULT_PORT,
770
0
           g_param_spec_uint ("default-port", NULL, NULL,
771
0
                                                      0, 65535, 0,
772
0
                                                      G_PARAM_READWRITE |
773
0
                                                      G_PARAM_CONSTRUCT_ONLY |
774
0
                                                      G_PARAM_STATIC_STRINGS));
775
776
  /**
777
   * GProxyAddressEnumerator:connectable:
778
   *
779
   * The connectable being enumerated.
780
   */
781
0
  g_object_class_install_property (object_class,
782
0
           PROP_CONNECTABLE,
783
0
           g_param_spec_object ("connectable", NULL, NULL,
784
0
              G_TYPE_SOCKET_CONNECTABLE,
785
0
              G_PARAM_READWRITE |
786
0
              G_PARAM_CONSTRUCT_ONLY |
787
0
              G_PARAM_STATIC_STRINGS));
788
789
  /**
790
   * GProxyAddressEnumerator:proxy-resolver:
791
   *
792
   * The proxy resolver to use.
793
   *
794
   * Since: 2.36
795
   */
796
0
  g_object_class_install_property (object_class,
797
0
                                   PROP_PROXY_RESOLVER,
798
0
                                   g_param_spec_object ("proxy-resolver", NULL, NULL,
799
0
                                                        G_TYPE_PROXY_RESOLVER,
800
0
                                                        G_PARAM_READWRITE |
801
0
                                                        G_PARAM_CONSTRUCT |
802
0
                                                        G_PARAM_STATIC_STRINGS));
803
0
}