Coverage Report

Created: 2025-06-13 06:55

/src/glib/gio/gnetworkservice.c
Line
Count
Source (jump to first uncovered line)
1
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2
3
/* GIO - GLib Input, Output and Streaming Library
4
 *
5
 * Copyright (C) 2008 Red Hat, Inc.
6
 *
7
 * SPDX-License-Identifier: LGPL-2.1-or-later
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General
20
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21
 */
22
23
#include "config.h"
24
#include <glib.h>
25
#include "glibintl.h"
26
27
#include "gnetworkservice.h"
28
29
#include "gcancellable.h"
30
#include "ginetaddress.h"
31
#include "ginetsocketaddress.h"
32
#include "gioerror.h"
33
#include "gnetworkaddress.h"
34
#include "gnetworkingprivate.h"
35
#include "gresolver.h"
36
#include "gtask.h"
37
#include "gsocketaddressenumerator.h"
38
#include "gsocketconnectable.h"
39
#include "gsrvtarget.h"
40
41
#include <stdlib.h>
42
#include <string.h>
43
44
45
/**
46
 * SECTION:gnetworkservice
47
 * @short_description: A GSocketConnectable for resolving SRV records
48
 * @include: gio/gio.h
49
 *
50
 * Like #GNetworkAddress does with hostnames, #GNetworkService
51
 * provides an easy way to resolve a SRV record, and then attempt to
52
 * connect to one of the hosts that implements that service, handling
53
 * service priority/weighting, multiple IP addresses, and multiple
54
 * address families.
55
 *
56
 * See #GSrvTarget for more information about SRV records, and see
57
 * #GSocketConnectable for an example of using the connectable
58
 * interface.
59
 */
60
61
/**
62
 * GNetworkService:
63
 *
64
 * A #GSocketConnectable for resolving a SRV record and connecting to
65
 * that service.
66
 */
67
68
struct _GNetworkServicePrivate
69
{
70
  gchar *service, *protocol, *domain, *scheme;
71
  GList *targets;
72
};
73
74
enum {
75
  PROP_0,
76
  PROP_SERVICE,
77
  PROP_PROTOCOL,
78
  PROP_DOMAIN,
79
  PROP_SCHEME
80
};
81
82
static void g_network_service_set_property (GObject      *object,
83
                                            guint         prop_id,
84
                                            const GValue *value,
85
                                            GParamSpec   *pspec);
86
static void g_network_service_get_property (GObject      *object,
87
                                            guint         prop_id,
88
                                            GValue       *value,
89
                                            GParamSpec   *pspec);
90
91
static void                      g_network_service_connectable_iface_init       (GSocketConnectableIface *iface);
92
static GSocketAddressEnumerator *g_network_service_connectable_enumerate        (GSocketConnectable      *connectable);
93
static GSocketAddressEnumerator *g_network_service_connectable_proxy_enumerate  (GSocketConnectable      *connectable);
94
static gchar                    *g_network_service_connectable_to_string        (GSocketConnectable      *connectable);
95
96
G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
97
                         G_ADD_PRIVATE (GNetworkService)
98
                         G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
99
                                                g_network_service_connectable_iface_init))
