1 /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
3 /* GIO - GLib Input, Output and Streaming Library
5 * Copyright (C) 2008 Red Hat, Inc.
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 of the License, or (at your option) any later version.
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.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
27 #include "gnetworkservice.h"
28 #include "gcancellable.h"
29 #include "ginetaddress.h"
30 #include "ginetsocketaddress.h"
31 #include "gresolver.h"
32 #include "gsimpleasyncresult.h"
33 #include "gsocketaddressenumerator.h"
34 #include "gsocketconnectable.h"
35 #include "gsrvtarget.h"
42 * SECTION:gnetworkservice
43 * @short_description: A GSocketConnectable for resolving SRV records
46 * Like #GNetworkAddress does with hostnames, #GNetworkService
47 * provides an easy way to resolve a SRV record, and then attempt to
48 * connect to one of the hosts that implements that service, handling
49 * service priority/weighting, multiple IP addresses, and multiple
52 * See #GSrvTarget for more information about SRV records, and see
53 * #GSocketConnectable for and example of using the connectable
60 * A #GSocketConnectable for resolving a SRV record and connecting to
64 struct _GNetworkServicePrivate
66 gchar *service, *protocol, *domain;
77 static void g_network_service_set_property (GObject *object,
81 static void g_network_service_get_property (GObject *object,
86 static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface);
87 static GSocketAddressEnumerator *g_network_service_connectable_enumerate (GSocketConnectable *connectable);
89 G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
90 G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
91 g_network_service_connectable_iface_init))
94 g_network_service_finalize (GObject *object)
96 GNetworkService *srv = G_NETWORK_SERVICE (object);
98 g_free (srv->priv->service);
99 g_free (srv->priv->protocol);
100 g_free (srv->priv->domain);
102 if (srv->priv->targets)
103 g_resolver_free_targets (srv->priv->targets);
105 G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
109 g_network_service_class_init (GNetworkServiceClass *klass)
111 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
113 g_type_class_add_private (klass, sizeof (GNetworkServicePrivate));
115 gobject_class->set_property = g_network_service_set_property;
116 gobject_class->get_property = g_network_service_get_property;
117 gobject_class->finalize = g_network_service_finalize;
119 g_object_class_install_property (gobject_class, PROP_SERVICE,
120 g_param_spec_string ("service",
122 P_("Service name, eg \"ldap\""),
125 G_PARAM_CONSTRUCT_ONLY |
126 G_PARAM_STATIC_STRINGS));
127 g_object_class_install_property (gobject_class, PROP_PROTOCOL,
128 g_param_spec_string ("protocol",
130 P_("Network protocol, eg \"tcp\""),
133 G_PARAM_CONSTRUCT_ONLY |
134 G_PARAM_STATIC_STRINGS));
135 g_object_class_install_property (gobject_class, PROP_DOMAIN,
136 g_param_spec_string ("domain",
138 P_("Network domain, eg, \"example.com\""),
141 G_PARAM_CONSTRUCT_ONLY |
142 G_PARAM_STATIC_STRINGS));
146 g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
148 connectable_iface->enumerate = g_network_service_connectable_enumerate;
152 g_network_service_init (GNetworkService *srv)
154 srv->priv = G_TYPE_INSTANCE_GET_PRIVATE (srv, G_TYPE_NETWORK_SERVICE,
155 GNetworkServicePrivate);
159 g_network_service_set_property (GObject *object,
164 GNetworkService *srv = G_NETWORK_SERVICE (object);
169 srv->priv->service = g_value_dup_string (value);
173 srv->priv->protocol = g_value_dup_string (value);
177 srv->priv->domain = g_value_dup_string (value);
181 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
187 g_network_service_get_property (GObject *object,
192 GNetworkService *srv = G_NETWORK_SERVICE (object);
197 g_value_set_string (value, g_network_service_get_service (srv));
201 g_value_set_string (value, g_network_service_get_protocol (srv));
205 g_value_set_string (value, g_network_service_get_domain (srv));
209 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215 * g_network_service_new:
216 * @service: the service type to look up (eg, "ldap")
217 * @protocol: the networking protocol to use for @service (eg, "tcp")
218 * @domain: the DNS domain to look up the service in
220 * Creates a new #GNetworkService representing the given @service,
221 * @protocol, and @domain. This will initially be unresolved; use the
222 * #GSocketConnectable interface to resolve it.
224 * Return value: a new #GNetworkService
229 g_network_service_new (const gchar *service,
230 const gchar *protocol,
233 return g_object_new (G_TYPE_NETWORK_SERVICE,
235 "protocol", protocol,
241 * g_network_service_get_service:
242 * @srv: a #GNetworkService
244 * Gets @srv's service name (eg, "ldap").
246 * Return value: @srv's service name
251 g_network_service_get_service (GNetworkService *srv)
253 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
255 return srv->priv->service;
259 * g_network_service_get_protocol:
260 * @srv: a #GNetworkService
262 * Gets @srv's protocol name (eg, "tcp").
264 * Return value: @srv's protocol name
269 g_network_service_get_protocol (GNetworkService *srv)
271 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
273 return srv->priv->protocol;
277 * g_network_service_get_domain:
278 * @srv: a #GNetworkService
280 * Gets the domain that @srv serves. This might be either UTF-8 or
281 * ASCII-encoded, depending on what @srv was created with.
283 * Return value: @srv's domain name
288 g_network_service_get_domain (GNetworkService *srv)
290 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
292 return srv->priv->domain;
295 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
296 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
299 GSocketAddressEnumerator parent_instance;
302 GNetworkService *srv;
303 GList *addrs, *a, *t;
307 /* For async operation */
308 GCancellable *cancellable;
309 GSimpleAsyncResult *result;
310 } GNetworkServiceAddressEnumerator;
313 GSocketAddressEnumeratorClass parent_class;
315 } GNetworkServiceAddressEnumeratorClass;
317 G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
320 g_network_service_address_enumerator_finalize (GObject *object)
322 GNetworkServiceAddressEnumerator *srv_enum =
323 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
325 g_object_unref (srv_enum->srv);
330 g_object_unref (srv_enum->a->data);
331 srv_enum->a = srv_enum->a->next;
333 g_list_free (srv_enum->addrs);
335 g_object_unref (srv_enum->resolver);
337 g_error_free (srv_enum->error);
339 G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
342 static GSocketAddress *
343 g_network_service_address_enumerator_next (GSocketAddressEnumerator *enumerator,
344 GCancellable *cancellable,
347 GNetworkServiceAddressEnumerator *srv_enum =
348 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
350 GSocketAddress *sockaddr;
352 /* If we haven't yet resolved srv, do that */
353 if (!srv_enum->srv->priv->targets)
357 targets = g_resolver_lookup_service (srv_enum->resolver,
358 srv_enum->srv->priv->service,
359 srv_enum->srv->priv->protocol,
360 srv_enum->srv->priv->domain,
365 if (!srv_enum->srv->priv->targets)
366 srv_enum->srv->priv->targets = targets;
367 srv_enum->t = srv_enum->srv->priv->targets;
370 /* Make sure we have a set of resolved addresses for the current
371 * target. When resolving the first target, we save the GError, if
372 * any. If any later target succeeds, we'll free the earlier error,
373 * but if we get to the last target without any of them resolving,
374 * we return that initial error.
378 /* Return if we're out of targets. */
383 g_propagate_error (error, srv_enum->error);
384 srv_enum->error = NULL;
388 target = srv_enum->t->data;
390 /* If we haven't resolved the addrs for the current target, do that */
391 if (!srv_enum->addrs)
395 error_p = (srv_enum->t == srv_enum->srv->priv->targets) ? &srv_enum->error : NULL;
396 srv_enum->addrs = g_resolver_lookup_by_name (srv_enum->resolver,
397 g_srv_target_get_hostname (target),
398 cancellable, error_p);
399 if (g_cancellable_set_error_if_cancelled (cancellable, error))
404 srv_enum->a = srv_enum->addrs;
407 g_error_free (srv_enum->error);
408 srv_enum->error = NULL;
413 /* Try the next target */
414 srv_enum->t = srv_enum->t->next;
418 while (!srv_enum->addrs);
420 /* Return the next address for this target. If it's the last one,
421 * advance the target counter.
423 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
424 g_srv_target_get_port (target));
425 g_object_unref (srv_enum->a->data);
426 srv_enum->a = srv_enum->a->next;
430 g_list_free (srv_enum->addrs);
431 srv_enum->addrs = NULL;
432 srv_enum->t = srv_enum->t->next;
438 static void next_async_resolved_targets (GObject *source_object,
439 GAsyncResult *result,
441 static void next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum);
442 static void next_async_resolved_addresses (GObject *source_object,
443 GAsyncResult *result,
445 static void next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum);
447 /* The async version is basically the same as the sync, except we have
448 * to split it into multiple functions.
451 g_network_service_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
452 GCancellable *cancellable,
453 GAsyncReadyCallback callback,
456 GNetworkServiceAddressEnumerator *srv_enum =
457 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
459 g_return_if_fail (srv_enum->result == NULL);
461 srv_enum->result = g_simple_async_result_new (G_OBJECT (enumerator),
463 g_network_service_address_enumerator_next_async);
464 srv_enum->cancellable = cancellable;
466 /* If we haven't yet resolved srv, do that */
467 if (!srv_enum->srv->priv->targets)
469 g_resolver_lookup_service_async (srv_enum->resolver,
470 srv_enum->srv->priv->service,
471 srv_enum->srv->priv->protocol,
472 srv_enum->srv->priv->domain,
474 next_async_resolved_targets,
478 next_async_have_targets (srv_enum);
482 next_async_resolved_targets (GObject *source_object,
483 GAsyncResult *result,
486 GNetworkServiceAddressEnumerator *srv_enum = user_data;
488 GError *error = NULL;
490 targets = g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
491 if (!srv_enum->srv->priv->targets)
495 GSimpleAsyncResult *simple = srv_enum->result;
497 srv_enum->result = NULL;
498 g_simple_async_result_set_from_error (simple, error);
499 g_error_free (error);
500 g_simple_async_result_complete (simple);
501 g_object_unref (simple);
505 srv_enum->srv->priv->targets = targets;
506 srv_enum->t = srv_enum->srv->priv->targets;
509 next_async_have_targets (srv_enum);
513 next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum)
517 /* Get the current target, check if we're already done. */
522 g_simple_async_result_set_from_error (srv_enum->result, srv_enum->error);
523 g_error_free (srv_enum->error);
524 srv_enum->error = NULL;
526 g_simple_async_result_complete_in_idle (srv_enum->result);
527 g_object_unref (srv_enum->result);
528 srv_enum->result = NULL;
531 target = srv_enum->t->data;
533 /* If we haven't resolved the addrs for the current target, do that */
534 if (!srv_enum->addrs)
536 g_resolver_lookup_by_name_async (srv_enum->resolver,
537 g_srv_target_get_hostname (target),
538 srv_enum->cancellable,
539 next_async_resolved_addresses,
543 next_async_have_addresses (srv_enum);
547 next_async_resolved_addresses (GObject *source_object,
548 GAsyncResult *result,
551 GNetworkServiceAddressEnumerator *srv_enum = user_data;
552 GError *error = NULL;
554 srv_enum->addrs = g_resolver_lookup_by_name_finish (srv_enum->resolver, result, &error);
557 srv_enum->a = srv_enum->addrs;
560 g_error_free (srv_enum->error);
561 srv_enum->error = NULL;
563 next_async_have_addresses (srv_enum);
567 if (g_cancellable_is_cancelled (srv_enum->cancellable))
569 GSimpleAsyncResult *simple = srv_enum->result;
571 srv_enum->result = NULL;
572 g_simple_async_result_set_from_error (srv_enum->result, error);
573 g_error_free (error);
574 g_simple_async_result_complete (simple);
575 g_object_unref (simple);
579 if (srv_enum->t == srv_enum->srv->priv->targets)
580 srv_enum->error = error;
582 g_error_free (error);
584 /* Try the next target */
585 srv_enum->t = srv_enum->t->next;
586 next_async_have_targets (srv_enum);
592 next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum)
594 GSocketAddress *sockaddr;
595 GSimpleAsyncResult *simple = srv_enum->result;
597 /* Return the next address for this target. If it's the last one,
598 * advance the target counter.
600 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
601 g_srv_target_get_port (srv_enum->t->data));
602 g_object_unref (srv_enum->a->data);
604 srv_enum->a = srv_enum->a->next;
607 g_list_free (srv_enum->addrs);
608 srv_enum->addrs = NULL;
609 srv_enum->t = srv_enum->t->next;
612 srv_enum->result = NULL;
613 g_simple_async_result_set_op_res_gpointer (simple, sockaddr, NULL);
614 g_simple_async_result_complete_in_idle (simple);
615 g_object_unref (simple);
618 static GSocketAddress *
619 g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
620 GAsyncResult *result,
623 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
624 GSocketAddress *sockaddr;
626 if (g_simple_async_result_propagate_error (simple, error))
629 sockaddr = g_simple_async_result_get_op_res_gpointer (simple);
630 return sockaddr ? g_object_ref (sockaddr) : NULL;
634 _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
639 _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *addrenum_class)
641 GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
642 GSocketAddressEnumeratorClass *enumerator_class =
643 G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
645 enumerator_class->next = g_network_service_address_enumerator_next;
646 enumerator_class->next_async = g_network_service_address_enumerator_next_async;
647 enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
648 object_class->finalize = g_network_service_address_enumerator_finalize;
651 static GSocketAddressEnumerator *
652 g_network_service_connectable_enumerate (GSocketConnectable *connectable)
654 GNetworkServiceAddressEnumerator *srv_enum;
656 srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
657 srv_enum->srv = g_object_ref (connectable);
658 srv_enum->resolver = g_resolver_get_default ();
660 return (GSocketAddressEnumerator *)srv_enum;