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"
43 * SECTION:gnetworkservice
44 * @short_description: a #GSocketConnectable for resolving SRV records
47 * Like #GNetworkAddress does with hostnames, #GNetworkService
48 * provides an easy way to resolve a SRV record, and then attempt to
49 * connect to one of the hosts that implements that service, handling
50 * service priority/weighting, multiple IP addresses, and multiple
53 * See #GSrvTarget for more information about SRV records, and see
54 * #GSocketConnectable for and example of using the connectable
61 * A #GSocketConnectable for resolving a SRV record and connecting to
65 struct _GNetworkServicePrivate
67 gchar *service, *protocol, *domain;
78 static void g_network_service_set_property (GObject *object,
82 static void g_network_service_get_property (GObject *object,
87 static void g_network_service_connectable_iface_init (GSocketConnectableIface *iface);
88 static GSocketAddressEnumerator *g_network_service_connectable_enumerate (GSocketConnectable *connectable);
90 G_DEFINE_TYPE_WITH_CODE (GNetworkService, g_network_service, G_TYPE_OBJECT,
91 G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE,
92 g_network_service_connectable_iface_init))
95 g_network_service_finalize (GObject *object)
97 GNetworkService *srv = G_NETWORK_SERVICE (object);
99 g_free (srv->priv->service);
100 g_free (srv->priv->protocol);
101 g_free (srv->priv->domain);
103 if (srv->priv->targets)
104 g_resolver_free_targets (srv->priv->targets);
106 G_OBJECT_CLASS (g_network_service_parent_class)->finalize (object);
110 g_network_service_class_init (GNetworkServiceClass *klass)
112 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
114 g_type_class_add_private (klass, sizeof (GNetworkServicePrivate));
116 gobject_class->set_property = g_network_service_set_property;
117 gobject_class->get_property = g_network_service_get_property;
118 gobject_class->finalize = g_network_service_finalize;
120 g_object_class_install_property (gobject_class, PROP_SERVICE,
121 g_param_spec_string ("service",
123 P_("Service name, eg \"ldap\""),
125 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
126 g_object_class_install_property (gobject_class, PROP_PROTOCOL,
127 g_param_spec_string ("protocol",
129 P_("Network protocol, eg \"tcp\""),
131 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
132 g_object_class_install_property (gobject_class, PROP_DOMAIN,
133 g_param_spec_string ("domain",
135 P_("Network domain, eg, \"example.com\""),
137 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
141 g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
143 connectable_iface->enumerate = g_network_service_connectable_enumerate;
147 g_network_service_init (GNetworkService *srv)
149 srv->priv = G_TYPE_INSTANCE_GET_PRIVATE (srv, G_TYPE_NETWORK_SERVICE,
150 GNetworkServicePrivate);
154 g_network_service_set_property (GObject *object,
159 GNetworkService *srv = G_NETWORK_SERVICE (object);
164 srv->priv->service = g_value_dup_string (value);
168 srv->priv->protocol = g_value_dup_string (value);
172 srv->priv->domain = g_value_dup_string (value);
176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
183 g_network_service_get_property (GObject *object,
188 GNetworkService *srv = G_NETWORK_SERVICE (object);
193 g_value_set_string (value, g_network_service_get_service (srv));
197 g_value_set_string (value, g_network_service_get_protocol (srv));
201 g_value_set_string (value, g_network_service_get_domain (srv));
205 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
212 * g_network_service_new:
213 * @service: the service type to look up (eg, "ldap")
214 * @protocol: the networking protocol to use for @service (eg, "tcp")
215 * @domain: the DNS domain to look up the service in
217 * Creates a new #GNetworkService representing the given @service,
218 * @protocol, and @domain. This will initially be unresolved; use the
219 * #GSocketConnectable interface to resolve it.
221 * Return value: a new #GNetworkService
226 g_network_service_new (const gchar *service,
227 const gchar *protocol,
230 return g_object_new (G_TYPE_NETWORK_SERVICE,
232 "protocol", protocol,
238 * g_network_service_get_service:
239 * @srv: a #GNetworkService
241 * Gets @srv's service name (eg, "ldap").
243 * Return value: @srv's service name
248 g_network_service_get_service (GNetworkService *srv)
250 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
252 return srv->priv->service;
256 * g_network_service_get_protocol:
257 * @srv: a #GNetworkService
259 * Gets @srv's protocol name (eg, "tcp").
261 * Return value: @srv's protocol name
266 g_network_service_get_protocol (GNetworkService *srv)
268 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
270 return srv->priv->protocol;
274 * g_network_service_get_domain:
275 * @srv: a #GNetworkService
277 * Gets the domain that @srv serves. This might be either UTF-8 or
278 * ASCII-encoded, depending on what @srv was created with.
280 * Return value: @srv's domain name
285 g_network_service_get_domain (GNetworkService *srv)
287 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
289 return srv->priv->domain;
292 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
293 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
296 GSocketAddressEnumerator parent_instance;
299 GNetworkService *srv;
300 GList *addrs, *a, *t;
304 /* For async operation */
305 GCancellable *cancellable;
306 GSimpleAsyncResult *result;
307 } GNetworkServiceAddressEnumerator;
310 GSocketAddressEnumeratorClass parent_class;
312 } GNetworkServiceAddressEnumeratorClass;
314 G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
317 g_network_service_address_enumerator_finalize (GObject *object)
319 GNetworkServiceAddressEnumerator *srv_enum =
320 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
322 g_object_unref (srv_enum->srv);
327 g_object_unref (srv_enum->a->data);
328 srv_enum->a = srv_enum->a->next;
330 g_list_free (srv_enum->addrs);
332 g_object_unref (srv_enum->resolver);
334 g_error_free (srv_enum->error);
336 G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
339 static GSocketAddress *
340 g_network_service_address_enumerator_next (GSocketAddressEnumerator *enumerator,
341 GCancellable *cancellable,
344 GNetworkServiceAddressEnumerator *srv_enum =
345 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
347 GSocketAddress *sockaddr;
349 /* If we haven't yet resolved srv, do that */
350 if (!srv_enum->srv->priv->targets)
354 targets = g_resolver_lookup_service (srv_enum->resolver,
355 srv_enum->srv->priv->service,
356 srv_enum->srv->priv->protocol,
357 srv_enum->srv->priv->domain,
362 if (!srv_enum->srv->priv->targets)
363 srv_enum->srv->priv->targets = targets;
364 srv_enum->t = srv_enum->srv->priv->targets;
367 /* Make sure we have a set of resolved addresses for the current
368 * target. When resolving the first target, we save the GError, if
369 * any. If any later target succeeds, we'll free the earlier error,
370 * but if we get to the last target without any of them resolving,
371 * we return that initial error.
375 /* Return if we're out of targets. */
380 g_propagate_error (error, srv_enum->error);
381 srv_enum->error = NULL;
385 target = srv_enum->t->data;
387 /* If we haven't resolved the addrs for the current target, do that */
388 if (!srv_enum->addrs)
392 error_p = (srv_enum->t == srv_enum->srv->priv->targets) ? &srv_enum->error : NULL;
393 srv_enum->addrs = g_resolver_lookup_by_name (srv_enum->resolver,
394 g_srv_target_get_hostname (target),
395 cancellable, error_p);
396 if (g_cancellable_set_error_if_cancelled (cancellable, error))
401 srv_enum->a = srv_enum->addrs;
404 g_error_free (srv_enum->error);
405 srv_enum->error = NULL;
410 /* Try the next target */
411 srv_enum->t = srv_enum->t->next;
415 while (!srv_enum->addrs);
417 /* Return the next address for this target. If it's the last one,
418 * advance the target counter.
420 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
421 g_srv_target_get_port (target));
422 g_object_unref (srv_enum->a->data);
423 srv_enum->a = srv_enum->a->next;
427 g_list_free (srv_enum->addrs);
428 srv_enum->addrs = NULL;
429 srv_enum->t = srv_enum->t->next;
435 static void next_async_resolved_targets (GObject *source_object,
436 GAsyncResult *result,
438 static void next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum);
439 static void next_async_resolved_addresses (GObject *source_object,
440 GAsyncResult *result,
442 static void next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum);
444 /* The async version is basically the same as the sync, except we have
445 * to split it into multiple functions.
448 g_network_service_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
449 GCancellable *cancellable,
450 GAsyncReadyCallback callback,
453 GNetworkServiceAddressEnumerator *srv_enum =
454 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
456 g_return_if_fail (srv_enum->result == NULL);
458 srv_enum->result = g_simple_async_result_new (G_OBJECT (enumerator),
460 g_network_service_address_enumerator_next_async);
461 srv_enum->cancellable = cancellable;
463 /* If we haven't yet resolved srv, do that */
464 if (!srv_enum->srv->priv->targets)
466 g_resolver_lookup_service_async (srv_enum->resolver,
467 srv_enum->srv->priv->service,
468 srv_enum->srv->priv->protocol,
469 srv_enum->srv->priv->domain,
471 next_async_resolved_targets,
475 next_async_have_targets (srv_enum);
479 next_async_resolved_targets (GObject *source_object,
480 GAsyncResult *result,
483 GNetworkServiceAddressEnumerator *srv_enum = user_data;
485 GError *error = NULL;
487 targets = g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
488 if (!srv_enum->srv->priv->targets)
492 GSimpleAsyncResult *simple = srv_enum->result;
494 srv_enum->result = NULL;
495 g_simple_async_result_set_from_error (simple, error);
496 g_error_free (error);
497 g_simple_async_result_complete (simple);
498 g_object_unref (simple);
502 srv_enum->srv->priv->targets = targets;
503 srv_enum->t = srv_enum->srv->priv->targets;
506 next_async_have_targets (srv_enum);
510 next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum)
514 /* Get the current target, check if we're already done. */
519 g_simple_async_result_set_from_error (srv_enum->result, srv_enum->error);
520 g_error_free (srv_enum->error);
521 srv_enum->error = NULL;
523 g_simple_async_result_complete_in_idle (srv_enum->result);
524 g_object_unref (srv_enum->result);
525 srv_enum->result = NULL;
528 target = srv_enum->t->data;
530 /* If we haven't resolved the addrs for the current target, do that */
531 if (!srv_enum->addrs)
533 g_resolver_lookup_by_name_async (srv_enum->resolver,
534 g_srv_target_get_hostname (target),
535 srv_enum->cancellable,
536 next_async_resolved_addresses,
540 next_async_have_addresses (srv_enum);
544 next_async_resolved_addresses (GObject *source_object,
545 GAsyncResult *result,
548 GNetworkServiceAddressEnumerator *srv_enum = user_data;
549 GError *error = NULL;
551 srv_enum->addrs = g_resolver_lookup_by_name_finish (srv_enum->resolver, result, &error);
554 srv_enum->a = srv_enum->addrs;
557 g_error_free (srv_enum->error);
558 srv_enum->error = NULL;
560 next_async_have_addresses (srv_enum);
564 if (g_cancellable_is_cancelled (srv_enum->cancellable))
566 GSimpleAsyncResult *simple = srv_enum->result;
568 srv_enum->result = NULL;
569 g_simple_async_result_set_from_error (srv_enum->result, error);
570 g_error_free (error);
571 g_simple_async_result_complete (simple);
572 g_object_unref (simple);
576 if (srv_enum->t == srv_enum->srv->priv->targets)
577 srv_enum->error = error;
579 g_error_free (error);
581 /* Try the next target */
582 srv_enum->t = srv_enum->t->next;
583 next_async_have_targets (srv_enum);
589 next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum)
591 GSocketAddress *sockaddr;
592 GSimpleAsyncResult *simple = srv_enum->result;
594 /* Return the next address for this target. If it's the last one,
595 * advance the target counter.
597 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
598 g_srv_target_get_port (srv_enum->t->data));
599 g_object_unref (srv_enum->a->data);
601 srv_enum->a = srv_enum->a->next;
604 g_list_free (srv_enum->addrs);
605 srv_enum->addrs = NULL;
606 srv_enum->t = srv_enum->t->next;
609 srv_enum->result = NULL;
610 g_simple_async_result_set_op_res_gpointer (simple, sockaddr, NULL);
611 g_simple_async_result_complete_in_idle (simple);
612 g_object_unref (simple);
615 static GSocketAddress *
616 g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
617 GAsyncResult *result,
620 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
621 GSocketAddress *sockaddr;
623 sockaddr = g_simple_async_result_get_op_res_gpointer (simple);
624 return sockaddr ? g_object_ref (sockaddr) : NULL;
628 _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
633 _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *addrenum_class)
635 GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
636 GSocketAddressEnumeratorClass *enumerator_class =
637 G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
639 enumerator_class->next = g_network_service_address_enumerator_next;
640 enumerator_class->next_async = g_network_service_address_enumerator_next_async;
641 enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
642 object_class->finalize = g_network_service_address_enumerator_finalize;
645 static GSocketAddressEnumerator *
646 g_network_service_connectable_enumerate (GSocketConnectable *connectable)
648 GNetworkServiceAddressEnumerator *srv_enum;
650 srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
651 srv_enum->srv = g_object_ref (connectable);
652 srv_enum->resolver = g_resolver_get_default ();
654 return (GSocketAddressEnumerator *)srv_enum;
657 #define __G_NETWORK_SERVICE_C__
658 #include "gioaliasdef.c"