100
101
static void
102
g_network_service_finalize (GObject *object)
103
0
{
104
0
  GNetworkService *srv = G_NETWORK_SERVICE (object);
105
106
0
  g_free (srv->priv->service);
107
0
  g_free (srv->priv->protocol);
108
0
  g_free (srv->priv->domain);
109
0
  g_free (srv->priv->scheme);
110
111
0
  if (srv->priv->targets)
112
0
    g_resolver_free_targets (srv->priv->targets);
113
114
0
  G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
115
0
}
116
117
static void
118
g_network_service_class_init (GNetworkServiceClass *klass)
119
0
{
120
0
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
121
122
0
  gobject_class->set_property = g_network_service_set_property;
123
0
  gobject_class->get_property = g_network_service_get_property;
124
0
  gobject_class->finalize = g_network_service_finalize;
125
126
0
  g_object_class_install_property (gobject_class, PROP_SERVICE,
127
0
                                   g_param_spec_string ("service",
128
0
                                                        P_("Service"),
129
0
                                                        P_("Service name, eg \"ldap\""),
130
0
                                                        NULL,
131
0
                                                        G_PARAM_READWRITE |
132
0
                                                        G_PARAM_CONSTRUCT_ONLY |
133
0
                                                        G_PARAM_STATIC_STRINGS));
134
0
  g_object_class_install_property (gobject_class, PROP_PROTOCOL,
135
0
                                   g_param_spec_string ("protocol",
136
0
                                                        P_("Protocol"),
137
0
                                                        P_("Network protocol, eg \"tcp\""),
138
0
                                                        NULL,
139
0
                                                        G_PARAM_READWRITE |
140
0
                                                        G_PARAM_CONSTRUCT_ONLY |
141
0
                                                        G_PARAM_STATIC_STRINGS));
142
0
  g_object_class_install_property (gobject_class, PROP_DOMAIN,
143
0
                                   g_param_spec_string ("domain",
144
0
                                                        P_("Domain"),
145
0
                                                        P_("Network domain, eg, \"example.com\""),
146
0
                                                        NULL,
147
0
                                                        G_PARAM_READWRITE |
148
0
                                                        G_PARAM_CONSTRUCT_ONLY |
149
0
                                                        G_PARAM_STATIC_STRINGS));
150
0
  g_object_class_install_property (gobject_class, PROP_DOMAIN,
151
0
                                   g_param_spec_string ("scheme",
152
0
                                                        P_("Scheme"),
153
0
                                                        P_("Network scheme (default is to use service)"),
154
0
                                                        NULL,
155
0
                                                        G_PARAM_READWRITE |
156
0
                                                        G_PARAM_STATIC_STRINGS));
157
158
0
}
159
160
static void
161
g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
162
0
{
163
0
  connectable_iface->enumerate = g_network_service_connectable_enumerate;
164
0
  connectable_iface->proxy_enumerate = g_network_service_connectable_proxy_enumerate;
165
0
  connectable_iface->to_string = g_network_service_connectable_to_string;
166
0
}
167
168
static void
169
g_network_service_init (GNetworkService *srv)
170
0
{
171
0
  srv->priv = g_network_service_get_instance_private (srv);
172
0
}
173
174
static void
175
g_network_service_set_property (GObject      *object,
176
                                guint         prop_id,
177
                                const GValue *value,
178
                                GParamSpec   *pspec)
179
0
{
180
0
  GNetworkService *srv = G_NETWORK_SERVICE (object);
181
182
0
  switch (prop_id)
183
0
    {
184
0
    case PROP_SERVICE:
185
0
      srv->priv->service = g_value_dup_string (value);
186
0
      break;
187
188
0
    case PROP_PROTOCOL:
189
0
      srv->priv->protocol = g_value_dup_string (value);
190
0
      break;
191
192
0
    case PROP_DOMAIN:
193
0
      srv->priv->domain = g_value_dup_string (value);
194
0
      break;
195
196
0
    case PROP_SCHEME:
197
0
      g_network_service_set_scheme (srv, g_value_get_string (value));
198
0
      break;
199
200
0
    default:
201
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202
0
      break;
203
0
    }
204
0
}
205
206
static void
207
g_network_service_get_property (GObject    *object,
208
                                guint       prop_id,
209
                                GValue     *value,
210
                                GParamSpec *pspec)
211
0
{
212
0
  GNetworkService *srv = G_NETWORK_SERVICE (object);
213
214
0
  switch (prop_id)
215
0
    {
216
0
    case PROP_SERVICE:
217
0
      g_value_set_string (value, g_network_service_get_service (srv));
218
0
      break;
219
220
0
    case PROP_PROTOCOL:
221
0
      g_value_set_string (value, g_network_service_get_protocol (srv));
222
0
      break;
223
224
0
    case PROP_DOMAIN:
225
0
      g_value_set_string (value, g_network_service_get_domain (srv));
226
0
      break;
227
228
0
    case PROP_SCHEME:
229
0
      g_value_set_string (value, g_network_service_get_scheme (srv));
230
0
      break;
231
232
0
    default:
233
0
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
234
0
      break;
235
0
    }
236
0
}
237
238
/**
239
 * g_network_service_new:
240
 * @service: the service type to look up (eg, "ldap")
241
 * @protocol: the networking protocol to use for @service (eg, "tcp")
242
 * @domain: the DNS domain to look up the service in
243
 *
244
 * Creates a new #GNetworkService representing the given @service,
245
 * @protocol, and @domain. This will initially be unresolved; use the
246
 * #GSocketConnectable interface to resolve it.
247
 *
248
 * Returns: (transfer full) (type GNetworkService): a new #GNetworkService
249
 *
250
 * Since: 2.22
251
 */
