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