1/* GIO - GLib Input, Output and Streaming Library
2 *
3 * Copyright © 2008, 2009 codethink
4 * Copyright © 2009 Red Hat, Inc
5 * Copyright © 2018 Igalia S.L.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 *
20 * Authors: Ryan Lortie <desrt@desrt.ca>
21 * Alexander Larsson <alexl@redhat.com>
22 */
23
24#include "config.h"
25#include "gsocketclient.h"
26
27#ifndef G_OS_WIN32
28#include <netinet/in.h>
29#endif
30
31#include <stdlib.h>
32#include <string.h>
33
34#include <gio/gioenumtypes.h>
35#include <gio/gsocketaddressenumerator.h>
36#include <gio/gsocketconnectable.h>
37#include <gio/gsocketconnection.h>
38#include <gio/gioprivate.h>
39#include <gio/gproxyaddressenumerator.h>
40#include <gio/gproxyaddress.h>
41#include <gio/gtask.h>
42#include <gio/gcancellable.h>
43#include <gio/gioerror.h>
44#include <gio/gsocket.h>
45#include <gio/gnetworkaddress.h>
46#include <gio/gnetworking.h>
47#include <gio/gnetworkservice.h>
48#include <gio/gproxy.h>
49#include <gio/gproxyresolver.h>
50#include <gio/gsocketaddress.h>
51#include <gio/gtcpconnection.h>
52#include <gio/gtcpwrapperconnection.h>
53#include <gio/gtlscertificate.h>
54#include <gio/gtlsclientconnection.h>
55#include <gio/ginetaddress.h>
56#include "glibintl.h"
57#include "gmarshal-internal.h"
58
59/* As recommended by RFC 8305 this is the time it waits
60 * on a connection before starting another concurrent attempt.
61 */
62#define HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS 250
63
64/**
65 * SECTION:gsocketclient
66 * @short_description: Helper for connecting to a network service
67 * @include: gio/gio.h
68 * @see_also: #GSocketConnection, #GSocketListener
69 *
70 * #GSocketClient is a lightweight high-level utility class for connecting to
71 * a network host using a connection oriented socket type.
72 *
73 * You create a #GSocketClient object, set any options you want, and then
74 * call a sync or async connect operation, which returns a #GSocketConnection
75 * subclass on success.
76 *
77 * The type of the #GSocketConnection object returned depends on the type of
78 * the underlying socket that is in use. For instance, for a TCP/IP connection
79 * it will be a #GTcpConnection.
80 *
81 * As #GSocketClient is a lightweight object, you don't need to cache it. You
82 * can just create a new one any time you need one.
83 *
84 * Since: 2.22
85 */
86
87
88enum
89{
90 EVENT,
91 LAST_SIGNAL
92};
93
94static guint signals[LAST_SIGNAL] = { 0 };
95
96enum
97{
98 PROP_NONE,
99 PROP_FAMILY,
100 PROP_TYPE,
101 PROP_PROTOCOL,
102 PROP_LOCAL_ADDRESS,
103 PROP_TIMEOUT,
104 PROP_ENABLE_PROXY,
105 PROP_TLS,
106 PROP_TLS_VALIDATION_FLAGS,
107 PROP_PROXY_RESOLVER
108};
109
110struct _GSocketClientPrivate
111{
112 GSocketFamily family;
113 GSocketType type;
114 GSocketProtocol protocol;
115 GSocketAddress *local_address;
116 guint timeout;
117 gboolean enable_proxy;
118 GHashTable *app_proxies;
119 gboolean tls;
120 GTlsCertificateFlags tls_validation_flags;
121 GProxyResolver *proxy_resolver;
122};
123
124G_DEFINE_TYPE_WITH_PRIVATE (GSocketClient, g_socket_client, G_TYPE_OBJECT)
125
126static GSocket *
127create_socket (GSocketClient *client,
128 GSocketAddress *dest_address,
129 GError **error)
130{
131 GSocketFamily family;
132 GSocket *socket;
133
134 family = client->priv->family;
135 if (family == G_SOCKET_FAMILY_INVALID &&
136 client->priv->local_address != NULL)
137 family = g_socket_address_get_family (address: client->priv->local_address);
138 if (family == G_SOCKET_FAMILY_INVALID)
139 family = g_socket_address_get_family (address: dest_address);
140
141 socket = g_socket_new (family,
142 type: client->priv->type,
143 protocol: client->priv->protocol,
144 error);
145 if (socket == NULL)
146 return NULL;
147
148 if (client->priv->local_address)
149 {
150#ifdef IP_BIND_ADDRESS_NO_PORT
151 g_socket_set_option (socket, IPPROTO_IP, IP_BIND_ADDRESS_NO_PORT, value: 1, NULL);
152#endif
153
154 if (!g_socket_bind (socket,
155 address: client->priv->local_address,
156 FALSE,
157 error))
158 {
159 g_object_unref (object: socket);
160 return NULL;
161 }
162 }
163
164 if (client->priv->timeout)
165 g_socket_set_timeout (socket, timeout: client->priv->timeout);
166
167 return socket;
168}
169
170static gboolean
171can_use_proxy (GSocketClient *client)
172{
173 GSocketClientPrivate *priv = client->priv;
174
175 return priv->enable_proxy
176 && priv->type == G_SOCKET_TYPE_STREAM;
177}
178
179static void
180clarify_connect_error (GError *error,
181 GSocketConnectable *connectable,
182 GSocketAddress *address)
183{
184 const char *name;
185 char *tmp_name = NULL;
186
187 if (G_IS_PROXY_ADDRESS (address))
188 {
189 name = tmp_name = g_inet_address_to_string (address: g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (address)));
190
191 g_prefix_error (err: &error, _("Could not connect to proxy server %s: "), name);
192 }
193 else
194 {
195 if (G_IS_NETWORK_ADDRESS (connectable))
196 name = g_network_address_get_hostname (G_NETWORK_ADDRESS (connectable));
197 else if (G_IS_NETWORK_SERVICE (connectable))
198 name = g_network_service_get_domain (G_NETWORK_SERVICE (connectable));
199 else if (G_IS_INET_SOCKET_ADDRESS (connectable))
200 name = tmp_name = g_inet_address_to_string (address: g_inet_socket_address_get_address (G_INET_SOCKET_ADDRESS (connectable)));
201 else
202 name = NULL;
203
204 if (name)
205 g_prefix_error (err: &error, _("Could not connect to %s: "), name);
206 else
207 g_prefix_error (err: &error, _("Could not connect: "));
208 }
209
210 g_free (mem: tmp_name);
211}
212
213static void
214g_socket_client_init (GSocketClient *client)
215{
216 client->priv = g_socket_client_get_instance_private (self: client);
217 client->priv->type = G_SOCKET_TYPE_STREAM;
218 client->priv->app_proxies = g_hash_table_new_full (hash_func: g_str_hash,
219 key_equal_func: g_str_equal,
220 key_destroy_func: g_free,
221 NULL);
222}
223
224/**
225 * g_socket_client_new:
226 *
227 * Creates a new #GSocketClient with the default options.
228 *
229 * Returns: a #GSocketClient.
230 * Free the returned object with g_object_unref().
231 *
232 * Since: 2.22
233 */
234GSocketClient *
235g_socket_client_new (void)
236{
237 return g_object_new (G_TYPE_SOCKET_CLIENT, NULL);
238}
239
240static void
241g_socket_client_finalize (GObject *object)
242{
243 GSocketClient *client = G_SOCKET_CLIENT (object);
244
245 g_clear_object (&client->priv->local_address);
246 g_clear_object (&client->priv->proxy_resolver);
247
248 G_OBJECT_CLASS (g_socket_client_parent_class)->finalize (object);
249
250 g_hash_table_unref (hash_table: client->priv->app_proxies);
251}
252
253static void
254g_socket_client_get_property (GObject *object,
255 guint prop_id,
256 GValue *value,
257 GParamSpec *pspec)
258{
259 GSocketClient *client = G_SOCKET_CLIENT (object);
260
261 switch (prop_id)
262 {
263 case PROP_FAMILY:
264 g_value_set_enum (value, v_enum: client->priv->family);
265 break;
266
267 case PROP_TYPE:
268 g_value_set_enum (value, v_enum: client->priv->type);
269 break;
270
271 case PROP_PROTOCOL:
272 g_value_set_enum (value, v_enum: client->priv->protocol);
273 break;
274
275 case PROP_LOCAL_ADDRESS:
276 g_value_set_object (value, v_object: client->priv->local_address);
277 break;
278
279 case PROP_TIMEOUT:
280 g_value_set_uint (value, v_uint: client->priv->timeout);
281 break;
282
283 case PROP_ENABLE_PROXY:
284 g_value_set_boolean (value, v_boolean: client->priv->enable_proxy);
285 break;
286
287 case PROP_TLS:
288 g_value_set_boolean (value, v_boolean: g_socket_client_get_tls (client));
289 break;
290
291 case PROP_TLS_VALIDATION_FLAGS:
292 g_value_set_flags (value, v_flags: g_socket_client_get_tls_validation_flags (client));
293 break;
294
295 case PROP_PROXY_RESOLVER:
296 g_value_set_object (value, v_object: g_socket_client_get_proxy_resolver (client));
297 break;
298
299 default:
300 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
301 }
302}
303
304static void
305g_socket_client_set_property (GObject *object,
306 guint prop_id,
307 const GValue *value,
308 GParamSpec *pspec)
309{
310 GSocketClient *client = G_SOCKET_CLIENT (object);
311
312 switch (prop_id)
313 {
314 case PROP_FAMILY:
315 g_socket_client_set_family (client, family: g_value_get_enum (value));
316 break;
317
318 case PROP_TYPE:
319 g_socket_client_set_socket_type (client, type: g_value_get_enum (value));
320 break;
321
322 case PROP_PROTOCOL:
323 g_socket_client_set_protocol (client, protocol: g_value_get_enum (value));
324 break;
325
326 case PROP_LOCAL_ADDRESS:
327 g_socket_client_set_local_address (client, address: g_value_get_object (value));
328 break;
329
330 case PROP_TIMEOUT:
331 g_socket_client_set_timeout (client, timeout: g_value_get_uint (value));
332 break;
333
334 case PROP_ENABLE_PROXY:
335 g_socket_client_set_enable_proxy (client, enable: g_value_get_boolean (value));
336 break;
337
338 case PROP_TLS:
339 g_socket_client_set_tls (client, tls: g_value_get_boolean (value));
340 break;
341
342 case PROP_TLS_VALIDATION_FLAGS:
343 g_socket_client_set_tls_validation_flags (client, flags: g_value_get_flags (value));
344 break;
345
346 case PROP_PROXY_RESOLVER:
347 g_socket_client_set_proxy_resolver (client, proxy_resolver: g_value_get_object (value));
348 break;
349
350 default:
351 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
352 }
353}
354
355/**
356 * g_socket_client_get_family:
357 * @client: a #GSocketClient.
358 *
359 * Gets the socket family of the socket client.
360 *
361 * See g_socket_client_set_family() for details.
362 *
363 * Returns: a #GSocketFamily
364 *
365 * Since: 2.22
366 */
367GSocketFamily
368g_socket_client_get_family (GSocketClient *client)
369{
370 return client->priv->family;
371}
372
373/**
374 * g_socket_client_set_family:
375 * @client: a #GSocketClient.
376 * @family: a #GSocketFamily
377 *
378 * Sets the socket family of the socket client.
379 * If this is set to something other than %G_SOCKET_FAMILY_INVALID
380 * then the sockets created by this object will be of the specified
381 * family.
382 *
383 * This might be useful for instance if you want to force the local
384 * connection to be an ipv4 socket, even though the address might
385 * be an ipv6 mapped to ipv4 address.
386 *
387 * Since: 2.22
388 */
389void
390g_socket_client_set_family (GSocketClient *client,
391 GSocketFamily family)
392{
393 if (client->priv->family == family)
394 return;
395
396 client->priv->family = family;
397 g_object_notify (G_OBJECT (client), property_name: "family");
398}
399
400/**
401 * g_socket_client_get_socket_type:
402 * @client: a #GSocketClient.
403 *
404 * Gets the socket type of the socket client.
405 *
406 * See g_socket_client_set_socket_type() for details.
407 *
408 * Returns: a #GSocketFamily
409 *
410 * Since: 2.22
411 */
412GSocketType
413g_socket_client_get_socket_type (GSocketClient *client)
414{
415 return client->priv->type;
416}
417
418/**
419 * g_socket_client_set_socket_type:
420 * @client: a #GSocketClient.
421 * @type: a #GSocketType
422 *
423 * Sets the socket type of the socket client.
424 * The sockets created by this object will be of the specified
425 * type.
426 *
427 * It doesn't make sense to specify a type of %G_SOCKET_TYPE_DATAGRAM,
428 * as GSocketClient is used for connection oriented services.
429 *
430 * Since: 2.22
431 */
432void
433g_socket_client_set_socket_type (GSocketClient *client,
434 GSocketType type)
435{
436 if (client->priv->type == type)
437 return;
438
439 client->priv->type = type;
440 g_object_notify (G_OBJECT (client), property_name: "type");
441}
442
443/**
444 * g_socket_client_get_protocol:
445 * @client: a #GSocketClient
446 *
447 * Gets the protocol name type of the socket client.
448 *
449 * See g_socket_client_set_protocol() for details.
450 *
451 * Returns: a #GSocketProtocol
452 *
453 * Since: 2.22
454 */
455GSocketProtocol
456g_socket_client_get_protocol (GSocketClient *client)
457{
458 return client->priv->protocol;
459}
460
461/**
462 * g_socket_client_set_protocol:
463 * @client: a #GSocketClient.
464 * @protocol: a #GSocketProtocol
465 *
466 * Sets the protocol of the socket client.
467 * The sockets created by this object will use of the specified
468 * protocol.
469 *
470 * If @protocol is %G_SOCKET_PROTOCOL_DEFAULT that means to use the default
471 * protocol for the socket family and type.
472 *
473 * Since: 2.22
474 */
475void
476g_socket_client_set_protocol (GSocketClient *client,
477 GSocketProtocol protocol)
478{
479 if (client->priv->protocol == protocol)
480 return;
481
482 client->priv->protocol = protocol;
483 g_object_notify (G_OBJECT (client), property_name: "protocol");
484}
485
486/**
487 * g_socket_client_get_local_address:
488 * @client: a #GSocketClient.
489 *
490 * Gets the local address of the socket client.
491 *
492 * See g_socket_client_set_local_address() for details.
493 *
494 * Returns: (nullable) (transfer none): a #GSocketAddress or %NULL. Do not free.
495 *
496 * Since: 2.22
497 */
498GSocketAddress *
499g_socket_client_get_local_address (GSocketClient *client)
500{
501 return client->priv->local_address;
502}
503
504/**
505 * g_socket_client_set_local_address:
506 * @client: a #GSocketClient.
507 * @address: (nullable): a #GSocketAddress, or %NULL
508 *
509 * Sets the local address of the socket client.
510 * The sockets created by this object will bound to the
511 * specified address (if not %NULL) before connecting.
512 *
513 * This is useful if you want to ensure that the local
514 * side of the connection is on a specific port, or on
515 * a specific interface.
516 *
517 * Since: 2.22
518 */
519void
520g_socket_client_set_local_address (GSocketClient *client,
521 GSocketAddress *address)
522{
523 if (address)
524 g_object_ref (address);
525
526 if (client->priv->local_address)
527 {
528 g_object_unref (object: client->priv->local_address);
529 }
530 client->priv->local_address = address;
531 g_object_notify (G_OBJECT (client), property_name: "local-address");
532}
533
534/**
535 * g_socket_client_get_timeout:
536 * @client: a #GSocketClient
537 *
538 * Gets the I/O timeout time for sockets created by @client.
539 *
540 * See g_socket_client_set_timeout() for details.
541 *
542 * Returns: the timeout in seconds
543 *
544 * Since: 2.26
545 */
546guint
547g_socket_client_get_timeout (GSocketClient *client)
548{
549 return client->priv->timeout;
550}
551
552
553/**
554 * g_socket_client_set_timeout:
555 * @client: a #GSocketClient.
556 * @timeout: the timeout
557 *
558 * Sets the I/O timeout for sockets created by @client. @timeout is a
559 * time in seconds, or 0 for no timeout (the default).
560 *
561 * The timeout value affects the initial connection attempt as well,
562 * so setting this may cause calls to g_socket_client_connect(), etc,
563 * to fail with %G_IO_ERROR_TIMED_OUT.
564 *
565 * Since: 2.26
566 */
567void
568g_socket_client_set_timeout (GSocketClient *client,
569 guint timeout)
570{
571 if (client->priv->timeout == timeout)
572 return;
573
574 client->priv->timeout = timeout;
575 g_object_notify (G_OBJECT (client), property_name: "timeout");
576}
577
578/**
579 * g_socket_client_get_enable_proxy:
580 * @client: a #GSocketClient.
581 *
582 * Gets the proxy enable state; see g_socket_client_set_enable_proxy()
583 *
584 * Returns: whether proxying is enabled
585 *
586 * Since: 2.26
587 */
588gboolean
589g_socket_client_get_enable_proxy (GSocketClient *client)
590{
591 return client->priv->enable_proxy;
592}
593
594/**
595 * g_socket_client_set_enable_proxy:
596 * @client: a #GSocketClient.
597 * @enable: whether to enable proxies
598 *
599 * Sets whether or not @client attempts to make connections via a
600 * proxy server. When enabled (the default), #GSocketClient will use a
601 * #GProxyResolver to determine if a proxy protocol such as SOCKS is
602 * needed, and automatically do the necessary proxy negotiation.
603 *
604 * See also g_socket_client_set_proxy_resolver().
605 *
606 * Since: 2.26
607 */
608void
609g_socket_client_set_enable_proxy (GSocketClient *client,
610 gboolean enable)
611{
612 enable = !!enable;
613 if (client->priv->enable_proxy == enable)
614 return;
615
616 client->priv->enable_proxy = enable;
617 g_object_notify (G_OBJECT (client), property_name: "enable-proxy");
618}
619
620/**
621 * g_socket_client_get_tls:
622 * @client: a #GSocketClient.
623 *
624 * Gets whether @client creates TLS connections. See
625 * g_socket_client_set_tls() for details.
626 *
627 * Returns: whether @client uses TLS
628 *
629 * Since: 2.28
630 */
631gboolean
632g_socket_client_get_tls (GSocketClient *client)
633{
634 return client->priv->tls;
635}
636
637/**
638 * g_socket_client_set_tls:
639 * @client: a #GSocketClient.
640 * @tls: whether to use TLS
641 *
642 * Sets whether @client creates TLS (aka SSL) connections. If @tls is
643 * %TRUE, @client will wrap its connections in a #GTlsClientConnection
644 * and perform a TLS handshake when connecting.
645 *
646 * Note that since #GSocketClient must return a #GSocketConnection,
647 * but #GTlsClientConnection is not a #GSocketConnection, this
648 * actually wraps the resulting #GTlsClientConnection in a
649 * #GTcpWrapperConnection when returning it. You can use
650 * g_tcp_wrapper_connection_get_base_io_stream() on the return value
651 * to extract the #GTlsClientConnection.
652 *
653 * If you need to modify the behavior of the TLS handshake (eg, by
654 * setting a client-side certificate to use, or connecting to the
655 * #GTlsConnection::accept-certificate signal), you can connect to
656 * @client's #GSocketClient::event signal and wait for it to be
657 * emitted with %G_SOCKET_CLIENT_TLS_HANDSHAKING, which will give you
658 * a chance to see the #GTlsClientConnection before the handshake
659 * starts.
660 *
661 * Since: 2.28
662 */
663void
664g_socket_client_set_tls (GSocketClient *client,
665 gboolean tls)
666{
667 tls = !!tls;
668 if (tls == client->priv->tls)
669 return;
670
671 client->priv->tls = tls;
672 g_object_notify (G_OBJECT (client), property_name: "tls");
673}
674
675/**
676 * g_socket_client_get_tls_validation_flags:
677 * @client: a #GSocketClient.
678 *
679 * Gets the TLS validation flags used creating TLS connections via
680 * @client.
681 *
682 * Returns: the TLS validation flags
683 *
684 * Since: 2.28
685 */
686GTlsCertificateFlags
687g_socket_client_get_tls_validation_flags (GSocketClient *client)
688{
689 return client->priv->tls_validation_flags;
690}
691
692/**
693 * g_socket_client_set_tls_validation_flags:
694 * @client: a #GSocketClient.
695 * @flags: the validation flags
696 *
697 * Sets the TLS validation flags used when creating TLS connections
698 * via @client. The default value is %G_TLS_CERTIFICATE_VALIDATE_ALL.
699 *
700 * Since: 2.28
701 */
702void
703g_socket_client_set_tls_validation_flags (GSocketClient *client,
704 GTlsCertificateFlags flags)
705{
706 if (client->priv->tls_validation_flags != flags)
707 {
708 client->priv->tls_validation_flags = flags;
709 g_object_notify (G_OBJECT (client), property_name: "tls-validation-flags");
710 }
711}
712
713/**
714 * g_socket_client_get_proxy_resolver:
715 * @client: a #GSocketClient.
716 *
717 * Gets the #GProxyResolver being used by @client. Normally, this will
718 * be the resolver returned by g_proxy_resolver_get_default(), but you
719 * can override it with g_socket_client_set_proxy_resolver().
720 *
721 * Returns: (transfer none): The #GProxyResolver being used by
722 * @client.
723 *
724 * Since: 2.36
725 */
726GProxyResolver *
727g_socket_client_get_proxy_resolver (GSocketClient *client)
728{
729 if (client->priv->proxy_resolver)
730 return client->priv->proxy_resolver;
731 else
732 return g_proxy_resolver_get_default ();
733}
734
735/**
736 * g_socket_client_set_proxy_resolver:
737 * @client: a #GSocketClient.
738 * @proxy_resolver: (nullable): a #GProxyResolver, or %NULL for the
739 * default.
740 *
741 * Overrides the #GProxyResolver used by @client. You can call this if
742 * you want to use specific proxies, rather than using the system
743 * default proxy settings.
744 *
745 * Note that whether or not the proxy resolver is actually used
746 * depends on the setting of #GSocketClient:enable-proxy, which is not
747 * changed by this function (but which is %TRUE by default)
748 *
749 * Since: 2.36
750 */
751void
752g_socket_client_set_proxy_resolver (GSocketClient *client,
753 GProxyResolver *proxy_resolver)
754{
755 /* We have to be careful to avoid calling
756 * g_proxy_resolver_get_default() until we're sure we need it,
757 * because trying to load the default proxy resolver module will
758 * break some test programs that aren't expecting it (eg,
759 * tests/gsettings).
760 */
761
762 if (client->priv->proxy_resolver)
763 g_object_unref (object: client->priv->proxy_resolver);
764
765 client->priv->proxy_resolver = proxy_resolver;
766
767 if (client->priv->proxy_resolver)
768 g_object_ref (client->priv->proxy_resolver);
769}
770
771static void
772g_socket_client_class_init (GSocketClientClass *class)
773{
774 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
775
776 gobject_class->finalize = g_socket_client_finalize;
777 gobject_class->set_property = g_socket_client_set_property;
778 gobject_class->get_property = g_socket_client_get_property;
779
780 /**
781 * GSocketClient::event:
782 * @client: the #GSocketClient
783 * @event: the event that is occurring
784 * @connectable: the #GSocketConnectable that @event is occurring on
785 * @connection: (nullable): the current representation of the connection
786 *
787 * Emitted when @client's activity on @connectable changes state.
788 * Among other things, this can be used to provide progress
789 * information about a network connection in the UI. The meanings of
790 * the different @event values are as follows:
791 *
792 * - %G_SOCKET_CLIENT_RESOLVING: @client is about to look up @connectable
793 * in DNS. @connection will be %NULL.
794 *
795 * - %G_SOCKET_CLIENT_RESOLVED: @client has successfully resolved
796 * @connectable in DNS. @connection will be %NULL.
797 *
798 * - %G_SOCKET_CLIENT_CONNECTING: @client is about to make a connection
799 * to a remote host; either a proxy server or the destination server
800 * itself. @connection is the #GSocketConnection, which is not yet
801 * connected. Since GLib 2.40, you can access the remote
802 * address via g_socket_connection_get_remote_address().
803 *
804 * - %G_SOCKET_CLIENT_CONNECTED: @client has successfully connected
805 * to a remote host. @connection is the connected #GSocketConnection.
806 *
807 * - %G_SOCKET_CLIENT_PROXY_NEGOTIATING: @client is about to negotiate
808 * with a proxy to get it to connect to @connectable. @connection is
809 * the #GSocketConnection to the proxy server.
810 *
811 * - %G_SOCKET_CLIENT_PROXY_NEGOTIATED: @client has negotiated a
812 * connection to @connectable through a proxy server. @connection is
813 * the stream returned from g_proxy_connect(), which may or may not
814 * be a #GSocketConnection.
815 *
816 * - %G_SOCKET_CLIENT_TLS_HANDSHAKING: @client is about to begin a TLS
817 * handshake. @connection is a #GTlsClientConnection.
818 *
819 * - %G_SOCKET_CLIENT_TLS_HANDSHAKED: @client has successfully completed
820 * the TLS handshake. @connection is a #GTlsClientConnection.
821 *
822 * - %G_SOCKET_CLIENT_COMPLETE: @client has either successfully connected
823 * to @connectable (in which case @connection is the #GSocketConnection
824 * that it will be returning to the caller) or has failed (in which
825 * case @connection is %NULL and the client is about to return an error).
826 *
827 * Each event except %G_SOCKET_CLIENT_COMPLETE may be emitted
828 * multiple times (or not at all) for a given connectable (in
829 * particular, if @client ends up attempting to connect to more than
830 * one address). However, if @client emits the #GSocketClient::event
831 * signal at all for a given connectable, then it will always emit
832 * it with %G_SOCKET_CLIENT_COMPLETE when it is done.
833 *
834 * Note that there may be additional #GSocketClientEvent values in
835 * the future; unrecognized @event values should be ignored.
836 *
837 * Since: 2.32
838 */
839 signals[EVENT] =
840 g_signal_new (I_("event"),
841 G_TYPE_FROM_CLASS (gobject_class),
842 signal_flags: G_SIGNAL_RUN_LAST,
843 G_STRUCT_OFFSET (GSocketClientClass, event),
844 NULL, NULL,
845 c_marshaller: _g_cclosure_marshal_VOID__ENUM_OBJECT_OBJECT,
846 G_TYPE_NONE, n_params: 3,
847 G_TYPE_SOCKET_CLIENT_EVENT,
848 G_TYPE_SOCKET_CONNECTABLE,
849 G_TYPE_IO_STREAM);
850 g_signal_set_va_marshaller (signal_id: signals[EVENT],
851 G_TYPE_FROM_CLASS (class),
852 va_marshaller: _g_cclosure_marshal_VOID__ENUM_OBJECT_OBJECTv);
853
854 g_object_class_install_property (oclass: gobject_class, property_id: PROP_FAMILY,
855 pspec: g_param_spec_enum (name: "family",
856 P_("Socket family"),
857 P_("The sockets address family to use for socket construction"),
858 enum_type: G_TYPE_SOCKET_FAMILY,
859 default_value: G_SOCKET_FAMILY_INVALID,
860 flags: G_PARAM_CONSTRUCT |
861 G_PARAM_READWRITE |
862 G_PARAM_STATIC_STRINGS));
863
864 g_object_class_install_property (oclass: gobject_class, property_id: PROP_TYPE,
865 pspec: g_param_spec_enum (name: "type",
866 P_("Socket type"),
867 P_("The sockets type to use for socket construction"),
868 enum_type: G_TYPE_SOCKET_TYPE,
869 default_value: G_SOCKET_TYPE_STREAM,
870 flags: G_PARAM_CONSTRUCT |
871 G_PARAM_READWRITE |
872 G_PARAM_STATIC_STRINGS));
873
874 g_object_class_install_property (oclass: gobject_class, property_id: PROP_PROTOCOL,
875 pspec: g_param_spec_enum (name: "protocol",
876 P_("Socket protocol"),
877 P_("The protocol to use for socket construction, or 0 for default"),
878 enum_type: G_TYPE_SOCKET_PROTOCOL,
879 default_value: G_SOCKET_PROTOCOL_DEFAULT,
880 flags: G_PARAM_CONSTRUCT |
881 G_PARAM_READWRITE |
882 G_PARAM_STATIC_STRINGS));
883
884 g_object_class_install_property (oclass: gobject_class, property_id: PROP_LOCAL_ADDRESS,
885 pspec: g_param_spec_object (name: "local-address",
886 P_("Local address"),
887 P_("The local address constructed sockets will be bound to"),
888 G_TYPE_SOCKET_ADDRESS,
889 flags: G_PARAM_CONSTRUCT |
890 G_PARAM_READWRITE |
891 G_PARAM_STATIC_STRINGS));
892
893 g_object_class_install_property (oclass: gobject_class, property_id: PROP_TIMEOUT,
894 pspec: g_param_spec_uint (name: "timeout",
895 P_("Socket timeout"),
896 P_("The I/O timeout for sockets, or 0 for none"),
897 minimum: 0, G_MAXUINT, default_value: 0,
898 flags: G_PARAM_CONSTRUCT |
899 G_PARAM_READWRITE |
900 G_PARAM_STATIC_STRINGS));
901
902 g_object_class_install_property (oclass: gobject_class, property_id: PROP_ENABLE_PROXY,
903 pspec: g_param_spec_boolean (name: "enable-proxy",
904 P_("Enable proxy"),
905 P_("Enable proxy support"),
906 TRUE,
907 flags: G_PARAM_CONSTRUCT |
908 G_PARAM_READWRITE |
909 G_PARAM_STATIC_STRINGS));
910
911 g_object_class_install_property (oclass: gobject_class, property_id: PROP_TLS,
912 pspec: g_param_spec_boolean (name: "tls",
913 P_("TLS"),
914 P_("Whether to create TLS connections"),
915 FALSE,
916 flags: G_PARAM_CONSTRUCT |
917 G_PARAM_READWRITE |
918 G_PARAM_STATIC_STRINGS));
919 g_object_class_install_property (oclass: gobject_class, property_id: PROP_TLS_VALIDATION_FLAGS,
920 pspec: g_param_spec_flags (name: "tls-validation-flags",
921 P_("TLS validation flags"),
922 P_("TLS validation flags to use"),
923 flags_type: G_TYPE_TLS_CERTIFICATE_FLAGS,
924 default_value: G_TLS_CERTIFICATE_VALIDATE_ALL,
925 flags: G_PARAM_CONSTRUCT |
926 G_PARAM_READWRITE |
927 G_PARAM_STATIC_STRINGS));
928
929 /**
930 * GSocketClient:proxy-resolver:
931 *
932 * The proxy resolver to use
933 *
934 * Since: 2.36
935 */
936 g_object_class_install_property (oclass: gobject_class, property_id: PROP_PROXY_RESOLVER,
937 pspec: g_param_spec_object (name: "proxy-resolver",
938 P_("Proxy resolver"),
939 P_("The proxy resolver to use"),
940 G_TYPE_PROXY_RESOLVER,
941 flags: G_PARAM_CONSTRUCT |
942 G_PARAM_READWRITE |
943 G_PARAM_STATIC_STRINGS));
944}
945
946static void
947g_socket_client_emit_event (GSocketClient *client,
948 GSocketClientEvent event,
949 GSocketConnectable *connectable,
950 GIOStream *connection)
951{
952 g_signal_emit (instance: client, signal_id: signals[EVENT], detail: 0,
953 event, connectable, connection);
954}
955
956/* Originally, GSocketClient returned whatever error occured last. Turns
957 * out this doesn't work well in practice. Consider the following case:
958 * DNS returns an IPv4 and IPv6 address. First we'll connect() to the
959 * IPv4 address, and say that succeeds, but TLS is enabled and the TLS
960 * handshake fails. Then we try the IPv6 address and receive ENETUNREACH
961 * because IPv6 isn't supported. We wind up returning NETWORK_UNREACHABLE
962 * even though the address can be pinged and a TLS error would be more
963 * appropriate. So instead, we now try to return the error corresponding
964 * to the latest attempted GSocketClientEvent in the connection process.
965 * TLS errors take precedence over proxy errors, which take precedence
966 * over connect() errors, which take precedence over DNS errors.
967 *
968 * Note that the example above considers a sync codepath, but this is an
969 * issue for the async codepath too, where events and errors may occur
970 * in confusing orders.
971 */
972typedef struct
973{
974 GError *tmp_error;
975 GError *best_error;
976 GSocketClientEvent best_error_event;
977} SocketClientErrorInfo;
978
979static SocketClientErrorInfo *
980socket_client_error_info_new (void)
981{
982 return g_new0 (SocketClientErrorInfo, 1);
983}
984
985static void
986socket_client_error_info_free (SocketClientErrorInfo *info)
987{
988 g_assert (info->tmp_error == NULL);
989 g_clear_error (err: &info->best_error);
990 g_free (mem: info);
991}
992
993static void
994consider_tmp_error (SocketClientErrorInfo *info,
995 GSocketClientEvent event)
996{
997 if (info->tmp_error == NULL)
998 return;
999
1000 /* If we ever add more GSocketClientEvents in the future, then we'll
1001 * no longer be able to use >= for this comparison, because future
1002 * events will compare greater than G_SOCKET_CLIENT_COMPLETE. Until
1003 * then, this is convenient. Note G_SOCKET_CLIENT_RESOLVING is 0 so we
1004 * need to use >= here or those errors would never be set. That means
1005 * if we get two errors on the same GSocketClientEvent, we wind up
1006 * preferring the last one, which is fine.
1007 */
1008 g_assert (event <= G_SOCKET_CLIENT_COMPLETE);
1009 if (event >= info->best_error_event)
1010 {
1011 g_clear_error (err: &info->best_error);
1012 info->best_error = info->tmp_error;
1013 info->tmp_error = NULL;
1014 info->best_error_event = event;
1015 }
1016 else
1017 {
1018 g_clear_error (err: &info->tmp_error);
1019 }
1020}
1021
1022/**
1023 * g_socket_client_connect:
1024 * @client: a #GSocketClient.
1025 * @connectable: a #GSocketConnectable specifying the remote address.
1026 * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
1027 * @error: #GError for error reporting, or %NULL to ignore.
1028 *
1029 * Tries to resolve the @connectable and make a network connection to it.
1030 *
1031 * Upon a successful connection, a new #GSocketConnection is constructed
1032 * and returned. The caller owns this new object and must drop their
1033 * reference to it when finished with it.
1034 *
1035 * The type of the #GSocketConnection object returned depends on the type of
1036 * the underlying socket that is used. For instance, for a TCP/IP connection
1037 * it will be a #GTcpConnection.
1038 *
1039 * The socket created will be the same family as the address that the
1040 * @connectable resolves to, unless family is set with g_socket_client_set_family()
1041 * or indirectly via g_socket_client_set_local_address(). The socket type
1042 * defaults to %G_SOCKET_TYPE_STREAM but can be set with
1043 * g_socket_client_set_socket_type().
1044 *
1045 * If a local address is specified with g_socket_client_set_local_address() the
1046 * socket will be bound to this address before connecting.
1047 *
1048 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
1049 *
1050 * Since: 2.22
1051 */
1052GSocketConnection *
1053g_socket_client_connect (GSocketClient *client,
1054 GSocketConnectable *connectable,
1055 GCancellable *cancellable,
1056 GError **error)
1057{
1058 GIOStream *connection = NULL;
1059 GSocketAddressEnumerator *enumerator = NULL;
1060 SocketClientErrorInfo *error_info;
1061 gboolean ever_resolved = FALSE;
1062
1063 error_info = socket_client_error_info_new ();
1064
1065 if (can_use_proxy (client))
1066 {
1067 enumerator = g_socket_connectable_proxy_enumerate (connectable);
1068 if (client->priv->proxy_resolver &&
1069 G_IS_PROXY_ADDRESS_ENUMERATOR (enumerator))
1070 {
1071 g_object_set (G_OBJECT (enumerator),
1072 first_property_name: "proxy-resolver", client->priv->proxy_resolver,
1073 NULL);
1074 }
1075 }
1076 else
1077 enumerator = g_socket_connectable_enumerate (connectable);
1078
1079 while (connection == NULL)
1080 {
1081 GSocketAddress *address = NULL;
1082 gboolean application_proxy = FALSE;
1083 GSocket *socket;
1084 gboolean using_proxy;
1085
1086 if (g_cancellable_is_cancelled (cancellable))
1087 {
1088 g_clear_error (err: &error_info->best_error);
1089 g_cancellable_set_error_if_cancelled (cancellable, error: &error_info->best_error);
1090 break;
1091 }
1092
1093 if (!ever_resolved)
1094 {
1095 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_RESOLVING,
1096 connectable, NULL);
1097 }
1098 address = g_socket_address_enumerator_next (enumerator, cancellable,
1099 error: &error_info->tmp_error);
1100 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_RESOLVING);
1101 if (!ever_resolved)
1102 {
1103 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_RESOLVED,
1104 connectable, NULL);
1105 ever_resolved = TRUE;
1106 }
1107
1108 if (address == NULL)
1109 {
1110 /* Enumeration is finished. */
1111 g_assert (&error_info->best_error != NULL);
1112 break;
1113 }
1114
1115 using_proxy = (G_IS_PROXY_ADDRESS (address) &&
1116 client->priv->enable_proxy);
1117
1118 socket = create_socket (client, dest_address: address, error: &error_info->tmp_error);
1119 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_CONNECTING);
1120 if (socket == NULL)
1121 {
1122 g_object_unref (object: address);
1123 continue;
1124 }
1125
1126 connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
1127 g_socket_connection_set_cached_remote_address (connection: (GSocketConnection*)connection, address);
1128 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_CONNECTING, connectable, connection);
1129
1130 if (g_socket_connection_connect (G_SOCKET_CONNECTION (connection),
1131 address, cancellable, error: &error_info->tmp_error))
1132 {
1133 g_socket_connection_set_cached_remote_address (connection: (GSocketConnection*)connection, NULL);
1134 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_CONNECTED, connectable, connection);
1135 }
1136 else
1137 {
1138 clarify_connect_error (error: error_info->tmp_error, connectable, address);
1139 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_CONNECTING);
1140 g_object_unref (object: connection);
1141 connection = NULL;
1142 }
1143
1144 if (connection && using_proxy)
1145 {
1146 GProxyAddress *proxy_addr = G_PROXY_ADDRESS (address);
1147 const gchar *protocol;
1148 GProxy *proxy;
1149
1150 protocol = g_proxy_address_get_protocol (proxy: proxy_addr);
1151
1152 /* The connection should not be anything else then TCP Connection,
1153 * but let's put a safety guard in case
1154 */
1155 if (!G_IS_TCP_CONNECTION (connection))
1156 {
1157 g_critical ("Trying to proxy over non-TCP connection, this is "
1158 "most likely a bug in GLib IO library.");
1159
1160 g_set_error_literal (err: &error_info->tmp_error,
1161 G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
1162 _("Proxying over a non-TCP connection is not supported."));
1163 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1164
1165 g_object_unref (object: connection);
1166 connection = NULL;
1167 }
1168 else if (g_hash_table_contains (hash_table: client->priv->app_proxies, key: protocol))
1169 {
1170 application_proxy = TRUE;
1171 }
1172 else if ((proxy = g_proxy_get_default_for_protocol (protocol)))
1173 {
1174 GIOStream *proxy_connection;
1175
1176 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING, connectable, connection);
1177 proxy_connection = g_proxy_connect (proxy,
1178 connection,
1179 proxy_address: proxy_addr,
1180 cancellable,
1181 error: &error_info->tmp_error);
1182 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1183
1184 g_object_unref (object: connection);
1185 connection = proxy_connection;
1186 g_object_unref (object: proxy);
1187
1188 if (connection)
1189 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_PROXY_NEGOTIATED, connectable, connection);
1190 }
1191 else
1192 {
1193 g_set_error (err: &error_info->tmp_error, G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
1194 _("Proxy protocol “%s” is not supported."),
1195 protocol);
1196 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1197 g_object_unref (object: connection);
1198 connection = NULL;
1199 }
1200 }
1201
1202 if (!application_proxy && connection && client->priv->tls)
1203 {
1204 GIOStream *tlsconn;
1205
1206 tlsconn = g_tls_client_connection_new (base_io_stream: connection, server_identity: connectable, error: &error_info->tmp_error);
1207 g_object_unref (object: connection);
1208 connection = tlsconn;
1209
1210 if (tlsconn)
1211 {
1212 g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
1213 flags: client->priv->tls_validation_flags);
1214 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_TLS_HANDSHAKING, connectable, connection);
1215 if (g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn),
1216 cancellable, error: &error_info->tmp_error))
1217 {
1218 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_TLS_HANDSHAKED, connectable, connection);
1219 }
1220 else
1221 {
1222 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_TLS_HANDSHAKING);
1223 g_object_unref (object: tlsconn);
1224 connection = NULL;
1225 }
1226 }
1227 else
1228 {
1229 consider_tmp_error (info: error_info, event: G_SOCKET_CLIENT_TLS_HANDSHAKING);
1230 }
1231 }
1232
1233 if (connection && !G_IS_SOCKET_CONNECTION (connection))
1234 {
1235 GSocketConnection *wrapper_connection;
1236
1237 wrapper_connection = g_tcp_wrapper_connection_new (base_io_stream: connection, socket);
1238 g_object_unref (object: connection);
1239 connection = (GIOStream *)wrapper_connection;
1240 }
1241
1242 g_object_unref (object: socket);
1243 g_object_unref (object: address);
1244 }
1245 g_object_unref (object: enumerator);
1246
1247 if (!connection)
1248 g_propagate_error (dest: error, g_steal_pointer (&error_info->best_error));
1249 socket_client_error_info_free (info: error_info);
1250
1251 g_socket_client_emit_event (client, event: G_SOCKET_CLIENT_COMPLETE, connectable, connection);
1252 return G_SOCKET_CONNECTION (connection);
1253}
1254
1255/**
1256 * g_socket_client_connect_to_host:
1257 * @client: a #GSocketClient
1258 * @host_and_port: the name and optionally port of the host to connect to
1259 * @default_port: the default port to connect to
1260 * @cancellable: (nullable): a #GCancellable, or %NULL
1261 * @error: a pointer to a #GError, or %NULL
1262 *
1263 * This is a helper function for g_socket_client_connect().
1264 *
1265 * Attempts to create a TCP connection to the named host.
1266 *
1267 * @host_and_port may be in any of a number of recognized formats; an IPv6
1268 * address, an IPv4 address, or a domain name (in which case a DNS
1269 * lookup is performed). Quoting with [] is supported for all address
1270 * types. A port override may be specified in the usual way with a
1271 * colon. Ports may be given as decimal numbers or symbolic names (in
1272 * which case an /etc/services lookup is performed).
1273 *
1274 * If no port override is given in @host_and_port then @default_port will be
1275 * used as the port number to connect to.
1276 *
1277 * In general, @host_and_port is expected to be provided by the user (allowing
1278 * them to give the hostname, and a port override if necessary) and
1279 * @default_port is expected to be provided by the application.
1280 *
1281 * In the case that an IP address is given, a single connection
1282 * attempt is made. In the case that a name is given, multiple
1283 * connection attempts may be made, in turn and according to the
1284 * number of address records in DNS, until a connection succeeds.
1285 *
1286 * Upon a successful connection, a new #GSocketConnection is constructed
1287 * and returned. The caller owns this new object and must drop their
1288 * reference to it when finished with it.
1289 *
1290 * In the event of any failure (DNS error, service not found, no hosts
1291 * connectable) %NULL is returned and @error (if non-%NULL) is set
1292 * accordingly.
1293 *
1294 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
1295 *
1296 * Since: 2.22
1297 */
1298GSocketConnection *
1299g_socket_client_connect_to_host (GSocketClient *client,
1300 const gchar *host_and_port,
1301 guint16 default_port,
1302 GCancellable *cancellable,
1303 GError **error)
1304{
1305 GSocketConnectable *connectable;
1306 GSocketConnection *connection;
1307
1308 connectable = g_network_address_parse (host_and_port, default_port, error);
1309 if (connectable == NULL)
1310 return NULL;
1311
1312 connection = g_socket_client_connect (client, connectable,
1313 cancellable, error);
1314 g_object_unref (object: connectable);
1315
1316 return connection;
1317}
1318
1319/**
1320 * g_socket_client_connect_to_service:
1321 * @client: a #GSocketConnection
1322 * @domain: a domain name
1323 * @service: the name of the service to connect to
1324 * @cancellable: (nullable): a #GCancellable, or %NULL
1325 * @error: a pointer to a #GError, or %NULL
1326 *
1327 * Attempts to create a TCP connection to a service.
1328 *
1329 * This call looks up the SRV record for @service at @domain for the
1330 * "tcp" protocol. It then attempts to connect, in turn, to each of
1331 * the hosts providing the service until either a connection succeeds
1332 * or there are no hosts remaining.
1333 *
1334 * Upon a successful connection, a new #GSocketConnection is constructed
1335 * and returned. The caller owns this new object and must drop their
1336 * reference to it when finished with it.
1337 *
1338 * In the event of any failure (DNS error, service not found, no hosts
1339 * connectable) %NULL is returned and @error (if non-%NULL) is set
1340 * accordingly.
1341 *
1342 * Returns: (transfer full): a #GSocketConnection if successful, or %NULL on error
1343 */
1344GSocketConnection *
1345g_socket_client_connect_to_service (GSocketClient *client,
1346 const gchar *domain,
1347 const gchar *service,
1348 GCancellable *cancellable,
1349 GError **error)
1350{
1351 GSocketConnectable *connectable;
1352 GSocketConnection *connection;
1353
1354 connectable = g_network_service_new (service, protocol: "tcp", domain);
1355 connection = g_socket_client_connect (client, connectable,
1356 cancellable, error);
1357 g_object_unref (object: connectable);
1358
1359 return connection;
1360}
1361
1362/**
1363 * g_socket_client_connect_to_uri:
1364 * @client: a #GSocketClient
1365 * @uri: A network URI
1366 * @default_port: the default port to connect to
1367 * @cancellable: (nullable): a #GCancellable, or %NULL
1368 * @error: a pointer to a #GError, or %NULL
1369 *
1370 * This is a helper function for g_socket_client_connect().
1371 *
1372 * Attempts to create a TCP connection with a network URI.
1373 *
1374 * @uri may be any valid URI containing an "authority" (hostname/port)
1375 * component. If a port is not specified in the URI, @default_port
1376 * will be used. TLS will be negotiated if #GSocketClient:tls is %TRUE.
1377 * (#GSocketClient does not know to automatically assume TLS for
1378 * certain URI schemes.)
1379 *
1380 * Using this rather than g_socket_client_connect() or
1381 * g_socket_client_connect_to_host() allows #GSocketClient to
1382 * determine when to use application-specific proxy protocols.
1383 *
1384 * Upon a successful connection, a new #GSocketConnection is constructed
1385 * and returned. The caller owns this new object and must drop their
1386 * reference to it when finished with it.
1387 *
1388 * In the event of any failure (DNS error, service not found, no hosts
1389 * connectable) %NULL is returned and @error (if non-%NULL) is set
1390 * accordingly.
1391 *
1392 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
1393 *
1394 * Since: 2.26
1395 */
1396GSocketConnection *
1397g_socket_client_connect_to_uri (GSocketClient *client,
1398 const gchar *uri,
1399 guint16 default_port,
1400 GCancellable *cancellable,
1401 GError **error)
1402{
1403 GSocketConnectable *connectable;
1404 GSocketConnection *connection;
1405
1406 connectable = g_network_address_parse_uri (uri, default_port, error);
1407 if (connectable == NULL)
1408 return NULL;
1409
1410 connection = g_socket_client_connect (client, connectable,
1411 cancellable, error);
1412 g_object_unref (object: connectable);
1413
1414 return connection;
1415}
1416
1417typedef struct
1418{
1419 GTask *task; /* unowned */
1420 GSocketClient *client;
1421
1422 GSocketConnectable *connectable;
1423 GSocketAddressEnumerator *enumerator;
1424 GCancellable *enumeration_cancellable;
1425
1426 GSList *connection_attempts;
1427 GSList *successful_connections;
1428 SocketClientErrorInfo *error_info;
1429
1430 gboolean enumerated_at_least_once;
1431 gboolean enumeration_completed;
1432 gboolean connection_in_progress;
1433 gboolean completed;
1434} GSocketClientAsyncConnectData;
1435
1436static void connection_attempt_unref (gpointer attempt);
1437
1438static void
1439g_socket_client_async_connect_data_free (GSocketClientAsyncConnectData *data)
1440{
1441 data->task = NULL;
1442 g_clear_object (&data->connectable);
1443 g_clear_object (&data->enumerator);
1444 g_clear_object (&data->enumeration_cancellable);
1445 g_slist_free_full (list: data->connection_attempts, free_func: connection_attempt_unref);
1446 g_slist_free_full (list: data->successful_connections, free_func: connection_attempt_unref);
1447
1448 g_clear_pointer (&data->error_info, socket_client_error_info_free);
1449
1450 g_slice_free (GSocketClientAsyncConnectData, data);
1451}
1452
1453typedef struct
1454{
1455 GSocketAddress *address;
1456 GSocket *socket;
1457 GIOStream *connection;
1458 GProxyAddress *proxy_addr;
1459 GSocketClientAsyncConnectData *data; /* unowned */
1460 GSource *timeout_source;
1461 GCancellable *cancellable;
1462 grefcount ref;
1463} ConnectionAttempt;
1464
1465static ConnectionAttempt *
1466connection_attempt_new (void)
1467{
1468 ConnectionAttempt *attempt = g_new0 (ConnectionAttempt, 1);
1469 g_ref_count_init (rc: &attempt->ref);
1470 return attempt;
1471}
1472
1473static ConnectionAttempt *
1474connection_attempt_ref (ConnectionAttempt *attempt)
1475{
1476 g_ref_count_inc (rc: &attempt->ref);
1477 return attempt;
1478}
1479
1480static void
1481connection_attempt_unref (gpointer pointer)
1482{
1483 ConnectionAttempt *attempt = pointer;
1484 if (g_ref_count_dec (rc: &attempt->ref))
1485 {
1486 g_clear_object (&attempt->address);
1487 g_clear_object (&attempt->socket);
1488 g_clear_object (&attempt->connection);
1489 g_clear_object (&attempt->cancellable);
1490 g_clear_object (&attempt->proxy_addr);
1491 if (attempt->timeout_source)
1492 {
1493 g_source_destroy (source: attempt->timeout_source);
1494 g_source_unref (source: attempt->timeout_source);
1495 }
1496 g_free (mem: attempt);
1497 }
1498}
1499
1500static void
1501connection_attempt_remove (ConnectionAttempt *attempt)
1502{
1503 attempt->data->connection_attempts = g_slist_remove (list: attempt->data->connection_attempts, data: attempt);
1504 connection_attempt_unref (pointer: attempt);
1505}
1506
1507static void
1508cancel_all_attempts (GSocketClientAsyncConnectData *data)
1509{
1510 GSList *l;
1511
1512 for (l = data->connection_attempts; l; l = g_slist_next (l))
1513 {
1514 ConnectionAttempt *attempt_entry = l->data;
1515 g_cancellable_cancel (cancellable: attempt_entry->cancellable);
1516 connection_attempt_unref (pointer: attempt_entry);
1517 }
1518 g_slist_free (list: data->connection_attempts);
1519 data->connection_attempts = NULL;
1520
1521 g_slist_free_full (list: data->successful_connections, free_func: connection_attempt_unref);
1522 data->successful_connections = NULL;
1523
1524 g_cancellable_cancel (cancellable: data->enumeration_cancellable);
1525}
1526
1527static void
1528g_socket_client_async_connect_complete (ConnectionAttempt *attempt)
1529{
1530 GSocketClientAsyncConnectData *data = attempt->data;
1531 GError *error = NULL;
1532 g_assert (attempt->connection);
1533 g_assert (!data->completed);
1534
1535 if (!G_IS_SOCKET_CONNECTION (attempt->connection))
1536 {
1537 GSocketConnection *wrapper_connection;
1538
1539 wrapper_connection = g_tcp_wrapper_connection_new (base_io_stream: attempt->connection, socket: attempt->socket);
1540 g_object_unref (object: attempt->connection);
1541 attempt->connection = (GIOStream *)wrapper_connection;
1542 }
1543
1544 data->completed = TRUE;
1545 cancel_all_attempts (data);
1546
1547 if (g_cancellable_set_error_if_cancelled (cancellable: g_task_get_cancellable (task: data->task), error: &error))
1548 {
1549 g_debug ("GSocketClient: Connection cancelled!");
1550 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_COMPLETE, connectable: data->connectable, NULL);
1551 g_task_return_error (task: data->task, g_steal_pointer (&error));
1552 }
1553 else
1554 {
1555 g_debug ("GSocketClient: Connection successful!");
1556 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_COMPLETE, connectable: data->connectable, connection: attempt->connection);
1557 g_task_return_pointer (task: data->task, g_steal_pointer (&attempt->connection), result_destroy: g_object_unref);
1558 }
1559
1560 connection_attempt_unref (pointer: attempt);
1561 g_object_unref (object: data->task);
1562}
1563
1564
1565static void
1566g_socket_client_enumerator_callback (GObject *object,
1567 GAsyncResult *result,
1568 gpointer user_data);
1569
1570static void
1571enumerator_next_async (GSocketClientAsyncConnectData *data,
1572 gboolean add_task_ref)
1573{
1574 /* Each enumeration takes a ref. This arg just avoids repeated unrefs when
1575 an enumeration starts another enumeration */
1576 if (add_task_ref)
1577 g_object_ref (data->task);
1578
1579 if (!data->enumerated_at_least_once)
1580 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_RESOLVING, connectable: data->connectable, NULL);
1581 g_debug ("GSocketClient: Starting new address enumeration");
1582 g_socket_address_enumerator_next_async (enumerator: data->enumerator,
1583 cancellable: data->enumeration_cancellable,
1584 callback: g_socket_client_enumerator_callback,
1585 user_data: data);
1586}
1587
1588static void try_next_connection_or_finish (GSocketClientAsyncConnectData *, gboolean);
1589
1590static void
1591g_socket_client_tls_handshake_callback (GObject *object,
1592 GAsyncResult *result,
1593 gpointer user_data)
1594{
1595 ConnectionAttempt *attempt = user_data;
1596 GSocketClientAsyncConnectData *data = attempt->data;
1597
1598 if (g_tls_connection_handshake_finish (G_TLS_CONNECTION (object),
1599 result,
1600 error: &data->error_info->tmp_error))
1601 {
1602 g_object_unref (object: attempt->connection);
1603 attempt->connection = G_IO_STREAM (object);
1604
1605 g_debug ("GSocketClient: TLS handshake succeeded");
1606 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_TLS_HANDSHAKED, connectable: data->connectable, connection: attempt->connection);
1607 g_socket_client_async_connect_complete (attempt);
1608 }
1609 else
1610 {
1611 g_object_unref (object);
1612 connection_attempt_unref (pointer: attempt);
1613
1614 g_debug ("GSocketClient: TLS handshake failed: %s", data->error_info->tmp_error->message);
1615 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_TLS_HANDSHAKING);
1616 try_next_connection_or_finish (data, TRUE);
1617 }
1618}
1619
1620static void
1621g_socket_client_tls_handshake (ConnectionAttempt *attempt)
1622{
1623 GSocketClientAsyncConnectData *data = attempt->data;
1624 GIOStream *tlsconn;
1625
1626 if (!data->client->priv->tls)
1627 {
1628 g_socket_client_async_connect_complete (attempt);
1629 return;
1630 }
1631
1632 g_debug ("GSocketClient: Starting TLS handshake");
1633 tlsconn = g_tls_client_connection_new (base_io_stream: attempt->connection,
1634 server_identity: data->connectable,
1635 error: &data->error_info->tmp_error);
1636 if (tlsconn)
1637 {
1638 g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
1639 flags: data->client->priv->tls_validation_flags);
1640 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_TLS_HANDSHAKING, connectable: data->connectable, G_IO_STREAM (tlsconn));
1641 g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn),
1642 G_PRIORITY_DEFAULT,
1643 cancellable: g_task_get_cancellable (task: data->task),
1644 callback: g_socket_client_tls_handshake_callback,
1645 user_data: attempt);
1646 }
1647 else
1648 {
1649 connection_attempt_unref (pointer: attempt);
1650
1651 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_TLS_HANDSHAKING);
1652 try_next_connection_or_finish (data, TRUE);
1653 }
1654}
1655
1656static void
1657g_socket_client_proxy_connect_callback (GObject *object,
1658 GAsyncResult *result,
1659 gpointer user_data)
1660{
1661 ConnectionAttempt *attempt = user_data;
1662 GSocketClientAsyncConnectData *data = attempt->data;
1663
1664 g_object_unref (object: attempt->connection);
1665 attempt->connection = g_proxy_connect_finish (G_PROXY (object),
1666 result,
1667 error: &data->error_info->tmp_error);
1668 if (attempt->connection)
1669 {
1670 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_PROXY_NEGOTIATED, connectable: data->connectable, connection: attempt->connection);
1671 g_socket_client_tls_handshake (attempt);
1672 }
1673 else
1674 {
1675 connection_attempt_unref (pointer: attempt);
1676
1677 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1678 try_next_connection_or_finish (data, TRUE);
1679 }
1680}
1681
1682static void
1683complete_connection_with_error (GSocketClientAsyncConnectData *data,
1684 GError *error)
1685{
1686 g_debug ("GSocketClient: Connection failed: %s", error->message);
1687 g_assert (!data->completed);
1688
1689 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_COMPLETE, connectable: data->connectable, NULL);
1690 data->completed = TRUE;
1691 cancel_all_attempts (data);
1692 g_task_return_error (task: data->task, error);
1693}
1694
1695static gboolean
1696task_completed_or_cancelled (GSocketClientAsyncConnectData *data)
1697{
1698 GTask *task = data->task;
1699 GCancellable *cancellable = g_task_get_cancellable (task);
1700 GError *error = NULL;
1701
1702 if (data->completed)
1703 return TRUE;
1704 else if (g_cancellable_set_error_if_cancelled (cancellable, error: &error))
1705 {
1706 complete_connection_with_error (data, g_steal_pointer (&error));
1707 return TRUE;
1708 }
1709 else
1710 return FALSE;
1711}
1712
1713static gboolean
1714try_next_successful_connection (GSocketClientAsyncConnectData *data)
1715{
1716 ConnectionAttempt *attempt;
1717 const gchar *protocol;
1718 GProxy *proxy;
1719
1720 if (data->connection_in_progress)
1721 return FALSE;
1722
1723 g_assert (data->successful_connections != NULL);
1724 attempt = data->successful_connections->data;
1725 g_assert (attempt != NULL);
1726 data->successful_connections = g_slist_remove (list: data->successful_connections, data: attempt);
1727 data->connection_in_progress = TRUE;
1728
1729 g_debug ("GSocketClient: Starting application layer connection");
1730
1731 if (!attempt->proxy_addr)
1732 {
1733 g_socket_client_tls_handshake (g_steal_pointer (&attempt));
1734 return TRUE;
1735 }
1736
1737 protocol = g_proxy_address_get_protocol (proxy: attempt->proxy_addr);
1738
1739 /* The connection should not be anything other than TCP,
1740 * but let's put a safety guard in case
1741 */
1742 if (!G_IS_TCP_CONNECTION (attempt->connection))
1743 {
1744 g_critical ("Trying to proxy over non-TCP connection, this is "
1745 "most likely a bug in GLib IO library.");
1746
1747 g_set_error_literal (err: &data->error_info->tmp_error,
1748 G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
1749 _("Proxying over a non-TCP connection is not supported."));
1750 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1751 }
1752 else if (g_hash_table_contains (hash_table: data->client->priv->app_proxies, key: protocol))
1753 {
1754 /* Simply complete the connection, we don't want to do TLS handshake
1755 * as the application proxy handling may need proxy handshake first */
1756 g_socket_client_async_connect_complete (g_steal_pointer (&attempt));
1757 return TRUE;
1758 }
1759 else if ((proxy = g_proxy_get_default_for_protocol (protocol)))
1760 {
1761 GIOStream *connection = attempt->connection;
1762 GProxyAddress *proxy_addr = attempt->proxy_addr;
1763
1764 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING, connectable: data->connectable, connection: attempt->connection);
1765 g_debug ("GSocketClient: Starting proxy connection");
1766 g_proxy_connect_async (proxy,
1767 connection,
1768 proxy_address: proxy_addr,
1769 cancellable: g_task_get_cancellable (task: data->task),
1770 callback: g_socket_client_proxy_connect_callback,
1771 g_steal_pointer (&attempt));
1772 g_object_unref (object: proxy);
1773 return TRUE;
1774 }
1775 else
1776 {
1777 g_set_error (err: &data->error_info->tmp_error, G_IO_ERROR, code: G_IO_ERROR_NOT_SUPPORTED,
1778 _("Proxy protocol “%s” is not supported."),
1779 protocol);
1780 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_PROXY_NEGOTIATING);
1781 }
1782
1783 data->connection_in_progress = FALSE;
1784 g_clear_pointer (&attempt, connection_attempt_unref);
1785 return FALSE; /* All non-return paths are failures */
1786}
1787
1788static void
1789try_next_connection_or_finish (GSocketClientAsyncConnectData *data,
1790 gboolean end_current_connection)
1791{
1792 if (end_current_connection)
1793 data->connection_in_progress = FALSE;
1794
1795 if (data->connection_in_progress)
1796 return;
1797
1798 /* Keep trying successful connections until one works, each iteration pops one */
1799 while (data->successful_connections)
1800 {
1801 if (try_next_successful_connection (data))
1802 return;
1803 }
1804
1805 if (!data->enumeration_completed)
1806 {
1807 enumerator_next_async (data, FALSE);
1808 return;
1809 }
1810
1811 complete_connection_with_error (data, g_steal_pointer (&data->error_info->best_error));
1812}
1813
1814static void
1815g_socket_client_connected_callback (GObject *source,
1816 GAsyncResult *result,
1817 gpointer user_data)
1818{
1819 ConnectionAttempt *attempt = user_data;
1820 GSocketClientAsyncConnectData *data = attempt->data;
1821
1822 if (task_completed_or_cancelled (data) || g_cancellable_is_cancelled (cancellable: attempt->cancellable))
1823 {
1824 g_object_unref (object: data->task);
1825 connection_attempt_unref (pointer: attempt);
1826 return;
1827 }
1828
1829 if (attempt->timeout_source)
1830 {
1831 g_source_destroy (source: attempt->timeout_source);
1832 g_clear_pointer (&attempt->timeout_source, g_source_unref);
1833 }
1834
1835 if (!g_socket_connection_connect_finish (G_SOCKET_CONNECTION (source),
1836 result, error: &data->error_info->tmp_error))
1837 {
1838 if (!g_cancellable_is_cancelled (cancellable: attempt->cancellable))
1839 {
1840 g_debug ("GSocketClient: Connection attempt failed: %s", data->error_info->tmp_error->message);
1841 clarify_connect_error (error: data->error_info->tmp_error, connectable: data->connectable, address: attempt->address);
1842 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_CONNECTING);
1843 connection_attempt_remove (attempt);
1844 connection_attempt_unref (pointer: attempt);
1845 try_next_connection_or_finish (data, FALSE);
1846 }
1847 else /* Silently ignore cancelled attempts */
1848 {
1849 g_clear_error (err: &data->error_info->tmp_error);
1850 g_object_unref (object: data->task);
1851 connection_attempt_unref (pointer: attempt);
1852 }
1853
1854 return;
1855 }
1856
1857 g_socket_connection_set_cached_remote_address (connection: (GSocketConnection*)attempt->connection, NULL);
1858 g_debug ("GSocketClient: TCP connection successful");
1859 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_CONNECTED, connectable: data->connectable, connection: attempt->connection);
1860
1861 /* wrong, but backward compatible */
1862 g_socket_set_blocking (socket: attempt->socket, TRUE);
1863
1864 /* This ends the parallel "happy eyeballs" portion of connecting.
1865 Now that we have a successful tcp connection we will attempt to connect
1866 at the TLS/Proxy layer. If those layers fail we will move on to the next
1867 connection.
1868 */
1869 connection_attempt_remove (attempt);
1870 data->successful_connections = g_slist_append (list: data->successful_connections, g_steal_pointer (&attempt));
1871 try_next_connection_or_finish (data, FALSE);
1872}
1873
1874static gboolean
1875on_connection_attempt_timeout (gpointer data)
1876{
1877 ConnectionAttempt *attempt = data;
1878
1879 if (!attempt->data->enumeration_completed)
1880 {
1881 g_debug ("GSocketClient: Timeout reached, trying another enumeration");
1882 enumerator_next_async (data: attempt->data, TRUE);
1883 }
1884
1885 g_clear_pointer (&attempt->timeout_source, g_source_unref);
1886 return G_SOURCE_REMOVE;
1887}
1888
1889static void
1890on_connection_cancelled (GCancellable *cancellable,
1891 gpointer data)
1892{
1893 GCancellable *linked_cancellable = G_CANCELLABLE (data);
1894
1895 g_cancellable_cancel (cancellable: linked_cancellable);
1896}
1897
1898static void
1899g_socket_client_enumerator_callback (GObject *object,
1900 GAsyncResult *result,
1901 gpointer user_data)
1902{
1903 GSocketClientAsyncConnectData *data = user_data;
1904 GSocketAddress *address = NULL;
1905 GSocket *socket;
1906 ConnectionAttempt *attempt;
1907
1908 if (task_completed_or_cancelled (data))
1909 {
1910 g_object_unref (object: data->task);
1911 return;
1912 }
1913
1914 address = g_socket_address_enumerator_next_finish (enumerator: data->enumerator,
1915 result, error: &data->error_info->tmp_error);
1916 if (address == NULL)
1917 {
1918 if (G_UNLIKELY (data->enumeration_completed))
1919 return;
1920
1921 data->enumeration_completed = TRUE;
1922 g_debug ("GSocketClient: Address enumeration completed (out of addresses)");
1923
1924 /* As per API docs: We only care about error if it's the first call,
1925 after that the enumerator is done.
1926
1927 Note that we don't care about cancellation errors because
1928 task_completed_or_cancelled() above should handle that.
1929
1930 If this fails and nothing is in progress then we will complete task here.
1931 */
1932 if ((data->enumerated_at_least_once && !data->connection_attempts && !data->connection_in_progress) ||
1933 !data->enumerated_at_least_once)
1934 {
1935 g_debug ("GSocketClient: Address enumeration failed: %s",
1936 data->error_info->tmp_error ? data->error_info->tmp_error->message : NULL);
1937 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_RESOLVING);
1938 g_assert (data->error_info->best_error);
1939 complete_connection_with_error (data, g_steal_pointer (&data->error_info->best_error));
1940 }
1941
1942 /* Enumeration should never trigger again, drop our ref */
1943 g_object_unref (object: data->task);
1944 return;
1945 }
1946
1947 g_debug ("GSocketClient: Address enumeration succeeded");
1948 if (!data->enumerated_at_least_once)
1949 {
1950 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_RESOLVED,
1951 connectable: data->connectable, NULL);
1952 data->enumerated_at_least_once = TRUE;
1953 }
1954
1955 socket = create_socket (client: data->client, dest_address: address, error: &data->error_info->tmp_error);
1956 if (socket == NULL)
1957 {
1958 g_object_unref (object: address);
1959 consider_tmp_error (info: data->error_info, event: G_SOCKET_CLIENT_CONNECTING);
1960 enumerator_next_async (data, FALSE);
1961 return;
1962 }
1963
1964 attempt = connection_attempt_new ();
1965 attempt->data = data;
1966 attempt->socket = socket;
1967 attempt->address = address;
1968 attempt->cancellable = g_cancellable_new ();
1969 attempt->connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
1970 attempt->timeout_source = g_timeout_source_new (HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS);
1971
1972 if (G_IS_PROXY_ADDRESS (address) && data->client->priv->enable_proxy)
1973 attempt->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address));
1974
1975 g_source_set_callback (source: attempt->timeout_source, func: on_connection_attempt_timeout, data: attempt, NULL);
1976 g_source_attach (source: attempt->timeout_source, context: g_task_get_context (task: data->task));
1977 data->connection_attempts = g_slist_append (list: data->connection_attempts, data: attempt);
1978
1979 if (g_task_get_cancellable (task: data->task))
1980 g_cancellable_connect (cancellable: g_task_get_cancellable (task: data->task), G_CALLBACK (on_connection_cancelled),
1981 g_object_ref (attempt->cancellable), data_destroy_func: g_object_unref);
1982
1983 g_socket_connection_set_cached_remote_address (connection: (GSocketConnection *)attempt->connection, address);
1984 g_debug ("GSocketClient: Starting TCP connection attempt");
1985 g_socket_client_emit_event (client: data->client, event: G_SOCKET_CLIENT_CONNECTING, connectable: data->connectable, connection: attempt->connection);
1986 g_socket_connection_connect_async (G_SOCKET_CONNECTION (attempt->connection),
1987 address,
1988 cancellable: attempt->cancellable,
1989 callback: g_socket_client_connected_callback, user_data: connection_attempt_ref (attempt));
1990}
1991
1992/**
1993 * g_socket_client_connect_async:
1994 * @client: a #GSocketClient
1995 * @connectable: a #GSocketConnectable specifying the remote address.
1996 * @cancellable: (nullable): a #GCancellable, or %NULL
1997 * @callback: (scope async): a #GAsyncReadyCallback
1998 * @user_data: (closure): user data for the callback
1999 *
2000 * This is the asynchronous version of g_socket_client_connect().
2001 *
2002 * You may wish to prefer the asynchronous version even in synchronous
2003 * command line programs because, since 2.60, it implements
2004 * [RFC 8305](https://tools.ietf.org/html/rfc8305) "Happy Eyeballs"
2005 * recommendations to work around long connection timeouts in networks
2006 * where IPv6 is broken by performing an IPv4 connection simultaneously
2007 * without waiting for IPv6 to time out, which is not supported by the
2008 * synchronous call. (This is not an API guarantee, and may change in
2009 * the future.)
2010 *
2011 * When the operation is finished @callback will be
2012 * called. You can then call g_socket_client_connect_finish() to get
2013 * the result of the operation.
2014 *
2015 * Since: 2.22
2016 */
2017void
2018g_socket_client_connect_async (GSocketClient *client,
2019 GSocketConnectable *connectable,
2020 GCancellable *cancellable,
2021 GAsyncReadyCallback callback,
2022 gpointer user_data)
2023{
2024 GSocketClientAsyncConnectData *data;
2025
2026 g_return_if_fail (G_IS_SOCKET_CLIENT (client));
2027
2028 data = g_slice_new0 (GSocketClientAsyncConnectData);
2029 data->client = client;
2030 data->connectable = g_object_ref (connectable);
2031 data->error_info = socket_client_error_info_new ();
2032
2033 if (can_use_proxy (client))
2034 {
2035 data->enumerator = g_socket_connectable_proxy_enumerate (connectable);
2036 if (client->priv->proxy_resolver &&
2037 G_IS_PROXY_ADDRESS_ENUMERATOR (data->enumerator))
2038 {
2039 g_object_set (G_OBJECT (data->enumerator),
2040 first_property_name: "proxy-resolver", client->priv->proxy_resolver,
2041 NULL);
2042 }
2043 }
2044 else
2045 data->enumerator = g_socket_connectable_enumerate (connectable);
2046
2047 /* This function tries to match the behavior of g_socket_client_connect ()
2048 which is simple enough but much of it is done in parallel to be as responsive
2049 as possible as per Happy Eyeballs (RFC 8305). This complicates flow quite a
2050 bit but we can describe it in 3 sections:
2051
2052 Firstly we have address enumeration (DNS):
2053 - This may be triggered multiple times by enumerator_next_async().
2054 - It also has its own cancellable (data->enumeration_cancellable).
2055 - Enumeration is done lazily because GNetworkAddressAddressEnumerator
2056 also does work in parallel and may lazily add new addresses.
2057 - If the first enumeration errors then the task errors. Otherwise all enumerations
2058 will potentially be used (until task or enumeration is cancelled).
2059
2060 Then we start attempting connections (TCP):
2061 - Each connection is independent and kept in a ConnectionAttempt object.
2062 - They each hold a ref on the main task and have their own cancellable.
2063 - Multiple attempts may happen in parallel as per Happy Eyeballs.
2064 - Upon failure or timeouts more connection attempts are made.
2065 - If no connections succeed the task errors.
2066 - Upon success they are kept in a list of successful connections.
2067
2068 Lastly we connect at the application layer (TLS, Proxies):
2069 - These are done in serial.
2070 - The reasoning here is that Happy Eyeballs is about making bad connections responsive
2071 at the IP/TCP layers. Issues at the application layer are generally not due to
2072 connectivity issues but rather misconfiguration.
2073 - Upon failure it will try the next TCP connection until it runs out and
2074 the task errors.
2075 - Upon success it cancels everything remaining (enumeration and connections)
2076 and returns the connection.
2077 */
2078
2079 data->task = g_task_new (source_object: client, cancellable, callback, callback_data: user_data);
2080 g_task_set_check_cancellable (task: data->task, FALSE); /* We handle this manually */
2081 g_task_set_source_tag (data->task, g_socket_client_connect_async);
2082 g_task_set_task_data (task: data->task, task_data: data, task_data_destroy: (GDestroyNotify)g_socket_client_async_connect_data_free);
2083
2084 data->enumeration_cancellable = g_cancellable_new ();
2085 if (cancellable)
2086 g_cancellable_connect (cancellable, G_CALLBACK (on_connection_cancelled),
2087 g_object_ref (data->enumeration_cancellable), data_destroy_func: g_object_unref);
2088
2089 enumerator_next_async (data, FALSE);
2090}
2091
2092/**
2093 * g_socket_client_connect_to_host_async:
2094 * @client: a #GSocketClient
2095 * @host_and_port: the name and optionally the port of the host to connect to
2096 * @default_port: the default port to connect to
2097 * @cancellable: (nullable): a #GCancellable, or %NULL
2098 * @callback: (scope async): a #GAsyncReadyCallback
2099 * @user_data: (closure): user data for the callback
2100 *
2101 * This is the asynchronous version of g_socket_client_connect_to_host().
2102 *
2103 * When the operation is finished @callback will be
2104 * called. You can then call g_socket_client_connect_to_host_finish() to get
2105 * the result of the operation.
2106 *
2107 * Since: 2.22
2108 */
2109void
2110g_socket_client_connect_to_host_async (GSocketClient *client,
2111 const gchar *host_and_port,
2112 guint16 default_port,
2113 GCancellable *cancellable,
2114 GAsyncReadyCallback callback,
2115 gpointer user_data)
2116{
2117 GSocketConnectable *connectable;
2118 GError *error;
2119
2120 error = NULL;
2121 connectable = g_network_address_parse (host_and_port, default_port,
2122 error: &error);
2123 if (connectable == NULL)
2124 {
2125 g_task_report_error (source_object: client, callback, callback_data: user_data,
2126 source_tag: g_socket_client_connect_to_host_async,
2127 error);
2128 }
2129 else
2130 {
2131 g_socket_client_connect_async (client,
2132 connectable, cancellable,
2133 callback, user_data);
2134 g_object_unref (object: connectable);
2135 }
2136}
2137
2138/**
2139 * g_socket_client_connect_to_service_async:
2140 * @client: a #GSocketClient
2141 * @domain: a domain name
2142 * @service: the name of the service to connect to
2143 * @cancellable: (nullable): a #GCancellable, or %NULL
2144 * @callback: (scope async): a #GAsyncReadyCallback
2145 * @user_data: (closure): user data for the callback
2146 *
2147 * This is the asynchronous version of
2148 * g_socket_client_connect_to_service().
2149 *
2150 * Since: 2.22
2151 */
2152void
2153g_socket_client_connect_to_service_async (GSocketClient *client,
2154 const gchar *domain,
2155 const gchar *service,
2156 GCancellable *cancellable,
2157 GAsyncReadyCallback callback,
2158 gpointer user_data)
2159{
2160 GSocketConnectable *connectable;
2161
2162 connectable = g_network_service_new (service, protocol: "tcp", domain);
2163 g_socket_client_connect_async (client,
2164 connectable, cancellable,
2165 callback, user_data);
2166 g_object_unref (object: connectable);
2167}
2168
2169/**
2170 * g_socket_client_connect_to_uri_async:
2171 * @client: a #GSocketClient
2172 * @uri: a network uri
2173 * @default_port: the default port to connect to
2174 * @cancellable: (nullable): a #GCancellable, or %NULL
2175 * @callback: (scope async): a #GAsyncReadyCallback
2176 * @user_data: (closure): user data for the callback
2177 *
2178 * This is the asynchronous version of g_socket_client_connect_to_uri().
2179 *
2180 * When the operation is finished @callback will be
2181 * called. You can then call g_socket_client_connect_to_uri_finish() to get
2182 * the result of the operation.
2183 *
2184 * Since: 2.26
2185 */
2186void
2187g_socket_client_connect_to_uri_async (GSocketClient *client,
2188 const gchar *uri,
2189 guint16 default_port,
2190 GCancellable *cancellable,
2191 GAsyncReadyCallback callback,
2192 gpointer user_data)
2193{
2194 GSocketConnectable *connectable;
2195 GError *error;
2196
2197 error = NULL;
2198 connectable = g_network_address_parse_uri (uri, default_port, error: &error);
2199 if (connectable == NULL)
2200 {
2201 g_task_report_error (source_object: client, callback, callback_data: user_data,
2202 source_tag: g_socket_client_connect_to_uri_async,
2203 error);
2204 }
2205 else
2206 {
2207 g_debug("g_socket_client_connect_to_uri_async");
2208 g_socket_client_connect_async (client,
2209 connectable, cancellable,
2210 callback, user_data);
2211 g_object_unref (object: connectable);
2212 }
2213}
2214
2215
2216/**
2217 * g_socket_client_connect_finish:
2218 * @client: a #GSocketClient.
2219 * @result: a #GAsyncResult.
2220 * @error: a #GError location to store the error occurring, or %NULL to
2221 * ignore.
2222 *
2223 * Finishes an async connect operation. See g_socket_client_connect_async()
2224 *
2225 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
2226 *
2227 * Since: 2.22
2228 */
2229GSocketConnection *
2230g_socket_client_connect_finish (GSocketClient *client,
2231 GAsyncResult *result,
2232 GError **error)
2233{
2234 g_return_val_if_fail (g_task_is_valid (result, client), NULL);
2235
2236 return g_task_propagate_pointer (G_TASK (result), error);
2237}
2238
2239/**
2240 * g_socket_client_connect_to_host_finish:
2241 * @client: a #GSocketClient.
2242 * @result: a #GAsyncResult.
2243 * @error: a #GError location to store the error occurring, or %NULL to
2244 * ignore.
2245 *
2246 * Finishes an async connect operation. See g_socket_client_connect_to_host_async()
2247 *
2248 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
2249 *
2250 * Since: 2.22
2251 */
2252GSocketConnection *
2253g_socket_client_connect_to_host_finish (GSocketClient *client,
2254 GAsyncResult *result,
2255 GError **error)
2256{
2257 return g_socket_client_connect_finish (client, result, error);
2258}
2259
2260/**
2261 * g_socket_client_connect_to_service_finish:
2262 * @client: a #GSocketClient.
2263 * @result: a #GAsyncResult.
2264 * @error: a #GError location to store the error occurring, or %NULL to
2265 * ignore.
2266 *
2267 * Finishes an async connect operation. See g_socket_client_connect_to_service_async()
2268 *
2269 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
2270 *
2271 * Since: 2.22
2272 */
2273GSocketConnection *
2274g_socket_client_connect_to_service_finish (GSocketClient *client,
2275 GAsyncResult *result,
2276 GError **error)
2277{
2278 return g_socket_client_connect_finish (client, result, error);
2279}
2280
2281/**
2282 * g_socket_client_connect_to_uri_finish:
2283 * @client: a #GSocketClient.
2284 * @result: a #GAsyncResult.
2285 * @error: a #GError location to store the error occurring, or %NULL to
2286 * ignore.
2287 *
2288 * Finishes an async connect operation. See g_socket_client_connect_to_uri_async()
2289 *
2290 * Returns: (transfer full): a #GSocketConnection on success, %NULL on error.
2291 *
2292 * Since: 2.26
2293 */
2294GSocketConnection *
2295g_socket_client_connect_to_uri_finish (GSocketClient *client,
2296 GAsyncResult *result,
2297 GError **error)
2298{
2299 return g_socket_client_connect_finish (client, result, error);
2300}
2301
2302/**
2303 * g_socket_client_add_application_proxy:
2304 * @client: a #GSocketClient
2305 * @protocol: The proxy protocol
2306 *
2307 * Enable proxy protocols to be handled by the application. When the
2308 * indicated proxy protocol is returned by the #GProxyResolver,
2309 * #GSocketClient will consider this protocol as supported but will
2310 * not try to find a #GProxy instance to handle handshaking. The
2311 * application must check for this case by calling
2312 * g_socket_connection_get_remote_address() on the returned
2313 * #GSocketConnection, and seeing if it's a #GProxyAddress of the
2314 * appropriate type, to determine whether or not it needs to handle
2315 * the proxy handshaking itself.
2316 *
2317 * This should be used for proxy protocols that are dialects of
2318 * another protocol such as HTTP proxy. It also allows cohabitation of
2319 * proxy protocols that are reused between protocols. A good example
2320 * is HTTP. It can be used to proxy HTTP, FTP and Gopher and can also
2321 * be use as generic socket proxy through the HTTP CONNECT method.
2322 *
2323 * When the proxy is detected as being an application proxy, TLS handshake
2324 * will be skipped. This is required to let the application do the proxy
2325 * specific handshake.
2326 */
2327void
2328g_socket_client_add_application_proxy (GSocketClient *client,
2329 const gchar *protocol)
2330{
2331 g_hash_table_add (hash_table: client->priv->app_proxies, key: g_strdup (str: protocol));
2332}
2333

source code of gtk/subprojects/glib/gio/gsocketclient.c