252
GSocketConnectable *
253
g_network_service_new (const gchar *service,
254
                       const gchar *protocol,
255
                       const gchar *domain)
256
0
{
257
0
  return g_object_new (G_TYPE_NETWORK_SERVICE,
258
0
                       "service", service,
259
0
                       "protocol", protocol,
260
0
                       "domain", domain,
261
0
                       NULL);
262
0
}
263
264
/**
265
 * g_network_service_get_service:
266
 * @srv: a #GNetworkService
267
 *
268
 * Gets @srv's service name (eg, "ldap").
269
 *
270
 * Returns: @srv's service name
271
 *
272
 * Since: 2.22
273
 */
274
const gchar *
275
g_network_service_get_service (GNetworkService *srv)
276
0
{
277
0
  g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
278
279
0
  return srv->priv->service;
280
0
}
281
282
/**
283
 * g_network_service_get_protocol:
284
 * @srv: a #GNetworkService
285
 *
286
 * Gets @srv's protocol name (eg, "tcp").
287
 *
288
 * Returns: @srv's protocol name
289
 *
290
 * Since: 2.22
291
 */
292
const gchar *
293
g_network_service_get_protocol (GNetworkService *srv)
294
0
{
295
0
  g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
296
297
0
  return srv->priv->protocol;
298
0
}
299
300
/**
301
 * g_network_service_get_domain:
302
 * @srv: a #GNetworkService
303
 *
304
 * Gets the domain that @srv serves. This might be either UTF-8 or
305
 * ASCII-encoded, depending on what @srv was created with.
306
 *
307
 * Returns: @srv's domain name
308
 *
309
 * Since: 2.22
310
 */
311
const gchar *
312
g_network_service_get_domain (GNetworkService *srv)
313
0
{
314
0
  g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
315
316
0
  return srv->priv->domain;
317
0
}
318
319
/**
320
 * g_network_service_get_scheme:
321
 * @srv: a #GNetworkService
322
 *
323
 * Gets the URI scheme used to resolve proxies. By default, the service name
324
 * is used as scheme.
325
 *
326
 * Returns: @srv's scheme name
327
 *
328
 * Since: 2.26
329
 */
330
const gchar *
331
g_network_service_get_scheme (GNetworkService *srv)
332
0
{
333
0
  g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
334
335
0
  if (srv->priv->scheme)
336
0
    return srv->priv->scheme;
337
0
  else
338
0
    return srv->priv->service;
339
0
}
340
341
/**
342
 * g_network_service_set_scheme:
343
 * @srv: a #GNetworkService
344
 * @scheme: a URI scheme
345
 *
346
 * Set's the URI scheme used to resolve proxies. By default, the service name
347
 * is used as scheme.
348
 *
349
 * Since: 2.26
350
 */
351
void
352
g_network_service_set_scheme (GNetworkService *srv,
353
                              const gchar     *scheme)
354
0
{
355
0
  g_return_if_fail (G_IS_NETWORK_SERVICE (srv));
356
357
0
  g_free (srv->priv->scheme);
358
0
  srv->priv->scheme = g_strdup (scheme);
359
360
0
  g_object_notify (G_OBJECT (srv), "scheme");
361
0
}
362
363
static GList *
364
g_network_service_fallback_targets (GNetworkService *srv)
365
0
{
366
0
  GSrvTarget *target;
367
0
  gboolean has_port;
368
0
  guint16 port;
369
370
0
  has_port = g_getservbyname_ntohs (srv->priv->service, "tcp", &port);
371
372
0
#ifdef HAVE_ENDSERVENT
373
0
  endservent ();
374
0
#endif
375
376
0
  if (!has_port)
377
0
    return NULL;
378
379
0
  target = g_srv_target_new (srv->priv->domain, port, 0, 0);
380
0
  return g_list_append (NULL, target);
381
0
}
382
383
0
#define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
384
0
#define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
385
386
typedef struct {
387
  GSocketAddressEnumerator parent_instance;
388
389
  GResolver *resolver;
390
  GNetworkService *srv;
391
  GSocketAddressEnumerator *addr_enum;
392
  GList *t;
393
  gboolean use_proxy;
394
395
  GError *error;
396
397
} GNetworkServiceAddressEnumerator;
398
399
typedef struct {
400
  GSocketAddressEnumeratorClass parent_class;
401
402
} GNetworkServiceAddressEnumeratorClass;
403
404
static GType _g_network_service_address_enumerator_get_type (void);
405
G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
406
407
static GSocketAddress *
408
g_network_service_address_enumerator_next (GSocketAddressEnumerator  *enumerator,
409
                                           GCancellable              *cancellable,
410
                                           GError                   **error)
