| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* GIO - GLib Input, Output and Streaming Library
 | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Copyright (C) 2008 Red Hat, Inc. | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |  * Copyright (C) 2018 Igalia S.L. | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2022-05-18 09:12:45 +01:00
										 |  |  |  |  * SPDX-License-Identifier: LGPL-2.1-or-later | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * This library is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  |  * modify it under the terms of the GNU Lesser General Public | 
					
						
							|  |  |  |  |  * License as published by the Free Software Foundation; either | 
					
						
							| 
									
										
										
										
											2017-05-27 18:21:30 +02:00
										 |  |  |  |  * version 2.1 of the License, or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * This library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
					
						
							|  |  |  |  |  * Lesser General Public License for more details. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * You should have received a copy of the GNU Lesser General | 
					
						
							| 
									
										
										
										
											2014-01-23 12:58:29 +01:00
										 |  |  |  |  * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include "config.h"
 | 
					
						
							|  |  |  |  | #include <glib.h>
 | 
					
						
							|  |  |  |  | #include "glibintl.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-15 20:43:02 +02:00
										 |  |  |  | #include <stdlib.h>
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | #include "gnetworkaddress.h"
 | 
					
						
							|  |  |  |  | #include "gasyncresult.h"
 | 
					
						
							|  |  |  |  | #include "ginetaddress.h"
 | 
					
						
							|  |  |  |  | #include "ginetsocketaddress.h"
 | 
					
						
							| 
									
										
										
										
											2009-04-27 17:35:04 -04:00
										 |  |  |  | #include "gnetworkingprivate.h"
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:45:32 -04:00
										 |  |  |  | #include "gproxyaddressenumerator.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | #include "gresolver.h"
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  | #include "gtask.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | #include "gsocketaddressenumerator.h"
 | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  | #include "gioerror.h"
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | #include "gsocketconnectable.h"
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #include <string.h>
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  | /* As recommended by RFC 8305 this is the time it waits for a following
 | 
					
						
							|  |  |  |  |    DNS response to come in (ipv4 waiting on ipv6 generally) | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | #define HAPPY_EYEBALLS_RESOLUTION_DELAY_MS 50
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | /**
 | 
					
						
							| 
									
										
										
										
											2023-10-23 13:43:07 +01:00
										 |  |  |  |  * GNetworkAddress: | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-10-23 13:43:07 +01:00
										 |  |  |  |  * `GNetworkAddress` provides an easy way to resolve a hostname and | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * then attempt to connect to that host, handling the possibility of | 
					
						
							|  |  |  |  |  * multiple IP addresses and multiple address families. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |  * The enumeration results of resolved addresses *may* be cached as long | 
					
						
							|  |  |  |  |  * as this object is kept alive which may have unexpected results if | 
					
						
							|  |  |  |  |  * alive for too long. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-10-23 13:43:07 +01:00
										 |  |  |  |  * See [iface@Gio.SocketConnectable] for an example of using the connectable | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * interface. | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | struct _GNetworkAddressPrivate { | 
					
						
							|  |  |  |  |   gchar *hostname; | 
					
						
							|  |  |  |  |   guint16 port; | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   GList *cached_sockaddrs; | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |   gchar *scheme; | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   gint64 resolver_serial; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | enum { | 
					
						
							|  |  |  |  |   PROP_0, | 
					
						
							|  |  |  |  |   PROP_HOSTNAME, | 
					
						
							|  |  |  |  |   PROP_PORT, | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |   PROP_SCHEME, | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | }; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void g_network_address_set_property (GObject      *object, | 
					
						
							|  |  |  |  |                                             guint         prop_id, | 
					
						
							|  |  |  |  |                                             const GValue *value, | 
					
						
							|  |  |  |  |                                             GParamSpec   *pspec); | 
					
						
							|  |  |  |  | static void g_network_address_get_property (GObject      *object, | 
					
						
							|  |  |  |  |                                             guint         prop_id, | 
					
						
							|  |  |  |  |                                             GValue       *value, | 
					
						
							|  |  |  |  |                                             GParamSpec   *pspec); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:45:32 -04:00
										 |  |  |  | static void                      g_network_address_connectable_iface_init       (GSocketConnectableIface *iface); | 
					
						
							|  |  |  |  | static GSocketAddressEnumerator *g_network_address_connectable_enumerate        (GSocketConnectable      *connectable); | 
					
						
							|  |  |  |  | static GSocketAddressEnumerator	*g_network_address_connectable_proxy_enumerate  (GSocketConnectable      *connectable); | 
					
						
							| 
									
										
										
										
											2015-10-04 15:24:24 +01:00
										 |  |  |  | static gchar                    *g_network_address_connectable_to_string        (GSocketConnectable      *connectable); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | G_DEFINE_TYPE_WITH_CODE (GNetworkAddress, g_network_address, G_TYPE_OBJECT, | 
					
						
							| 
									
										
										
										
											2013-06-11 00:29:58 +01:00
										 |  |  |  |                          G_ADD_PRIVATE (GNetworkAddress) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |                          G_IMPLEMENT_INTERFACE (G_TYPE_SOCKET_CONNECTABLE, | 
					
						
							|  |  |  |  |                                                 g_network_address_connectable_iface_init)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_finalize (GObject *object) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *addr = G_NETWORK_ADDRESS (object); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_free (addr->priv->hostname); | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |   g_free (addr->priv->scheme); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   G_OBJECT_CLASS (g_network_address_parent_class)->finalize (object); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_class_init (GNetworkAddressClass *klass) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GObjectClass *gobject_class = G_OBJECT_CLASS (klass); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   gobject_class->set_property = g_network_address_set_property; | 
					
						
							|  |  |  |  |   gobject_class->get_property = g_network_address_get_property; | 
					
						
							|  |  |  |  |   gobject_class->finalize = g_network_address_finalize; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-29 13:23:09 +00:00
										 |  |  |  |   /**
 | 
					
						
							|  |  |  |  |    * GNetworkAddress:hostname: | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * Hostname to resolve. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * Since: 2.22 | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |   g_object_class_install_property (gobject_class, PROP_HOSTNAME, | 
					
						
							| 
									
										
										
										
											2023-04-28 01:59:26 +02:00
										 |  |  |  |                                    g_param_spec_string ("hostname", NULL, NULL, | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |                                                         NULL, | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |                                                         G_PARAM_READWRITE | | 
					
						
							|  |  |  |  |                                                         G_PARAM_CONSTRUCT_ONLY | | 
					
						
							|  |  |  |  |                                                         G_PARAM_STATIC_STRINGS)); | 
					
						
							| 
									
										
										
										
											2023-11-29 13:23:09 +00:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /**
 | 
					
						
							|  |  |  |  |    * GNetworkAddress:port: | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * Network port. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * Since: 2.22 | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |   g_object_class_install_property (gobject_class, PROP_PORT, | 
					
						
							| 
									
										
										
										
											2023-04-28 01:59:26 +02:00
										 |  |  |  |                                    g_param_spec_uint ("port", NULL, NULL, | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |                                                       0, 65535, 0, | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |                                                       G_PARAM_READWRITE | | 
					
						
							|  |  |  |  |                                                       G_PARAM_CONSTRUCT_ONLY | | 
					
						
							|  |  |  |  |                                                       G_PARAM_STATIC_STRINGS)); | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-29 13:23:09 +00:00
										 |  |  |  |   /**
 | 
					
						
							|  |  |  |  |    * GNetworkAddress:scheme: | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * URI scheme. | 
					
						
							|  |  |  |  |    * | 
					
						
							|  |  |  |  |    * Since: 2.22 | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |   g_object_class_install_property (gobject_class, PROP_SCHEME, | 
					
						
							| 
									
										
										
										
											2023-04-28 01:59:26 +02:00
										 |  |  |  |                                    g_param_spec_string ("scheme", NULL, NULL, | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |                                                         NULL, | 
					
						
							|  |  |  |  |                                                         G_PARAM_READWRITE | | 
					
						
							|  |  |  |  |                                                         G_PARAM_CONSTRUCT_ONLY | | 
					
						
							|  |  |  |  |                                                         G_PARAM_STATIC_STRINGS)); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_connectable_iface_init (GSocketConnectableIface *connectable_iface) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   connectable_iface->enumerate  = g_network_address_connectable_enumerate; | 
					
						
							| 
									
										
										
										
											2010-08-10 15:45:32 -04:00
										 |  |  |  |   connectable_iface->proxy_enumerate = g_network_address_connectable_proxy_enumerate; | 
					
						
							| 
									
										
										
										
											2015-10-04 15:24:24 +01:00
										 |  |  |  |   connectable_iface->to_string = g_network_address_connectable_to_string; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_init (GNetworkAddress *addr) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2013-06-24 15:43:04 +01:00
										 |  |  |  |   addr->priv = g_network_address_get_instance_private (addr); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_set_property (GObject      *object, | 
					
						
							|  |  |  |  |                                 guint         prop_id, | 
					
						
							|  |  |  |  |                                 const GValue *value, | 
					
						
							|  |  |  |  |                                 GParamSpec   *pspec) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *addr = G_NETWORK_ADDRESS (object); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |   switch (prop_id) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |     case PROP_HOSTNAME: | 
					
						
							| 
									
										
										
										
											2010-07-26 18:40:17 -04:00
										 |  |  |  |       g_free (addr->priv->hostname); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |       addr->priv->hostname = g_value_dup_string (value); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     case PROP_PORT: | 
					
						
							|  |  |  |  |       addr->priv->port = g_value_get_uint (value); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |     case PROP_SCHEME: | 
					
						
							| 
									
										
										
										
											2014-07-14 15:37:06 +02:00
										 |  |  |  |       g_free (addr->priv->scheme); | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |       addr->priv->scheme = g_value_dup_string (value); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     default: | 
					
						
							|  |  |  |  |       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_get_property (GObject    *object, | 
					
						
							|  |  |  |  |                                 guint       prop_id, | 
					
						
							|  |  |  |  |                                 GValue     *value, | 
					
						
							|  |  |  |  |                                 GParamSpec *pspec) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *addr = G_NETWORK_ADDRESS (object); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   switch (prop_id) | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     case PROP_HOSTNAME: | 
					
						
							|  |  |  |  |       g_value_set_string (value, addr->priv->hostname); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     case PROP_PORT: | 
					
						
							|  |  |  |  |       g_value_set_uint (value, addr->priv->port); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |     case PROP_SCHEME: | 
					
						
							|  |  |  |  |       g_value_set_string (value, addr->priv->scheme); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     default: | 
					
						
							|  |  |  |  |       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); | 
					
						
							|  |  |  |  |       break; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-09 15:15:10 -04:00
										 |  |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |  * inet_addresses_to_inet_socket_addresses: | 
					
						
							|  |  |  |  |  * @addresses: (transfer full): #GList of #GInetAddress | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |  * Returns: (transfer full): #GList of #GInetSocketAddress | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  | static GList * | 
					
						
							|  |  |  |  | inet_addresses_to_inet_socket_addresses (GNetworkAddress *addr, | 
					
						
							|  |  |  |  |                                          GList           *addresses) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   GList *a, *socket_addresses = NULL; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   for (a = addresses; a; a = a->next) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |       GSocketAddress *sockaddr = g_inet_socket_address_new (a->data, addr->priv->port); | 
					
						
							|  |  |  |  |       socket_addresses = g_list_append (socket_addresses, g_steal_pointer (&sockaddr)); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |       g_object_unref (a->data); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |   g_list_free (addresses); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   return socket_addresses; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  | /*
 | 
					
						
							|  |  |  |  |  * g_network_address_set_cached_addresses: | 
					
						
							|  |  |  |  |  * @addr: A #GNetworkAddress | 
					
						
							|  |  |  |  |  * @addresses: (transfer full): List of #GInetAddress or #GInetSocketAddress | 
					
						
							|  |  |  |  |  * @resolver_serial: Serial of #GResolver used | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Consumes @addresses and uses them to replace the current internal list. | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_set_cached_addresses (GNetworkAddress *addr, | 
					
						
							|  |  |  |  |                                         GList           *addresses, | 
					
						
							|  |  |  |  |                                         guint64          resolver_serial) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_assert (addresses != NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (addr->priv->cached_sockaddrs) | 
					
						
							|  |  |  |  |     g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (G_IS_INET_SOCKET_ADDRESS (addresses->data)) | 
					
						
							|  |  |  |  |     addr->priv->cached_sockaddrs = g_steal_pointer (&addresses); | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     addr->priv->cached_sockaddrs = inet_addresses_to_inet_socket_addresses (addr, g_steal_pointer (&addresses)); | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |   addr->priv->resolver_serial = resolver_serial; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | static gboolean | 
					
						
							|  |  |  |  | g_network_address_parse_sockaddr (GNetworkAddress *addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GSocketAddress *sockaddr; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   g_assert (addr->priv->cached_sockaddrs == NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-08-20 21:36:25 -04:00
										 |  |  |  |   sockaddr = g_inet_socket_address_new_from_string (addr->priv->hostname, | 
					
						
							|  |  |  |  |                                                     addr->priv->port); | 
					
						
							|  |  |  |  |   if (sockaddr) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |       addr->priv->cached_sockaddrs = g_list_append (addr->priv->cached_sockaddrs, sockaddr); | 
					
						
							| 
									
										
										
										
											2013-08-20 21:36:25 -04:00
										 |  |  |  |       return TRUE; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |     return FALSE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_new: | 
					
						
							|  |  |  |  |  * @hostname: the hostname | 
					
						
							|  |  |  |  |  * @port: the port | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Creates a new #GSocketConnectable for connecting to the given | 
					
						
							|  |  |  |  |  * @hostname and @port. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-11-23 12:53:03 -05:00
										 |  |  |  |  * Note that depending on the configuration of the machine, a | 
					
						
							|  |  |  |  |  * @hostname of `localhost` may refer to the IPv4 loopback address | 
					
						
							|  |  |  |  |  * only, or to both IPv4 and IPv6; use | 
					
						
							|  |  |  |  |  * g_network_address_new_loopback() to create a #GNetworkAddress that | 
					
						
							|  |  |  |  |  * is guaranteed to resolve to both addresses. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-02-19 19:35:23 -05:00
										 |  |  |  |  * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.22 | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | GSocketConnectable * | 
					
						
							|  |  |  |  | g_network_address_new (const gchar *hostname, | 
					
						
							|  |  |  |  |                        guint16      port) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   return g_object_new (G_TYPE_NETWORK_ADDRESS, | 
					
						
							|  |  |  |  |                        "hostname", hostname, | 
					
						
							|  |  |  |  |                        "port", port, | 
					
						
							|  |  |  |  |                        NULL); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-23 12:53:03 -05:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_new_loopback: | 
					
						
							|  |  |  |  |  * @port: the port | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Creates a new #GSocketConnectable for connecting to the local host | 
					
						
							|  |  |  |  |  * over a loopback connection to the given @port. This is intended for | 
					
						
							|  |  |  |  |  * use in connecting to local services which may be running on IPv4 or | 
					
						
							|  |  |  |  |  * IPv6. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * The connectable will return IPv4 and IPv6 loopback addresses, | 
					
						
							|  |  |  |  |  * regardless of how the host resolves `localhost`. By contrast, | 
					
						
							|  |  |  |  |  * g_network_address_new() will often only return an IPv4 address when | 
					
						
							|  |  |  |  |  * resolving `localhost`, and an IPv6 address for `localhost6`. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * g_network_address_get_hostname() will always return `localhost` for | 
					
						
							| 
									
										
										
										
											2019-03-07 17:30:31 +00:00
										 |  |  |  |  * a #GNetworkAddress created with this constructor. | 
					
						
							| 
									
										
										
										
											2014-11-23 12:53:03 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Returns: (transfer full) (type GNetworkAddress): the new #GNetworkAddress | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.44 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | GSocketConnectable * | 
					
						
							|  |  |  |  | g_network_address_new_loopback (guint16 port) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *addr; | 
					
						
							|  |  |  |  |   GList *addrs = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   addr = g_object_new (G_TYPE_NETWORK_ADDRESS, | 
					
						
							|  |  |  |  |                        "hostname", "localhost", | 
					
						
							|  |  |  |  |                        "port", port, | 
					
						
							|  |  |  |  |                        NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET6)); | 
					
						
							|  |  |  |  |   addrs = g_list_append (addrs, g_inet_address_new_loopback (AF_INET)); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   g_network_address_set_cached_addresses (addr, g_steal_pointer (&addrs), 0); | 
					
						
							| 
									
										
										
										
											2014-11-23 12:53:03 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return G_SOCKET_CONNECTABLE (addr); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_parse: | 
					
						
							|  |  |  |  |  * @host_and_port: the hostname and optionally a port | 
					
						
							|  |  |  |  |  * @default_port: the default port if not in @host_and_port | 
					
						
							|  |  |  |  |  * @error: a pointer to a #GError, or %NULL | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Creates a new #GSocketConnectable for connecting to the given | 
					
						
							|  |  |  |  |  * @hostname and @port. May fail and return %NULL in case | 
					
						
							|  |  |  |  |  * parsing @host_and_port fails. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2010-09-24 18:24:41 -03:00
										 |  |  |  |  * @host_and_port may be in any of a number of recognised formats; an IPv6 | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |  * address, an IPv4 address, or a domain name (in which case a DNS | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  * lookup is performed). Quoting with [] is supported for all address | 
					
						
							|  |  |  |  |  * types. A port override may be specified in the usual way with a | 
					
						
							| 
									
										
										
										
											2011-09-03 19:49:19 -04:00
										 |  |  |  |  * colon. | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * If no port is specified in @host_and_port then @default_port will be | 
					
						
							|  |  |  |  |  * used as the port number to connect to. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  * In general, @host_and_port is expected to be provided by the user | 
					
						
							| 
									
										
										
										
											2018-02-28 12:24:41 +01:00
										 |  |  |  |  * (allowing them to give the hostname, and a port override if necessary) | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  * and @default_port is expected to be provided by the application. | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2011-09-03 19:49:19 -04:00
										 |  |  |  |  * (The port component of @host_and_port can also be specified as a | 
					
						
							|  |  |  |  |  * service name rather than as a numeric port, but this functionality | 
					
						
							|  |  |  |  |  * is deprecated, because it depends on the contents of /etc/services, | 
					
						
							|  |  |  |  |  * which is generally quite sparse on platforms other than Linux.) | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2015-05-09 23:45:03 -07:00
										 |  |  |  |  * Returns: (transfer full) (type GNetworkAddress): the new | 
					
						
							|  |  |  |  |  *   #GNetworkAddress, or %NULL on error | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.22 | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  | GSocketConnectable * | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  | g_network_address_parse (const gchar  *host_and_port, | 
					
						
							|  |  |  |  |                          guint16       default_port, | 
					
						
							|  |  |  |  |                          GError      **error) | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  | { | 
					
						
							|  |  |  |  |   GSocketConnectable *connectable; | 
					
						
							|  |  |  |  |   const gchar *port; | 
					
						
							|  |  |  |  |   guint16 portnum; | 
					
						
							|  |  |  |  |   gchar *name; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_return_val_if_fail (host_and_port != NULL, NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   port = NULL; | 
					
						
							|  |  |  |  |   if (host_and_port[0] == '[') | 
					
						
							|  |  |  |  |     /* escaped host part (to allow, eg. "[2001:db8::1]:888") */ | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       const gchar *end; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       end = strchr (host_and_port, ']'); | 
					
						
							|  |  |  |  |       if (end == NULL) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							| 
									
										
										
										
											2016-09-30 05:47:15 +02:00
										 |  |  |  |                        _("Hostname “%s” contains “[” but not “]”"), host_and_port); | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |           return NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (end[1] == '\0') | 
					
						
							|  |  |  |  |         port = NULL; | 
					
						
							|  |  |  |  |       else if (end[1] == ':') | 
					
						
							|  |  |  |  |         port = &end[2]; | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							|  |  |  |  |                        "The ']' character (in hostname '%s') must come at the" | 
					
						
							|  |  |  |  |                        " end or be immediately followed by ':' and a port", | 
					
						
							|  |  |  |  |                        host_and_port); | 
					
						
							|  |  |  |  |           return NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       name = g_strndup (host_and_port + 1, end - host_and_port - 1); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else if ((port = strchr (host_and_port, ':'))) | 
					
						
							|  |  |  |  |     /* string has a ':' in it */ | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       /* skip ':' */ | 
					
						
							|  |  |  |  |       port++; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (strchr (port, ':')) | 
					
						
							|  |  |  |  |         /* more than one ':' in string */ | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* this is actually an unescaped IPv6 address */ | 
					
						
							|  |  |  |  |           name = g_strdup (host_and_port); | 
					
						
							|  |  |  |  |           port = NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         name = g_strndup (host_and_port, port - host_and_port - 1); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     /* plain hostname, no port */ | 
					
						
							|  |  |  |  |     name = g_strdup (host_and_port); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (port != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       if (port[0] == '\0') | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							|  |  |  |  |                        "If a ':' character is given, it must be followed by a " | 
					
						
							|  |  |  |  |                        "port (in hostname '%s').", host_and_port); | 
					
						
							|  |  |  |  |           g_free (name); | 
					
						
							|  |  |  |  |           return NULL; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       else if ('0' <= port[0] && port[0] <= '9') | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           char *end; | 
					
						
							|  |  |  |  |           long value; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           value = strtol (port, &end, 10); | 
					
						
							|  |  |  |  |           if (*end != '\0' || value < 0 || value > G_MAXUINT16) | 
					
						
							|  |  |  |  |             { | 
					
						
							|  |  |  |  |               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							|  |  |  |  |                            "Invalid numeric port '%s' specified in hostname '%s'", | 
					
						
							|  |  |  |  |                            port, host_and_port); | 
					
						
							|  |  |  |  |               g_free (name); | 
					
						
							|  |  |  |  |               return NULL; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |           portnum = value; | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       else | 
					
						
							|  |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2023-08-11 12:08:42 +02:00
										 |  |  |  |           if (!g_getservbyname_ntohs (port, "tcp", &portnum)) | 
					
						
							| 
									
										
										
										
											2009-05-14 10:53:53 +02:00
										 |  |  |  |             { | 
					
						
							|  |  |  |  |               g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							|  |  |  |  |                            "Unknown service '%s' specified in hostname '%s'", | 
					
						
							|  |  |  |  |                            port, host_and_port); | 
					
						
							|  |  |  |  | #ifdef HAVE_ENDSERVENT
 | 
					
						
							|  |  |  |  |               endservent (); | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  |               g_free (name); | 
					
						
							|  |  |  |  |               return NULL; | 
					
						
							|  |  |  |  |             } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | #ifdef HAVE_ENDSERVENT
 | 
					
						
							|  |  |  |  |           endservent (); | 
					
						
							|  |  |  |  | #endif
 | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       /* No port in host_and_port */ | 
					
						
							|  |  |  |  |       portnum = default_port; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   connectable = g_network_address_new (name, portnum); | 
					
						
							|  |  |  |  |   g_free (name); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return connectable; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_parse_uri: | 
					
						
							|  |  |  |  |  * @uri: the hostname and optionally a port | 
					
						
							|  |  |  |  |  * @default_port: The default port if none is found in the URI | 
					
						
							|  |  |  |  |  * @error: a pointer to a #GError, or %NULL | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Creates a new #GSocketConnectable for connecting to the given | 
					
						
							|  |  |  |  |  * @uri. May fail and return %NULL in case parsing @uri fails. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Using this rather than g_network_address_new() or | 
					
						
							| 
									
										
										
										
											2012-02-19 16:39:15 +00:00
										 |  |  |  |  * g_network_address_parse() allows #GSocketClient to determine | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |  * when to use application-specific proxy protocols. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2015-05-09 23:45:03 -07:00
										 |  |  |  |  * Returns: (transfer full) (type GNetworkAddress): the new | 
					
						
							|  |  |  |  |  *   #GNetworkAddress, or %NULL on error | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.26 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | GSocketConnectable * | 
					
						
							|  |  |  |  | g_network_address_parse_uri (const gchar  *uri, | 
					
						
							|  |  |  |  |     			     guint16       default_port, | 
					
						
							|  |  |  |  | 			     GError      **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2020-07-07 12:58:33 +04:00
										 |  |  |  |   GSocketConnectable *conn = NULL; | 
					
						
							|  |  |  |  |   gchar *scheme = NULL; | 
					
						
							|  |  |  |  |   gchar *hostname = NULL; | 
					
						
							|  |  |  |  |   gint port; | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-06 15:14:26 +01:00
										 |  |  |  |   if (!g_uri_split_network (uri, G_URI_FLAGS_NONE, | 
					
						
							| 
									
										
										
										
											2020-07-07 12:58:33 +04:00
										 |  |  |  |                             &scheme, &hostname, &port, NULL)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, | 
					
						
							|  |  |  |  |                    "Invalid URI ‘%s’", uri); | 
					
						
							|  |  |  |  |       return NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-07 12:58:33 +04:00
										 |  |  |  |   if (port <= 0) | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |     port = default_port; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   conn = g_object_new (G_TYPE_NETWORK_ADDRESS, | 
					
						
							|  |  |  |  |                        "hostname", hostname, | 
					
						
							| 
									
										
										
										
											2020-07-07 12:58:33 +04:00
										 |  |  |  |                        "port", (guint) port, | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |                        "scheme", scheme, | 
					
						
							|  |  |  |  |                        NULL); | 
					
						
							|  |  |  |  |   g_free (scheme); | 
					
						
							|  |  |  |  |   g_free (hostname); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return conn; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_get_hostname: | 
					
						
							|  |  |  |  |  * @addr: a #GNetworkAddress | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Gets @addr's hostname. This might be either UTF-8 or ASCII-encoded, | 
					
						
							|  |  |  |  |  * depending on what @addr was created with. | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-02-19 19:35:23 -05:00
										 |  |  |  |  * Returns: @addr's hostname | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.22 | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | const gchar * | 
					
						
							|  |  |  |  | g_network_address_get_hostname (GNetworkAddress *addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return addr->priv->hostname; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_get_port: | 
					
						
							|  |  |  |  |  * @addr: a #GNetworkAddress | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Gets @addr's port number | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2014-02-19 19:35:23 -05:00
										 |  |  |  |  * Returns: @addr's port (which may be 0) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.22 | 
					
						
							| 
									
										
										
										
											2009-05-27 18:20:08 -04:00
										 |  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | guint16 | 
					
						
							|  |  |  |  | g_network_address_get_port (GNetworkAddress *addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), 0); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return addr->priv->port; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  | /**
 | 
					
						
							|  |  |  |  |  * g_network_address_get_scheme: | 
					
						
							|  |  |  |  |  * @addr: a #GNetworkAddress | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Gets @addr's scheme | 
					
						
							|  |  |  |  |  * | 
					
						
							| 
									
										
										
										
											2020-10-18 11:15:54 +03:00
										 |  |  |  |  * Returns: (nullable): @addr's scheme (%NULL if not built from URI) | 
					
						
							| 
									
										
										
										
											2010-08-10 15:23:37 -04:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Since: 2.26 | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | const gchar * | 
					
						
							|  |  |  |  | g_network_address_get_scheme (GNetworkAddress *addr) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_return_val_if_fail (G_IS_NETWORK_ADDRESS (addr), NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return addr->priv->scheme; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | #define G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (_g_network_address_address_enumerator_get_type ())
 | 
					
						
							|  |  |  |  | #define G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, GNetworkAddressAddressEnumerator))
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  | typedef enum { | 
					
						
							|  |  |  |  |   RESOLVE_STATE_NONE = 0, | 
					
						
							|  |  |  |  |   RESOLVE_STATE_WAITING_ON_IPV4 = 1 << 0, | 
					
						
							|  |  |  |  |   RESOLVE_STATE_WAITING_ON_IPV6 = 1 << 1, | 
					
						
							|  |  |  |  | } ResolveState; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | typedef struct { | 
					
						
							|  |  |  |  |   GSocketAddressEnumerator parent_instance; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   GNetworkAddress *addr; /* (owned) */ | 
					
						
							|  |  |  |  |   GList *addresses; /* (owned) (nullable) */ | 
					
						
							|  |  |  |  |   GList *current_item; /* (unowned) (nullable) */ | 
					
						
							|  |  |  |  |   GTask *queued_task; /* (owned) (nullable) */ | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   GTask *waiting_task; /* (owned) (nullable) */ | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   GError *last_error; /* (owned) (nullable) */ | 
					
						
							|  |  |  |  |   GSource *wait_source; /* (owned) (nullable) */ | 
					
						
							|  |  |  |  |   GMainContext *context; /* (owned) (nullable) */ | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   ResolveState state; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } GNetworkAddressAddressEnumerator; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | typedef struct { | 
					
						
							|  |  |  |  |   GSocketAddressEnumeratorClass parent_class; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | } GNetworkAddressAddressEnumeratorClass; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 21:24:45 -04:00
										 |  |  |  | static GType _g_network_address_address_enumerator_get_type (void); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | G_DEFINE_TYPE (GNetworkAddressAddressEnumerator, _g_network_address_address_enumerator, G_TYPE_SOCKET_ADDRESS_ENUMERATOR) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_address_enumerator_finalize (GObject *object) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = | 
					
						
							|  |  |  |  |     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (object); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   if (addr_enum->wait_source) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (addr_enum->wait_source); | 
					
						
							|  |  |  |  |       g_clear_pointer (&addr_enum->wait_source, g_source_unref); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   g_clear_object (&addr_enum->queued_task); | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   g_clear_object (&addr_enum->waiting_task); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   g_clear_error (&addr_enum->last_error); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |   g_object_unref (addr_enum->addr); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   g_clear_pointer (&addr_enum->context, g_main_context_unref); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   g_list_free_full (addr_enum->addresses, g_object_unref); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   G_OBJECT_CLASS (_g_network_address_address_enumerator_parent_class)->finalize (object); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  | static inline GSocketFamily | 
					
						
							|  |  |  |  | get_address_family (GInetSocketAddress *address) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   return g_inet_address_get_family (g_inet_socket_address_get_address (address)); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | list_split_families (GList  *list, | 
					
						
							|  |  |  |  |                      GList **out_ipv4, | 
					
						
							|  |  |  |  |                      GList **out_ipv6) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   g_assert (out_ipv4); | 
					
						
							|  |  |  |  |   g_assert (out_ipv6); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   while (list) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       GSocketFamily family = get_address_family (list->data); | 
					
						
							|  |  |  |  |       switch (family) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           case G_SOCKET_FAMILY_IPV4: | 
					
						
							|  |  |  |  |             *out_ipv4 = g_list_prepend (*out_ipv4, list->data); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case G_SOCKET_FAMILY_IPV6: | 
					
						
							|  |  |  |  |             *out_ipv6 = g_list_prepend (*out_ipv6, list->data); | 
					
						
							|  |  |  |  |             break; | 
					
						
							|  |  |  |  |           case G_SOCKET_FAMILY_INVALID: | 
					
						
							|  |  |  |  |           case G_SOCKET_FAMILY_UNIX: | 
					
						
							|  |  |  |  |             g_assert_not_reached (); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       list = g_list_next (list); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   *out_ipv4 = g_list_reverse (*out_ipv4); | 
					
						
							|  |  |  |  |   *out_ipv6 = g_list_reverse (*out_ipv6); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GList * | 
					
						
							|  |  |  |  | list_interleave_families (GList *list1, | 
					
						
							|  |  |  |  |                           GList *list2) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *interleaved = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   while (list1 || list2) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       if (list1) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           interleaved = g_list_append (interleaved, list1->data); | 
					
						
							|  |  |  |  |           list1 = g_list_delete_link (list1, list1); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |       if (list2) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           interleaved = g_list_append (interleaved, list2->data); | 
					
						
							|  |  |  |  |           list2 = g_list_delete_link (list2, list2); | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return interleaved; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* list_copy_interleaved:
 | 
					
						
							|  |  |  |  |  * @list: (transfer container): List to copy | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Does a shallow copy of a list with address families interleaved. | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * For example: | 
					
						
							|  |  |  |  |  *   Input: [ipv6, ipv6, ipv4, ipv4] | 
					
						
							|  |  |  |  |  *   Output: [ipv6, ipv4, ipv6, ipv4] | 
					
						
							|  |  |  |  |  * | 
					
						
							|  |  |  |  |  * Returns: (transfer container): A new list | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | static GList * | 
					
						
							|  |  |  |  | list_copy_interleaved (GList *list) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *ipv4 = NULL, *ipv6 = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   list_split_families (list, &ipv4, &ipv6); | 
					
						
							|  |  |  |  |   return list_interleave_families (ipv6, ipv4); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* list_concat_interleaved:
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |  * @parent_list: (transfer container): Already existing list | 
					
						
							|  |  |  |  |  * @current_item: (transfer container): Item after which to resort | 
					
						
							|  |  |  |  |  * @new_list: (transfer container): New list to be interleaved and concatenated | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * This differs from g_list_concat() + list_copy_interleaved() in that it sorts | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |  * items in the previous list starting from @current_item and concats the results | 
					
						
							|  |  |  |  |  * to @parent_list. | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  |  * | 
					
						
							|  |  |  |  |  * Returns: (transfer container): New start of list | 
					
						
							|  |  |  |  |  */ | 
					
						
							|  |  |  |  | static GList * | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  | list_concat_interleaved (GList *parent_list, | 
					
						
							|  |  |  |  |                          GList *current_item, | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  |                          GList *new_list) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *ipv4 = NULL, *ipv6 = NULL, *interleaved, *trailing = NULL; | 
					
						
							|  |  |  |  |   GSocketFamily last_family = G_SOCKET_FAMILY_IPV4; /* Default to starting with ipv6 */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (current_item) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       last_family = get_address_family (current_item->data); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       /* Unused addresses will get removed, resorted, then readded */ | 
					
						
							|  |  |  |  |       trailing = g_list_next (current_item); | 
					
						
							|  |  |  |  |       current_item->next = NULL; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   list_split_families (trailing, &ipv4, &ipv6); | 
					
						
							|  |  |  |  |   list_split_families (new_list, &ipv4, &ipv6); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   g_list_free (new_list); | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (trailing) | 
					
						
							|  |  |  |  |     g_list_free (trailing); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (last_family == G_SOCKET_FAMILY_IPV4) | 
					
						
							|  |  |  |  |     interleaved = list_interleave_families (ipv6, ipv4); | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     interleaved = list_interleave_families (ipv4, ipv6); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   return g_list_concat (parent_list, interleaved); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | maybe_update_address_cache (GNetworkAddressAddressEnumerator *addr_enum, | 
					
						
							|  |  |  |  |                             GResolver                        *resolver) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *addresses, *p; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* Only cache complete results */ | 
					
						
							|  |  |  |  |   if (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4 || addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV6) | 
					
						
							|  |  |  |  |     return; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* The enumerators list will not necessarily be fully sorted */ | 
					
						
							|  |  |  |  |   addresses = list_copy_interleaved (addr_enum->addresses); | 
					
						
							|  |  |  |  |   for (p = addresses; p; p = p->next) | 
					
						
							|  |  |  |  |     g_object_ref (p->data); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_network_address_set_cached_addresses (addr_enum->addr, g_steal_pointer (&addresses), g_resolver_get_serial (resolver)); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_address_enumerator_add_addresses (GNetworkAddressAddressEnumerator *addr_enum, | 
					
						
							|  |  |  |  |                                                     GList                            *addresses, | 
					
						
							|  |  |  |  |                                                     GResolver                        *resolver) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *new_addresses = inet_addresses_to_inet_socket_addresses (addr_enum->addr, addresses); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (addr_enum->addresses == NULL) | 
					
						
							|  |  |  |  |     addr_enum->addresses = g_steal_pointer (&new_addresses); | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     addr_enum->addresses = list_concat_interleaved (addr_enum->addresses, addr_enum->current_item, g_steal_pointer (&new_addresses)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   maybe_update_address_cache (addr_enum, resolver); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static gpointer | 
					
						
							|  |  |  |  | copy_object (gconstpointer src, | 
					
						
							|  |  |  |  |              gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   return g_object_ref (G_OBJECT (src)); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GSocketAddress * | 
					
						
							|  |  |  |  | init_and_query_next_address (GNetworkAddressAddressEnumerator *addr_enum) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GList *next_item; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (addr_enum->addresses == NULL) | 
					
						
							|  |  |  |  |     addr_enum->addresses = g_list_copy_deep (addr_enum->addr->priv->cached_sockaddrs, | 
					
						
							|  |  |  |  |                                              copy_object, NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* We always want to look at the next item at call time to get the latest results.
 | 
					
						
							|  |  |  |  |      That means that sometimes ->next is NULL this call but is valid next call. | 
					
						
							|  |  |  |  |    */ | 
					
						
							|  |  |  |  |   if (addr_enum->current_item == NULL) | 
					
						
							|  |  |  |  |     next_item = addr_enum->current_item = addr_enum->addresses; | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     next_item = g_list_next (addr_enum->current_item); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (next_item) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       addr_enum->current_item = next_item; | 
					
						
							|  |  |  |  |       return g_object_ref (addr_enum->current_item->data); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     return NULL; | 
					
						
							| 
									
										
										
										
											2018-11-06 13:36:19 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | static GSocketAddress * | 
					
						
							|  |  |  |  | g_network_address_address_enumerator_next (GSocketAddressEnumerator  *enumerator, | 
					
						
							|  |  |  |  |                                            GCancellable              *cancellable, | 
					
						
							|  |  |  |  |                                            GError                   **error) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = | 
					
						
							|  |  |  |  |     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |   if (addr_enum->addresses == NULL) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |       GNetworkAddress *addr = addr_enum->addr; | 
					
						
							|  |  |  |  |       GResolver *resolver = g_resolver_get_default (); | 
					
						
							|  |  |  |  |       gint64 serial = g_resolver_get_serial (resolver); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (addr->priv->resolver_serial != 0 && | 
					
						
							|  |  |  |  |           addr->priv->resolver_serial != serial) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* Resolver has reloaded, discard cached addresses */ | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |           g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref); | 
					
						
							|  |  |  |  |           addr->priv->cached_sockaddrs = NULL; | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |       if (!addr->priv->cached_sockaddrs) | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |         g_network_address_parse_sockaddr (addr); | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |       if (!addr->priv->cached_sockaddrs) | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |         { | 
					
						
							|  |  |  |  |           GList *addresses; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |           addresses = g_resolver_lookup_by_name (resolver, | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |                                                  addr->priv->hostname, | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |                                                  cancellable, error); | 
					
						
							|  |  |  |  |           if (!addresses) | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |             { | 
					
						
							|  |  |  |  |               g_object_unref (resolver); | 
					
						
							|  |  |  |  |               return NULL; | 
					
						
							|  |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |           g_network_address_set_cached_addresses (addr, g_steal_pointer (&addresses), serial); | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |       g_object_unref (resolver); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |   return init_and_query_next_address (addr_enum); | 
					
						
							| 
									
										
										
										
											2019-02-11 08:51:47 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | complete_queued_task (GNetworkAddressAddressEnumerator *addr_enum, | 
					
						
							|  |  |  |  |                       GTask                            *task, | 
					
						
							|  |  |  |  |                       GError                           *error) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |   if (error) | 
					
						
							|  |  |  |  |     g_task_return_error (task, error); | 
					
						
							|  |  |  |  |   else | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |     { | 
					
						
							|  |  |  |  |       GSocketAddress *sockaddr = init_and_query_next_address (addr_enum); | 
					
						
							|  |  |  |  |       g_task_return_pointer (task, g_steal_pointer (&sockaddr), g_object_unref); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  |   g_object_unref (task); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | static int | 
					
						
							|  |  |  |  | on_address_timeout (gpointer user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = user_data; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-01-23 19:08:49 -08:00
										 |  |  |  |   /* Upon completion it may get unref'd by the owner */ | 
					
						
							|  |  |  |  |   g_object_ref (addr_enum); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   if (addr_enum->queued_task != NULL) | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), | 
					
						
							|  |  |  |  |                             g_steal_pointer (&addr_enum->last_error)); | 
					
						
							|  |  |  |  |   else if (addr_enum->waiting_task != NULL) | 
					
						
							|  |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), | 
					
						
							|  |  |  |  |                             NULL); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_clear_pointer (&addr_enum->wait_source, g_source_unref); | 
					
						
							| 
									
										
										
										
											2019-01-23 19:08:49 -08:00
										 |  |  |  |   g_object_unref (addr_enum); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   return G_SOURCE_REMOVE; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | static void | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | got_ipv6_addresses (GObject      *source_object, | 
					
						
							|  |  |  |  |                     GAsyncResult *result, | 
					
						
							|  |  |  |  |                     gpointer      user_data) | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = user_data; | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |   GResolver *resolver = G_RESOLVER (source_object); | 
					
						
							|  |  |  |  |   GList *addresses; | 
					
						
							|  |  |  |  |   GError *error = NULL; | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV6; | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error); | 
					
						
							|  |  |  |  |   if (!error) | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |     g_network_address_address_enumerator_add_addresses (addr_enum, g_steal_pointer (&addresses), resolver); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   else | 
					
						
							|  |  |  |  |     g_debug ("IPv6 DNS error: %s", error->message); | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   /* If ipv4 was first and waiting on us it can stop waiting */ | 
					
						
							|  |  |  |  |   if (addr_enum->wait_source) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (addr_enum->wait_source); | 
					
						
							|  |  |  |  |       g_clear_pointer (&addr_enum->wait_source, g_source_unref); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  |   /* If we got an error before ipv4 then let its response handle it.
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |    * If we get ipv6 response first or error second then | 
					
						
							|  |  |  |  |    * immediately complete the task. | 
					
						
							|  |  |  |  |    */ | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   if (error != NULL && !addr_enum->last_error && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4)) | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-05-23 09:33:00 +02:00
										 |  |  |  |       /* ipv6 lookup failed, but ipv4 is still outstanding.  wait. */ | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |       addr_enum->last_error = g_steal_pointer (&error); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   else if (addr_enum->waiting_task != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   else if (addr_enum->queued_task != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  |       GError *task_error = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       /* If both errored just use the ipv6 one,
 | 
					
						
							|  |  |  |  |          but if ipv6 errored and ipv4 didn't we don't error */ | 
					
						
							|  |  |  |  |       if (error != NULL && addr_enum->last_error) | 
					
						
							|  |  |  |  |           task_error = g_steal_pointer (&error); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |       g_clear_error (&addr_enum->last_error); | 
					
						
							|  |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  |                             g_steal_pointer (&task_error)); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  |   g_clear_error (&error); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   g_object_unref (addr_enum); | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | got_ipv4_addresses (GObject      *source_object, | 
					
						
							|  |  |  |  |                     GAsyncResult *result, | 
					
						
							|  |  |  |  |                     gpointer      user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = user_data; | 
					
						
							|  |  |  |  |   GResolver *resolver = G_RESOLVER (source_object); | 
					
						
							|  |  |  |  |   GList *addresses; | 
					
						
							|  |  |  |  |   GError *error = NULL; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   addr_enum->state ^= RESOLVE_STATE_WAITING_ON_IPV4; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   addresses = g_resolver_lookup_by_name_with_flags_finish (resolver, result, &error); | 
					
						
							|  |  |  |  |   if (!error) | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |     g_network_address_address_enumerator_add_addresses (addr_enum, g_steal_pointer (&addresses), resolver); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   else | 
					
						
							|  |  |  |  |     g_debug ("IPv4 DNS error: %s", error->message); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   if (addr_enum->wait_source) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_source_destroy (addr_enum->wait_source); | 
					
						
							|  |  |  |  |       g_clear_pointer (&addr_enum->wait_source, g_source_unref); | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   /* If ipv6 already came in and errored then we return.
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |    * If ipv6 returned successfully then we don't need to do anything unless | 
					
						
							|  |  |  |  |    * another enumeration was waiting on us. | 
					
						
							|  |  |  |  |    * If ipv6 hasn't come we should wait a short while for it as RFC 8305 suggests. | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |    */ | 
					
						
							|  |  |  |  |   if (addr_enum->last_error) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_assert (addr_enum->queued_task); | 
					
						
							|  |  |  |  |       g_clear_error (&addr_enum->last_error); | 
					
						
							|  |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->queued_task), | 
					
						
							|  |  |  |  |                             g_steal_pointer (&error)); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   else if (addr_enum->waiting_task != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       complete_queued_task (addr_enum, g_steal_pointer (&addr_enum->waiting_task), NULL); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   else if (addr_enum->queued_task != NULL) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       addr_enum->last_error = g_steal_pointer (&error); | 
					
						
							| 
									
										
										
										
											2019-02-07 09:50:56 -05:00
										 |  |  |  |       addr_enum->wait_source = g_timeout_source_new (HAPPY_EYEBALLS_RESOLUTION_DELAY_MS); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |       g_source_set_callback (addr_enum->wait_source, | 
					
						
							|  |  |  |  |                              on_address_timeout, | 
					
						
							|  |  |  |  |                              addr_enum, NULL); | 
					
						
							|  |  |  |  |       g_source_attach (addr_enum->wait_source, addr_enum->context); | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   g_clear_error (&error); | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   g_object_unref (addr_enum); | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | static void | 
					
						
							|  |  |  |  | g_network_address_address_enumerator_next_async (GSocketAddressEnumerator  *enumerator, | 
					
						
							|  |  |  |  |                                                  GCancellable              *cancellable, | 
					
						
							|  |  |  |  |                                                  GAsyncReadyCallback        callback, | 
					
						
							|  |  |  |  |                                                  gpointer                   user_data) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum = | 
					
						
							|  |  |  |  |     G_NETWORK_ADDRESS_ADDRESS_ENUMERATOR (enumerator); | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  |   GSocketAddress *sockaddr; | 
					
						
							|  |  |  |  |   GTask *task; | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  |   task = g_task_new (addr_enum, cancellable, callback, user_data); | 
					
						
							| 
									
										
										
										
											2016-06-16 19:39:38 -04:00
										 |  |  |  |   g_task_set_source_tag (task, g_network_address_address_enumerator_next_async); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   if (addr_enum->addresses == NULL && addr_enum->state == RESOLVE_STATE_NONE) | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     { | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |       GNetworkAddress *addr = addr_enum->addr; | 
					
						
							|  |  |  |  |       GResolver *resolver = g_resolver_get_default (); | 
					
						
							|  |  |  |  |       gint64 serial = g_resolver_get_serial (resolver); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       if (addr->priv->resolver_serial != 0 && | 
					
						
							|  |  |  |  |           addr->priv->resolver_serial != serial) | 
					
						
							|  |  |  |  |         { | 
					
						
							|  |  |  |  |           /* Resolver has reloaded, discard cached addresses */ | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |           g_list_free_full (addr->priv->cached_sockaddrs, g_object_unref); | 
					
						
							|  |  |  |  |           addr->priv->cached_sockaddrs = NULL; | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |         } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-05-08 20:10:40 -07:00
										 |  |  |  |       if (addr->priv->cached_sockaddrs == NULL) | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |         { | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |           if (g_network_address_parse_sockaddr (addr)) | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |             complete_queued_task (addr_enum, task, NULL); | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |           else | 
					
						
							|  |  |  |  |             { | 
					
						
							| 
									
										
										
										
											2018-12-11 10:10:10 -05:00
										 |  |  |  |               /* It does not make sense for this to be called multiple
 | 
					
						
							|  |  |  |  |                * times before the initial callback has been called */ | 
					
						
							|  |  |  |  |               g_assert (addr_enum->queued_task == NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |               addr_enum->state = RESOLVE_STATE_WAITING_ON_IPV4 | RESOLVE_STATE_WAITING_ON_IPV6; | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |               addr_enum->queued_task = g_steal_pointer (&task); | 
					
						
							| 
									
										
										
										
											2019-04-26 12:12:31 +01:00
										 |  |  |  |               /* Look up in parallel as per RFC 8305 */ | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |               g_resolver_lookup_by_name_with_flags_async (resolver, | 
					
						
							|  |  |  |  |                                                           addr->priv->hostname, | 
					
						
							|  |  |  |  |                                                           G_RESOLVER_NAME_LOOKUP_FLAGS_IPV6_ONLY, | 
					
						
							|  |  |  |  |                                                           cancellable, | 
					
						
							|  |  |  |  |                                                           got_ipv6_addresses, g_object_ref (addr_enum)); | 
					
						
							|  |  |  |  |               g_resolver_lookup_by_name_with_flags_async (resolver, | 
					
						
							|  |  |  |  |                                                           addr->priv->hostname, | 
					
						
							|  |  |  |  |                                                           G_RESOLVER_NAME_LOOKUP_FLAGS_IPV4_ONLY, | 
					
						
							|  |  |  |  |                                                           cancellable, | 
					
						
							|  |  |  |  |                                                           got_ipv4_addresses, g_object_ref (addr_enum)); | 
					
						
							| 
									
										
										
										
											2012-12-12 16:12:09 +01:00
										 |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |           g_object_unref (resolver); | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  |           return; | 
					
						
							|  |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-19 15:19:22 -05:00
										 |  |  |  |       g_object_unref (resolver); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2010-12-07 17:25:01 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-11 08:51:47 -05:00
										 |  |  |  |   sockaddr = init_and_query_next_address (addr_enum); | 
					
						
							| 
									
										
										
										
											2019-02-11 08:53:23 -05:00
										 |  |  |  |   if (sockaddr == NULL && (addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV4 || | 
					
						
							|  |  |  |  |                            addr_enum->state & RESOLVE_STATE_WAITING_ON_IPV6)) | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       addr_enum->waiting_task = task; | 
					
						
							|  |  |  |  |     } | 
					
						
							|  |  |  |  |   else | 
					
						
							|  |  |  |  |     { | 
					
						
							|  |  |  |  |       g_task_return_pointer (task, sockaddr, g_object_unref); | 
					
						
							|  |  |  |  |       g_object_unref (task); | 
					
						
							|  |  |  |  |     } | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GSocketAddress * | 
					
						
							|  |  |  |  | g_network_address_address_enumerator_next_finish (GSocketAddressEnumerator  *enumerator, | 
					
						
							|  |  |  |  |                                                   GAsyncResult              *result, | 
					
						
							|  |  |  |  |                                                   GError                   **error) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  |   g_return_val_if_fail (g_task_is_valid (result, enumerator), NULL); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 15:48:22 -04:00
										 |  |  |  |   return g_task_propagate_pointer (G_TASK (result), error); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | _g_network_address_address_enumerator_init (GNetworkAddressAddressEnumerator *enumerator) | 
					
						
							|  |  |  |  | { | 
					
						
							| 
									
										
										
										
											2018-10-22 13:36:27 -04:00
										 |  |  |  |   enumerator->context = g_main_context_ref_thread_default (); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static void | 
					
						
							|  |  |  |  | _g_network_address_address_enumerator_class_init (GNetworkAddressAddressEnumeratorClass *addrenum_class) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GObjectClass *object_class = G_OBJECT_CLASS (addrenum_class); | 
					
						
							|  |  |  |  |   GSocketAddressEnumeratorClass *enumerator_class = | 
					
						
							|  |  |  |  |     G_SOCKET_ADDRESS_ENUMERATOR_CLASS (addrenum_class); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   enumerator_class->next = g_network_address_address_enumerator_next; | 
					
						
							|  |  |  |  |   enumerator_class->next_async = g_network_address_address_enumerator_next_async; | 
					
						
							|  |  |  |  |   enumerator_class->next_finish = g_network_address_address_enumerator_next_finish; | 
					
						
							|  |  |  |  |   object_class->finalize = g_network_address_address_enumerator_finalize; | 
					
						
							|  |  |  |  | } | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | static GSocketAddressEnumerator * | 
					
						
							|  |  |  |  | g_network_address_connectable_enumerate (GSocketConnectable *connectable) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddressAddressEnumerator *addr_enum; | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   addr_enum = g_object_new (G_TYPE_NETWORK_ADDRESS_ADDRESS_ENUMERATOR, NULL); | 
					
						
							| 
									
										
										
										
											2017-11-22 00:00:39 -08:00
										 |  |  |  |   addr_enum->addr = g_object_ref (G_NETWORK_ADDRESS (connectable)); | 
					
						
							| 
									
										
										
										
											2008-12-29 13:38:28 -05:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   return (GSocketAddressEnumerator *)addr_enum; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2010-08-10 15:45:32 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | static GSocketAddressEnumerator * | 
					
						
							|  |  |  |  | g_network_address_connectable_proxy_enumerate (GSocketConnectable *connectable) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *self = G_NETWORK_ADDRESS (connectable); | 
					
						
							|  |  |  |  |   GSocketAddressEnumerator *proxy_enum; | 
					
						
							|  |  |  |  |   gchar *uri; | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-06 23:34:27 +04:00
										 |  |  |  |   uri = g_uri_join (G_URI_FLAGS_NONE, | 
					
						
							|  |  |  |  |                     self->priv->scheme ? self->priv->scheme : "none", | 
					
						
							|  |  |  |  |                     NULL, | 
					
						
							|  |  |  |  |                     self->priv->hostname, | 
					
						
							|  |  |  |  |                     self->priv->port, | 
					
						
							|  |  |  |  |                     "", | 
					
						
							|  |  |  |  |                     NULL, | 
					
						
							|  |  |  |  |                     NULL); | 
					
						
							| 
									
										
										
										
											2010-08-10 15:45:32 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |   proxy_enum = g_object_new (G_TYPE_PROXY_ADDRESS_ENUMERATOR, | 
					
						
							|  |  |  |  |                              "connectable", connectable, | 
					
						
							|  |  |  |  |       	       	       	     "uri", uri, | 
					
						
							|  |  |  |  |       	       	       	     NULL); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_free (uri); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return proxy_enum; | 
					
						
							|  |  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-10-04 15:24:24 +01:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | static gchar * | 
					
						
							|  |  |  |  | g_network_address_connectable_to_string (GSocketConnectable *connectable) | 
					
						
							|  |  |  |  | { | 
					
						
							|  |  |  |  |   GNetworkAddress *addr; | 
					
						
							|  |  |  |  |   const gchar *scheme; | 
					
						
							|  |  |  |  |   guint16 port; | 
					
						
							|  |  |  |  |   GString *out;  /* owned */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   addr = G_NETWORK_ADDRESS (connectable); | 
					
						
							|  |  |  |  |   out = g_string_new (""); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   scheme = g_network_address_get_scheme (addr); | 
					
						
							|  |  |  |  |   if (scheme != NULL) | 
					
						
							|  |  |  |  |     g_string_append_printf (out, "%s:", scheme); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   g_string_append (out, g_network_address_get_hostname (addr)); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   port = g_network_address_get_port (addr); | 
					
						
							|  |  |  |  |   if (port != 0) | 
					
						
							|  |  |  |  |     g_string_append_printf (out, ":%u", port); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |   return g_string_free (out, FALSE); | 
					
						
							|  |  |  |  | } |