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\""),
126 G_PARAM_CONSTRUCT_ONLY |
127 G_PARAM_STATIC_STRINGS));
128 g_object_class_install_property (gobject_class, PROP_PROTOCOL,
129 g_param_spec_string ("protocol",
131 P_("Network protocol, eg \"tcp\""),
134 G_PARAM_CONSTRUCT_ONLY |
135 G_PARAM_STATIC_STRINGS));
136 g_object_class_install_property (gobject_class, PROP_DOMAIN,
137 g_param_spec_string ("domain",
139 P_("Network domain, eg, \"example.com\""),
142 G_PARAM_CONSTRUCT_ONLY |
143 G_PARAM_STATIC_STRINGS));
147 g_network_service_connectable_iface_init (GSocketConnectableIface *connectable_iface)
149 connectable_iface->enumerate = g_network_service_connectable_enumerate;
153 g_network_service_init (GNetworkService *srv)
155 srv->priv = G_TYPE_INSTANCE_GET_PRIVATE (srv, G_TYPE_NETWORK_SERVICE,
156 GNetworkServicePrivate);
160 g_network_service_set_property (GObject *object,
165 GNetworkService *srv = G_NETWORK_SERVICE (object);
170 srv->priv->service = g_value_dup_string (value);
174 srv->priv->protocol = g_value_dup_string (value);
178 srv->priv->domain = g_value_dup_string (value);
182 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
188 g_network_service_get_property (GObject *object,
193 GNetworkService *srv = G_NETWORK_SERVICE (object);
198 g_value_set_string (value, g_network_service_get_service (srv));
202 g_value_set_string (value, g_network_service_get_protocol (srv));
206 g_value_set_string (value, g_network_service_get_domain (srv));
210 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
216 * g_network_service_new:
217 * @service: the service type to look up (eg, "ldap")
218 * @protocol: the networking protocol to use for @service (eg, "tcp")
219 * @domain: the DNS domain to look up the service in
221 * Creates a new #GNetworkService representing the given @service,
222 * @protocol, and @domain. This will initially be unresolved; use the
223 * #GSocketConnectable interface to resolve it.
225 * Return value: a new #GNetworkService
230 g_network_service_new (const gchar *service,
231 const gchar *protocol,
234 return g_object_new (G_TYPE_NETWORK_SERVICE,
236 "protocol", protocol,
242 * g_network_service_get_service:
243 * @srv: a #GNetworkService
245 * Gets @srv's service name (eg, "ldap").
247 * Return value: @srv's service name
252 g_network_service_get_service (GNetworkService *srv)
254 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
256 return srv->priv->service;
260 * g_network_service_get_protocol:
261 * @srv: a #GNetworkService
263 * Gets @srv's protocol name (eg, "tcp").
265 * Return value: @srv's protocol name
270 g_network_service_get_protocol (GNetworkService *srv)
272 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
274 return srv->priv->protocol;
278 * g_network_service_get_domain:
279 * @srv: a #GNetworkService
281 * Gets the domain that @srv serves. This might be either UTF-8 or
282 * ASCII-encoded, depending on what @srv was created with.
284 * Return value: @srv's domain name
289 g_network_service_get_domain (GNetworkService *srv)
291 g_return_val_if_fail (G_IS_NETWORK_SERVICE (srv), NULL);
293 return srv->priv->domain;
296 #define G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR (_g_network_service_address_enumerator_get_type ())
297 #define G_NETWORK_SERVICE_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, GNetworkServiceAddressEnumerator))
300 GSocketAddressEnumerator parent_instance;
303 GNetworkService *srv;
304 GList *addrs, *a, *t;
308 /* For async operation */
309 GCancellable *cancellable;
310 GSimpleAsyncResult *result;
311 } GNetworkServiceAddressEnumerator;
314 GSocketAddressEnumeratorClass parent_class;
316 } GNetworkServiceAddressEnumeratorClass;
318 G_DEFINE_TYPE (GNetworkServiceAddressEnumerator, _g_network_service_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR)
321 g_network_service_address_enumerator_finalize (GObject *object)
323 GNetworkServiceAddressEnumerator *srv_enum =
324 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (object);
326 g_object_unref (srv_enum->srv);
331 g_object_unref (srv_enum->a->data);
332 srv_enum->a = srv_enum->a->next;
334 g_list_free (srv_enum->addrs);
336 g_object_unref (srv_enum->resolver);
338 g_error_free (srv_enum->error);
340 G_OBJECT_CLASS (_g_network_service_address_enumerator_parent_class)->finalize (object);
343 static GSocketAddress *
344 g_network_service_address_enumerator_next (GSocketAddressEnumerator *enumerator,
345 GCancellable *cancellable,
348 GNetworkServiceAddressEnumerator *srv_enum =
349 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
351 GSocketAddress *sockaddr;
353 /* If we haven't yet resolved srv, do that */
354 if (!srv_enum->srv->priv->targets)
358 targets = g_resolver_lookup_service (srv_enum->resolver,
359 srv_enum->srv->priv->service,
360 srv_enum->srv->priv->protocol,
361 srv_enum->srv->priv->domain,
366 if (!srv_enum->srv->priv->targets)
367 srv_enum->srv->priv->targets = targets;
368 srv_enum->t = srv_enum->srv->priv->targets;
371 /* Make sure we have a set of resolved addresses for the current
372 * target. When resolving the first target, we save the GError, if
373 * any. If any later target succeeds, we'll free the earlier error,
374 * but if we get to the last target without any of them resolving,
375 * we return that initial error.
379 /* Return if we're out of targets. */
384 g_propagate_error (error, srv_enum->error);
385 srv_enum->error = NULL;
389 target = srv_enum->t->data;
391 /* If we haven't resolved the addrs for the current target, do that */
392 if (!srv_enum->addrs)
396 error_p = (srv_enum->t == srv_enum->srv->priv->targets) ? &srv_enum->error : NULL;
397 srv_enum->addrs = g_resolver_lookup_by_name (srv_enum->resolver,
398 g_srv_target_get_hostname (target),
399 cancellable, error_p);
400 if (g_cancellable_set_error_if_cancelled (cancellable, error))
405 srv_enum->a = srv_enum->addrs;
408 g_error_free (srv_enum->error);
409 srv_enum->error = NULL;
414 /* Try the next target */
415 srv_enum->t = srv_enum->t->next;
419 while (!srv_enum->addrs);
421 /* Return the next address for this target. If it's the last one,
422 * advance the target counter.
424 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
425 g_srv_target_get_port (target));
426 g_object_unref (srv_enum->a->data);
427 srv_enum->a = srv_enum->a->next;
431 g_list_free (srv_enum->addrs);
432 srv_enum->addrs = NULL;
433 srv_enum->t = srv_enum->t->next;
439 static void next_async_resolved_targets (GObject *source_object,
440 GAsyncResult *result,
442 static void next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum);
443 static void next_async_resolved_addresses (GObject *source_object,
444 GAsyncResult *result,
446 static void next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum);
448 /* The async version is basically the same as the sync, except we have
449 * to split it into multiple functions.
452 g_network_service_address_enumerator_next_async (GSocketAddressEnumerator *enumerator,
453 GCancellable *cancellable,
454 GAsyncReadyCallback callback,
457 GNetworkServiceAddressEnumerator *srv_enum =
458 G_NETWORK_SERVICE_ADDRESS_ENUMERATOR (enumerator);
460 g_return_if_fail (srv_enum->result == NULL);
462 srv_enum->result = g_simple_async_result_new (G_OBJECT (enumerator),
464 g_network_service_address_enumerator_next_async);
465 srv_enum->cancellable = cancellable;
467 /* If we haven't yet resolved srv, do that */
468 if (!srv_enum->srv->priv->targets)
470 g_resolver_lookup_service_async (srv_enum->resolver,
471 srv_enum->srv->priv->service,
472 srv_enum->srv->priv->protocol,
473 srv_enum->srv->priv->domain,
475 next_async_resolved_targets,
479 next_async_have_targets (srv_enum);
483 next_async_resolved_targets (GObject *source_object,
484 GAsyncResult *result,
487 GNetworkServiceAddressEnumerator *srv_enum = user_data;
489 GError *error = NULL;
491 targets = g_resolver_lookup_service_finish (srv_enum->resolver, result, &error);
492 if (!srv_enum->srv->priv->targets)
496 GSimpleAsyncResult *simple = srv_enum->result;
498 srv_enum->result = NULL;
499 g_simple_async_result_set_from_error (simple, error);
500 g_error_free (error);
501 g_simple_async_result_complete (simple);
502 g_object_unref (simple);
506 srv_enum->srv->priv->targets = targets;
507 srv_enum->t = srv_enum->srv->priv->targets;
510 next_async_have_targets (srv_enum);
514 next_async_have_targets (GNetworkServiceAddressEnumerator *srv_enum)
518 /* Get the current target, check if we're already done. */
523 g_simple_async_result_set_from_error (srv_enum->result, srv_enum->error);
524 g_error_free (srv_enum->error);
525 srv_enum->error = NULL;
527 g_simple_async_result_complete_in_idle (srv_enum->result);
528 g_object_unref (srv_enum->result);
529 srv_enum->result = NULL;
532 target = srv_enum->t->data;
534 /* If we haven't resolved the addrs for the current target, do that */
535 if (!srv_enum->addrs)
537 g_resolver_lookup_by_name_async (srv_enum->resolver,
538 g_srv_target_get_hostname (target),
539 srv_enum->cancellable,
540 next_async_resolved_addresses,
544 next_async_have_addresses (srv_enum);
548 next_async_resolved_addresses (GObject *source_object,
549 GAsyncResult *result,
552 GNetworkServiceAddressEnumerator *srv_enum = user_data;
553 GError *error = NULL;
555 srv_enum->addrs = g_resolver_lookup_by_name_finish (srv_enum->resolver, result, &error);
558 srv_enum->a = srv_enum->addrs;
561 g_error_free (srv_enum->error);
562 srv_enum->error = NULL;
564 next_async_have_addresses (srv_enum);
568 if (g_cancellable_is_cancelled (srv_enum->cancellable))
570 GSimpleAsyncResult *simple = srv_enum->result;
572 srv_enum->result = NULL;
573 g_simple_async_result_set_from_error (srv_enum->result, error);
574 g_error_free (error);
575 g_simple_async_result_complete (simple);
576 g_object_unref (simple);
580 if (srv_enum->t == srv_enum->srv->priv->targets)
581 srv_enum->error = error;
583 g_error_free (error);
585 /* Try the next target */
586 srv_enum->t = srv_enum->t->next;
587 next_async_have_targets (srv_enum);
593 next_async_have_addresses (GNetworkServiceAddressEnumerator *srv_enum)
595 GSocketAddress *sockaddr;
596 GSimpleAsyncResult *simple = srv_enum->result;
598 /* Return the next address for this target. If it's the last one,
599 * advance the target counter.
601 sockaddr = g_inet_socket_address_new (srv_enum->a->data,
602 g_srv_target_get_port (srv_enum->t->data));
603 g_object_unref (srv_enum->a->data);
605 srv_enum->a = srv_enum->a->next;
608 g_list_free (srv_enum->addrs);
609 srv_enum->addrs = NULL;
610 srv_enum->t = srv_enum->t->next;
613 srv_enum->result = NULL;
614 g_simple_async_result_set_op_res_gpointer (simple, sockaddr, NULL);
615 g_simple_async_result_complete_in_idle (simple);
616 g_object_unref (simple);
619 static GSocketAddress *
620 g_network_service_address_enumerator_next_finish (GSocketAddressEnumerator *enumerator,
621 GAsyncResult *result,
624 GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result);
625 GSocketAddress *sockaddr;
627 if (g_simple_async_result_propagate_error (simple, error))
630 sockaddr = g_simple_async_result_get_op_res_gpointer (simple);
631 return sockaddr ? g_object_ref (sockaddr) : NULL;
635 _g_network_service_address_enumerator_init (GNetworkServiceAddressEnumerator *enumerator)
640 _g_network_service_address_enumerator_class_init (GNetworkServiceAddressEnumeratorClass *addrenum_class)
642 GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class);
643 GSocketAddressEnumeratorClass *enumerator_class =
644 G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class);
646 enumerator_class->next = g_network_service_address_enumerator_next;
647 enumerator_class->next_async = g_network_service_address_enumerator_next_async;
648 enumerator_class->next_finish = g_network_service_address_enumerator_next_finish;
649 object_class->finalize = g_network_service_address_enumerator_finalize;
652 static GSocketAddressEnumerator *
653 g_network_service_connectable_enumerate (GSocketConnectable *connectable)
655 GNetworkServiceAddressEnumerator *srv_enum;
657 srv_enum = g_object_new (G_TYPE_NETWORK_SERVICE_ADDRESS_ENUMERATOR, NULL);
658 srv_enum->srv = g_object_ref (connectable);
659 srv_enum->resolver = g_resolver_get_default ();
661 return (GSocketAddressEnumerator *)srv_enum;
664 #define __G_NETWORK_SERVICE_C__
665 #include "gioaliasdef.c"