411
0
{
412
0
  GNetworkServiceAddressEnumerator *srv_enum =
413
0
    G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
414
0
  GSocketAddress *ret = NULL;
415
416
  /* If we haven't yet resolved srv, do that */
417
0
  if (!srv_enum->srv->priv->targets)
418
0
    {
419
0
      GList *targets;
420
0
      GError *my_error = NULL;
421
422
0
      targets = g_resolver_lookup_service (srv_enum->resolver,
423
0
                                           srv_enum->srv->priv->service,
424
0
                                           srv_enum->srv->priv->protocol,
425
0
                                           srv_enum->srv->priv->domain,
426
0
                                           cancellable, &my_error);
427
0
      if (!targets && g_error_matches (my_error, G_RESOLVER_ERROR,
428
0
                                       G_RESOLVER_ERROR_NOT_FOUND))
429
0
        {
430
0
          targets = g_network_service_fallback_targets (srv_enum->srv);
431
0
          if (targets)
432
0
            g_clear_error (&my_error);
433
0
        }
434
435
0
      if (my_error)
436
0
        {
437
0
          g_propagate_error (error, my_error);
438
0
          return NULL;
439
0
        }
440
441
0
      srv_enum->srv->priv->targets = targets;
442
0
      srv_enum->t = srv_enum->srv->priv->targets;
443
0
    }
444
445
  /* Delegate to GNetworkAddress */
446
0
  do
447
0
    {
448
0
      if (srv_enum->addr_enum == NULL && srv_enum->t)
449
0
        {
450
0
          GError *my_error = NULL;
451
0
          gchar *uri;
452
0
          gchar *hostname;
453
0
          GSocketConnectable *addr;
454
0
          GSrvTarget *target = srv_enum->t->data;
455
456
0
          srv_enum->t = g_list_next (srv_enum->t);
457
458
0
          hostname = g_hostname_to_ascii (g_srv_target_get_hostname (target));
459
460
0
          if (hostname == NULL)
461
0
            {
462
0
              if (srv_enum->error == NULL)
463
0
                srv_enum->error =
464
0
                  g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
465
0
                               "Received invalid hostname '%s' from GSrvTarget",
466
0
                               g_srv_target_get_hostname (target));
467
0
              continue;
468
0
            }
469
470
0
          uri = g_uri_join (G_URI_FLAGS_NONE,
471
0
                            g_network_service_get_scheme (srv_enum->srv),
472
0
                            NULL,
473
0
                            hostname,
474
0
                            g_srv_target_get_port (target),
475
0
                            "",
476
0
                            NULL,
477
0
                            NULL);
478
0
          g_free (hostname);
479
480
0
          addr = g_network_address_parse_uri (uri,
481
0
                                              g_srv_target_get_port (target),
482
0
                                              &my_error);
483
0
          g_free (uri);
484
485
0
          if (addr == NULL)
486
0
            {
487
0
              if (srv_enum->error == NULL)
488
0
                srv_enum->error = my_error;
489
0
              else
490
0
                g_error_free (my_error);
491
0
              continue;
492
0
            }
493
494
0
          if (srv_enum->use_proxy)
495
0
            srv_enum->addr_enum = g_socket_connectable_proxy_enumerate (addr);
496
0
          else
497
0
            srv_enum->addr_enum = g_socket_connectable_enumerate (addr);
498
0
          g_object_unref (addr);
499
0
        }
500
501
0
      if (srv_enum->addr_enum)
502
0
        {
503
0
          GError *my_error = NULL;
504
505
0
          ret = g_socket_address_enumerator_next (srv_enum->addr_enum,
506
0
                                                  cancellable,
507
0
                                                  &my_error);
508
509
0
          if (my_error)
510
0
            {
511
0
              if (srv_enum->error == NULL)
512
0
                srv_enum->error = my_error;
513
0
              else
514
0
                g_error_free (my_error);
515
0
            }
516
517
0
          if (!ret)
518
0
            {
519
0
              g_object_unref (srv_enum->addr_enum);
520
0
              srv_enum->addr_enum = NULL;
521
0
            }
522
0
        }
523
0
    }
