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