/src/pango/subprojects/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 | | * 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 | | 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 | | g_network_service_finalize (GObject *object) |
94 | 0 | { |
95 | 0 | GNetworkService *srv = G_NETWORK_SERVICE (object); |
96 | |
|
97 | 0 | g_free (srv->priv->service); |
98 | 0 | g_free (srv->priv->protocol); |
99 | 0 | g_free (srv->priv->domain); |
100 | 0 | g_free (srv->priv->scheme); |
101 | |
|
102 | 0 | if (srv->priv->targets) |
103 | 0 | g_resolver_free_targets (srv->priv->targets); |
104 | |
|
105 | 0 | G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object); |
106 | 0 | } |
107 | | |
108 | | static void |
109 | | g_network_service_class_init (GNetworkServiceClass *klass) |
110 | 0 | { |
111 | 0 | GObjectClass *gobject_class = G_OBJECT_CLASS (klass); |
112 | |
|
113 | 0 | gobject_class->set_property = g_network_service_set_property; |
114 | 0 | gobject_class->get_property = g_network_service_get_property; |
115 | 0 | 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 | 0 | g_object_class_install_property (gobject_class, PROP_SERVICE, |
125 | 0 | g_param_spec_string ("service", NULL, NULL, |
126 | 0 | NULL, |
127 | 0 | G_PARAM_READWRITE | |
128 | 0 | G_PARAM_CONSTRUCT_ONLY | |
129 | 0 | G_PARAM_STATIC_STRINGS)); |
130 | | |
131 | | /** |
132 | | * GNetworkService:protocol: |
133 | | * |
134 | | * Network protocol, for example `tcp`. |
135 | | * |
136 | | * Since: 2.22 |
137 | | */ |
138 | 0 | g_object_class_install_property (gobject_class, PROP_PROTOCOL, |
139 | 0 | g_param_spec_string ("protocol", NULL, NULL, |
140 | 0 | NULL, |
141 | 0 | G_PARAM_READWRITE | |
142 | 0 | G_PARAM_CONSTRUCT_ONLY | |
143 | 0 | G_PARAM_STATIC_STRINGS)); |
144 | | |
145 | | /** |
146 | | * GNetworkService:domain: |
147 | | * |
148 | | * Network domain, for example `example.com`. |
149 | | * |
150 | | * Since: 2.22 |
151 | | */ |
152 | 0 | g_object_class_install_property (gobject_class, PROP_DOMAIN, |
153 | 0 | g_param_spec_string ("domain", NULL, NULL, |
154 | 0 | NULL, |
155 | 0 | G_PARAM_READWRITE | |
156 | 0 | G_PARAM_CONSTRUCT_ONLY | |
157 | 0 | 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 | 0 | g_object_class_install_property (gobject_class, PROP_DOMAIN, |
167 | 0 | g_param_spec_string ("scheme", NULL, NULL, |
168 | 0 | NULL, |
169 | 0 | G_PARAM_READWRITE | |
170 | 0 | G_PARAM_STATIC_STRINGS)); |
171 | |
|
172 | 0 | } |
173 | | |
174 | | static void |
175 | | g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface) |
176 | 0 | { |
177 | 0 | connectable_iface->enumerate = g_network_service_connectable_enumerate; |
178 | 0 | connectable_iface->proxy_enumerate = g_network_service_connectable_proxy_enumerate; |
179 | 0 | connectable_iface->to_string = g_network_service_connectable_to_string; |
180 | 0 | } |
181 | | |
182 | | static void |
183 | | g_network_service_init (GNetworkService *srv) |
184 | 0 | { |
185 | 0 | srv->priv = g_network_service_get_instance_private (srv); |
186 | 0 | } |
187 | | |
188 | | static void |
189 | | g_network_service_set_property (GObject *object, |
190 | | guint prop_id, |
191 | | const GValue *value, |
192 | | GParamSpec *pspec) |
193 | 0 | { |
194 | 0 | GNetworkService *srv = G_NETWORK_SERVICE (object); |
195 | |
|
196 | 0 | switch (prop_id) |
197 | 0 | { |
198 | 0 | case PROP_SERVICE: |
199 | 0 | srv->priv->service = g_value_dup_string (value); |
200 | 0 | break; |
201 | | |
202 | 0 | case PROP_PROTOCOL: |
203 | 0 | srv->priv->protocol = g_value_dup_string (value); |
204 | 0 | break; |
205 | | |
206 | 0 | case PROP_DOMAIN: |
207 | 0 | srv->priv->domain = g_value_dup_string (value); |
208 | 0 | 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 | 0 | } |
218 | 0 | } |
219 | | |
220 | | static void |
221 | | g_network_service_get_property (GObject *object, |
222 | | guint prop_id, |
223 | | GValue *value, |
224 | | GParamSpec *pspec) |
225 | 0 | { |
226 | 0 | GNetworkService *srv = G_NETWORK_SERVICE (object); |
227 | |
|
228 | 0 | switch (prop_id) |
229 | 0 | { |
230 | 0 | case PROP_SERVICE: |
231 | 0 | g_value_set_string (value, g_network_service_get_service (srv)); |
232 | 0 | break; |
233 | | |
234 | 0 | case PROP_PROTOCOL: |
235 | 0 | g_value_set_string (value, g_network_service_get_protocol (srv)); |
236 | 0 | break; |
237 | | |
238 | 0 | case PROP_DOMAIN: |
239 | 0 | g_value_set_string (value, g_network_service_get_domain (srv)); |
240 | 0 | 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 | 0 | } |
250 | 0 | } |
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 | | g_network_service_new (const gchar *service, |
268 | | const gchar *protocol, |
269 | | const gchar *domain) |
270 | 0 | { |
271 | 0 | return g_object_new (G_TYPE_NETWORK_SERVICE, |
272 | 0 | "service", service, |
273 | 0 | "protocol", protocol, |
274 | 0 | "domain", domain, |
275 | 0 | NULL); |
276 | 0 | } |
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 | | g_network_service_get_service (GNetworkService *srv) |
290 | 0 | { |
291 | 0 | g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL); |
292 | | |
293 | 0 | return srv->priv->service; |
294 | 0 | } |
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 | | g_network_service_get_protocol (GNetworkService *srv) |
308 | 0 | { |
309 | 0 | g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL); |
310 | | |
311 | 0 | return srv->priv->protocol; |
312 | 0 | } |
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 | | g_network_service_get_domain (GNetworkService *srv) |
327 | 0 | { |
328 | 0 | g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL); |
329 | | |
330 | 0 | return srv->priv->domain; |
331 | 0 | } |
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 | | g_network_service_get_scheme (GNetworkService *srv) |
346 | 0 | { |
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 | 0 | else |
352 | 0 | return srv->priv->service; |
353 | 0 | } |
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 | | g_network_service_set_scheme (GNetworkService *srv, |
367 | | const gchar *scheme) |
368 | 0 | { |
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 | 0 | } |
376 | | |
377 | | static GList * |
378 | | g_network_service_fallback_targets (GNetworkService *srv) |
379 | 0 | { |
380 | 0 | GSrvTarget *target; |
381 | 0 | gboolean has_port; |
382 | 0 | guint16 port; |
383 | |
|
384 | 0 | has_port = g_getservbyname_ntohs (srv->priv->service, "tcp", &port); |
385 | |
|
386 | 0 | #ifdef HAVE_ENDSERVENT |
387 | 0 | endservent (); |
388 | 0 | #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 | 0 | } |
396 | | |
397 | 0 | #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ()) |
398 | 0 | #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 | | G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR) |
420 | | |
421 | | static GSocketAddress * |
422 | | g_network_service_address_enumerator_next (GSocketAddressEnumerator *enumerator, |
423 | | GCancellable *cancellable, |
424 | | GError **error) |
425 | 0 | { |
426 | 0 | 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 | 0 | { |
433 | 0 | 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 | 0 | cancellable, &my_error); |
441 | 0 | if (!targets && g_error_matches (my_error, G_RESOLVER_ERROR, |
442 | 0 | G_RESOLVER_ERROR_NOT_FOUND)) |
443 | 0 | { |
444 | 0 | targets = g_network_service_fallback_targets (srv_enum->srv); |
445 | 0 | if (targets) |
446 | 0 | g_clear_error (&my_error); |
447 | 0 | } |
448 | |
|
449 | 0 | if (my_error) |
450 | 0 | { |
451 | 0 | g_propagate_error (error, my_error); |
452 | 0 | return NULL; |
453 | 0 | } |
454 | | |
455 | 0 | srv_enum->srv->priv->targets = targets; |
456 | 0 | srv_enum->t = srv_enum->srv->priv->targets; |
457 | 0 | } |
458 | | |
459 | | /* Delegate to GNetworkAddress */ |
460 | 0 | do |
461 | 0 | { |
462 | 0 | if (srv_enum->addr_enum == NULL && srv_enum->t) |
463 | 0 | { |
464 | 0 | GError *my_error = NULL; |
465 | 0 | gchar *uri; |
466 | 0 | gchar *hostname; |
467 | 0 | 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 | 0 | { |
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 | 0 | "Received invalid hostname '%s' from GSrvTarget", |
480 | 0 | g_srv_target_get_hostname (target)); |
481 | 0 | continue; |
482 | 0 | } |
483 | | |
484 | 0 | uri = g_uri_join (G_URI_FLAGS_NONE, |
485 | 0 | g_network_service_get_scheme (srv_enum->srv), |
486 | 0 | NULL, |
487 | 0 | hostname, |
488 | 0 | g_srv_target_get_port (target), |
489 | 0 | "", |
490 | 0 | NULL, |
491 | 0 | 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 | 0 | &my_error); |
497 | 0 | g_free (uri); |
498 | |
|
499 | 0 | if (addr == NULL) |
500 | 0 | { |
501 | 0 | if (srv_enum->error == NULL) |
502 | 0 | srv_enum->error = my_error; |
503 | 0 | else |
504 | 0 | g_error_free (my_error); |
505 | 0 | continue; |
506 | 0 | } |
507 | | |
508 | 0 | if (srv_enum->use_proxy) |
509 | 0 | srv_enum->addr_enum = g_socket_connectable_proxy_enumerate (addr); |
510 | 0 | else |
511 | 0 | srv_enum->addr_enum = g_socket_connectable_enumerate (addr); |
512 | 0 | g_object_unref (addr); |
513 | 0 | } |
514 | | |
515 | 0 | if (srv_enum->addr_enum) |
516 | 0 | { |
517 | 0 | GError *my_error = NULL; |
518 | |
|
519 | 0 | ret = g_socket_address_enumerator_next (srv_enum->addr_enum, |
520 | 0 | cancellable, |
521 | 0 | &my_error); |
522 | |
|
523 | 0 | if (my_error) |
524 | 0 | { |
525 | 0 | if (srv_enum->error == NULL) |
526 | 0 | srv_enum->error = my_error; |
527 | 0 | else |
528 | 0 | g_error_free (my_error); |
529 | 0 | } |
530 | |
|
531 | 0 | if (!ret) |
532 | 0 | { |
533 | 0 | g_object_unref (srv_enum->addr_enum); |
534 | 0 | srv_enum->addr_enum = NULL; |
535 | 0 | } |
536 | 0 | } |
537 | 0 | } |
538 | 0 | while (srv_enum->addr_enum == NULL && srv_enum->t); |
539 | | |
540 | 0 | if (ret == NULL && srv_enum->error) |
541 | 0 | { |
542 | 0 | g_propagate_error (error, srv_enum->error); |
543 | 0 | srv_enum->error = NULL; |
544 | 0 | } |
545 | |
|
546 | 0 | return ret; |
547 | 0 | } |
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 | | g_network_service_address_enumerator_next_async (GSocketAddressEnumerator *enumerator, |
559 | | GCancellable *cancellable, |
560 | | GAsyncReadyCallback callback, |
561 | | gpointer user_data) |
562 | 0 | { |
563 | 0 | GNetworkServiceAddressEnumerator *srv_enum = |
564 | 0 | G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator); |
565 | 0 | 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 | 0 | { |
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 | 0 | cancellable, |
578 | 0 | next_async_resolved_targets, |
579 | 0 | task); |
580 | 0 | } |
581 | 0 | else |
582 | 0 | next_async_have_targets (task); |
583 | 0 | } |
584 | | |
585 | | static void |
586 | | next_async_resolved_targets (GObject *source_object, |
587 | | GAsyncResult *result, |
588 | | gpointer user_data) |
589 | 0 | { |
590 | 0 | GTask *task = user_data; |
591 | 0 | GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task); |
592 | 0 | GError *error = NULL; |
593 | 0 | GList *targets; |
594 | |
|
595 | 0 | targets = g_resolver_lookup_service_finish (srv_enum->resolver, |
596 | 0 | result, &error); |
597 | |
|
598 | 0 | if (!targets && g_error_matches (error, G_RESOLVER_ERROR, |
599 | 0 | G_RESOLVER_ERROR_NOT_FOUND)) |
600 | 0 | { |
601 | 0 | targets = g_network_service_fallback_targets (srv_enum->srv); |
602 | 0 | if (targets) |
603 | 0 | g_clear_error (&error); |
604 | 0 | } |
605 | |
|
606 | 0 | if (error) |
607 | 0 | { |
608 | 0 | g_task_return_error (task, error); |
609 | 0 | g_object_unref (task); |
610 | 0 | } |
611 | 0 | else |
612 | 0 | { |
613 | 0 | srv_enum->t = srv_enum->srv->priv->targets = targets; |
614 | 0 | next_async_have_targets (task); |
615 | 0 | } |
616 | 0 | } |
617 | | |
618 | | static void |
619 | | next_async_have_targets (GTask *task) |
620 | 0 | { |
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 | 0 | { |
626 | 0 | 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 | 0 | else |
636 | 0 | srv_enum->addr_enum = g_socket_connectable_enumerate (addr); |
637 | |
|
638 | 0 | g_object_unref (addr); |
639 | 0 | } |
640 | |
|
641 | 0 | if (srv_enum->addr_enum) |
642 | 0 | { |
643 | 0 | g_socket_address_enumerator_next_async (srv_enum->addr_enum, |
644 | 0 | g_task_get_cancellable (task), |
645 | 0 | next_async_have_address, |
646 | 0 | task); |
647 | 0 | } |
648 | 0 | else |
649 | 0 | { |
650 | 0 | if (srv_enum->error) |
651 | 0 | { |
652 | 0 | g_task_return_error (task, srv_enum->error); |
653 | 0 | srv_enum->error = NULL; |
654 | 0 | } |
655 | 0 | else |
656 | 0 | g_task_return_pointer (task, NULL, NULL); |
657 | |
|
658 | 0 | g_object_unref (task); |
659 | 0 | } |
660 | 0 | } |
661 | | |
662 | | static void |
663 | | next_async_have_address (GObject *source_object, |
664 | | GAsyncResult *result, |
665 | | gpointer user_data) |
666 | 0 | { |
667 | 0 | GTask *task = user_data; |
668 | 0 | GNetworkServiceAddressEnumerator *srv_enum = g_task_get_source_object (task); |
669 | 0 | GSocketAddress *address; |
670 | 0 | GError *error = NULL; |
671 | | |
672 | 0 | address = g_socket_address_enumerator_next_finish (srv_enum->addr_enum, |
673 | 0 | result, |
674 | 0 | &error); |
675 | |
|
676 | 0 | if (error) |
677 | 0 | { |
678 | 0 | if (srv_enum->error == NULL) |
679 | 0 | srv_enum->error = error; |
680 | 0 | else |
681 | 0 | g_error_free (error); |
682 | 0 | } |
683 | |
|
684 | 0 | if (!address) |
685 | 0 | { |
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 | 0 | } |
691 | 0 | else |
692 | 0 | { |
693 | 0 | g_task_return_pointer (task, address, g_object_unref); |
694 | 0 | g_object_unref (task); |
695 | 0 | } |
696 | 0 | } |
697 | | |
698 | | static GSocketAddress * |
699 | | g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator, |
700 | | GAsyncResult *result, |
701 | | GError **error) |
702 | 0 | { |
703 | 0 | return g_task_propagate_pointer (G_TASK (result), error); |
704 | 0 | } |
705 | | |
706 | | static void |
707 | | _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator) |
708 | 0 | { |
709 | 0 | } |
710 | | |
711 | | static void |
712 | | g_network_service_address_enumerator_finalize (GObject *object) |
713 | 0 | { |
714 | 0 | 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 | | _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *srvenum_class) |
734 | 0 | { |
735 | 0 | GObjectClass *object_class = G_OBJECT_CLASS (srvenum_class); |
736 | 0 | 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 | | g_network_service_connectable_enumerate (GSocketConnectable *connectable) |
748 | 0 | { |
749 | 0 | 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 | 0 | } |
758 | | |
759 | | static GSocketAddressEnumerator * |
760 | | g_network_service_connectable_proxy_enumerate (GSocketConnectable *connectable) |
761 | 0 | { |
762 | 0 | GSocketAddressEnumerator *addr_enum; |
763 | 0 | 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 | 0 | } |
771 | | |
772 | | static gchar * |
773 | | g_network_service_connectable_to_string (GSocketConnectable *connectable) |
774 | 0 | { |
775 | 0 | 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 | 0 | } |