524
0
  while (srv_enum->addr_enum == NULL && srv_enum->t);
525
526
0
  if (ret == NULL && srv_enum->error)
527
0
    {
528
0
      g_propagate_error (error, srv_enum->error);
529
0
      srv_enum->error = NULL;
530
0
    }
531
532
0
  return ret;
533
0
}
534
535
static void next_async_resolved_targets   (GObject      *source_object,
536
                                           GAsyncResult *result,
537
                                           gpointer      user_data);
538
static void next_async_have_targets       (GTask        *srv_enum);
539
static void next_async_have_address       (GObject      *source_object,
540
                                           GAsyncResult *result,
541
                                           gpointer      user_data);
542
543
static void
544
g_network_service_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator,
545
                                                 GCancellable              *cancellable,
546
                                                 GAsyncReadyCallback        callback,
547
                                                 gpointer                   user_data)
548
0
{
549
0
  GNetworkServiceAddressEnumerator *srv_enum =
550
0
    G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
551
0
  GTask *task;
552
553
0
  task = g_task_new (enumerator, cancellable, callback, user_data);
554
0
  g_task_set_source_tag (task, g_network_service_address_enumerator_next_async);
555
556
  /* If we haven't yet resolved srv, do that */
557
0
  if (!srv_enum->srv->priv->targets)
558
0
    {
559
0
      g_resolver_lookup_service_async (srv_enum->resolver,
560
0
                                       srv_enum->srv->priv->service,
561
0
                                       srv_enum->srv->priv->protocol,
562
0
                                       srv_enum->srv->priv->domain,
563
0
                                       cancellable,
564
0
                                       next_async_resolved_targets,
565
0
                                       task);
566
0
    }
567
0
  else
568
0
    next_async_have_targets (task);
569
0
}
570
571
static void
572
next_async_resolved_targets (GObject      *source_object,
573
                             GAsyncResult *result,
574
                             gpointer      user_data)
575
0
{
576
0
  GTask *task = user_data;
577
0
  GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
578
0
  GError *error = NULL;
579
0
  GList *targets;
580
581
0
  targets = g_resolver_lookup_service_finish (srv_enum->resolver,
582
0
                                              result, &error);
583
584
0
  if (!targets && g_error_matches (error, G_RESOLVER_ERROR,
585
0
                                   G_RESOLVER_ERROR_NOT_FOUND))
586
0
    {
587
0
      targets = g_network_service_fallback_targets (srv_enum->srv);
588
0
      if (targets)
589
0
        g_clear_error (&error);
590
0
    }
591
592
0
  if (error)
593
0
    {
594
0
      g_task_return_error (task, error);
595
0
      g_object_unref (task);
596
0
    }
597
0
  else
598
0
    {
599
0
      srv_enum->t = srv_enum->srv->priv->targets = targets;
600
0
      next_async_have_targets (task);
601
0
    }
602
0
}
603
604
static void
605
next_async_have_targets (GTask *task)
606
0
{
607
0
  GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
608
609
  /* Delegate to GNetworkAddress */
610
0
  if (srv_enum->addr_enum == NULL && srv_enum->t)
611
0
    {
612
0
      GSocketConnectable *addr;
613
0
      GSrvTarget *target = srv_enum->t->data;
614
615
0
      srv_enum->t = g_list_next (srv_enum->t);
616
0
      addr = g_network_address_new (g_srv_target_get_hostname (target),
617
0
                                    (guint16) g_srv_target_get_port (target));
618
619
0
      if (srv_enum->use_proxy)
620
0
        srv_enum->addr_enum = g_socket_connectable_proxy_enumerate (addr);
621
0
      else
622
0
        srv_enum->addr_enum = g_socket_connectable_enumerate (addr);
623
624
0
      g_object_unref (addr);
625
0
    }
626
627
0
  if (srv_enum->addr_enum)
628
0
    {
629
0
      g_socket_address_enumerator_next_async (srv_enum->addr_enum,
630
0
                                              g_task_get_cancellable (task),
631
0
                                              next_async_have_address,
632
0
                                              task);
633
0
    }
634
0
  else
635
0
    {
636
0
      if (srv_enum->error)
637
0
        {
638
0
          g_task_return_error (task, srv_enum->error);
639
0
          srv_enum->error = NULL;
640
0
        }
641
0
      else
642
0
        g_task_return_pointer (task, NULL, NULL);
643
644
0
      g_object_unref (task);
645
0
    }
646
0
}
647
648
static void
649
next_async_have_address (GObject      *source_object,
650
                         GAsyncResult *result,
651
                         gpointer      user_data)
652
0
{
653
0
  GTask *task = user_data;
654
0
  GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task);
655
0
  GSocketAddress *address;
656
0
  GError *error = NULL;
657
  
658
0
  address = g_socket_address_enumerator_next_finish (srv_enum->addr_enum,
659
0
                                                     result,
660
0
                                                     &error);
661
662
0
  if (error)
663
0
    {
664
0
      if (srv_enum->error == NULL)
665
0
        srv_enum->error = error;
666
0
      else
667
0
        g_error_free (error);
668
0
    }
669
670
0
  if (!address)
671
0
    {
672
0
      g_object_unref (srv_enum->addr_enum);
673
0
      srv_enum->addr_enum = NULL;
674
675
0
      next_async_have_targets (task);
676
0
    }
677
0
  else
678
0
    {
679
0
      g_task_return_pointer (task, address, g_object_unref);
680
0
      g_object_unref (task);
681
0
    }
682
0
}
683
684
static GSocketAddress *
685
g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator,
686
                                                  GAsyncResult              *result,
687
                                                  GError                   **error)
688
0
{
689
0
  return g_task_propagate_pointer (G_TASK (result), error);
690
0
}
691
692
static void
693
_g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
694
0
{
695
0
}
696
697
static void
698
g_network_service_address_enumerator_finalize (GObject *object)
699
0
{
700
0
  GNetworkServiceAddressEnumerator *srv_enum =
701
0
    G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
702
703
0
  if (srv_enum->srv)
704
0
    g_object_unref (srv_enum->srv);
705
706
0
  if (srv_enum->addr_enum)
707
0
    g_object_unref (srv_enum->addr_enum);
708
709
0
  if (srv_enum->resolver)
710
0
    g_object_unref (srv_enum->resolver);
711
712
0
  if (srv_enum->error)
713
0
    g_error_free (srv_enum->error);
714
715
0
  G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
716
0
}
717
718
static void
719
_g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *srvenum_class)
720
0
{
721
0
  GObjectClass *object_class = G_OBJECT_CLASS (srvenum_class);
722
0
  GSocketAddressEnumeratorClass *enumerator_class =
723
0
    G_SOCKET_ADDRESS_ENUMERATOR_CLASS (srvenum_class);
724
725
0
  enumerator_class->next        = g_network_service_address_enumerator_next;
726
0
  enumerator_class->next_async  = g_network_service_address_enumerator_next_async;
727
0
  enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
728
729
0
  object_class->finalize = g_network_service_address_enumerator_finalize;
730
0
}
731
732
static GSocketAddressEnumerator *
733
g_network_service_connectable_enumerate (GSocketConnectable *connectable)
734
0
{
735
0
  GNetworkServiceAddressEnumerator *srv_enum;
736
737
0
  srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
738
0
  srv_enum->srv = g_object_ref (G_NETWORK_SERVICE (connectable));
739
0
  srv_enum->resolver = g_resolver_get_default ();
740
0
  srv_enum->use_proxy = FALSE;
741
742
0
  return G_SOCKET_ADDRESS_ENUMERATOR (srv_enum);
743
0
}
744
745
static GSocketAddressEnumerator *
746
g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable)
747
0
{
748
0
  GSocketAddressEnumerator *addr_enum;
749
0
  GNetworkServiceAddressEnumerator *srv_enum;
750
751
0
  addr_enum = g_network_service_connectable_enumerate (connectable);
752
0
  srv_enum = G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (addr_enum);
753
0
  srv_enum->use_proxy = TRUE;
754
755
0
  return addr_enum;
756
0
}
757
758
static gchar *
759
g_network_service_connectable_to_string (GSocketConnectable *connectable)
760
0
{
761
0
  GNetworkService *service;
762
763
0
  service = G_NETWORK_SERVICE (connectable);
764
765
0
  return g_strdup_printf ("(%s, %s, %s, %s)", service->priv->service,
766
0
                          service->priv->protocol, service->priv->domain,
767
0
                          service->priv->scheme);
768
0
}