1 /*
2  * Copyright (c) 2012 Tim Ruehsen
3  * Copyright (c) 2015-2021 Free Software Foundation, Inc.
4  *
5  * This file is part of libwget.
6  *
7  * Libwget is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation, either version 3 of the License, or
10  * (at your option) any later version.
11  *
12  * Libwget 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
15  * GNU Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with libwget.  If not, see <https://www.gnu.org/licenses/>.
19  *
20  *
21  * network routines
22  *
23  * Changelog
24  * 25.04.2012  Tim Ruehsen  created
25  * 16.11.2012               new functions tcp_set_family() and tcp_set_preferred_family()
26  *
27  * RFC 7413: TCP Fast Open
28  */
29 
30 #include <config.h>
31 
32 #include <sys/types.h>
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <stdarg.h>
38 #include <c-ctype.h>
39 #include <time.h>
40 #include <errno.h>
41 #include <sys/socket.h>
42 #include <netdb.h>
43 #include <netinet/in.h>
44 
45 #ifdef HAVE_NETINET_TCP_H
46 #	include <netinet/tcp.h>
47 #endif
48 
49 #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
50 # include <sys/ioctl.h>
51 #else
52 # include <fcntl.h>
53 #endif
54 
55 #if defined __APPLE__ && defined __MACH__ && defined CONNECT_DATA_IDEMPOTENT && defined CONNECT_RESUME_ON_READ_WRITE
56 # define TCP_FASTOPEN_OSX
57 #elif defined TCP_FASTOPEN_CONNECT // since Linux 4.11
58 # define TCP_FASTOPEN_LINUX_411
59 #elif defined TCP_FASTOPEN && defined MSG_FASTOPEN
60 # define TCP_FASTOPEN_LINUX
61 #endif
62 
63 #include <wget.h>
64 #include "private.h"
65 #include "net.h"
66 
67 /**
68  * \file
69  * \brief Functions to work with TCP sockets and SSL/TLS
70  * \defgroup libwget-net TCP sockets
71  *
72  * @{
73  *
74  * TCP sockets and DNS cache management functions.
75  *
76  * The following features are supported:
77  *
78  *  - TCP Fast Open ([RFC 7413](https://tools.ietf.org/html/rfc7413))
79  *  - SSL/TLS
80  *
81  * Most functions here take a `wget_tcp` structure as argument.
82  *
83  * The `wget_tcp` structure represents a TCP connection. You create it with wget_tcp_init()
84  * and destroy it with wget_tcp_deinit(). You can connect to a remote host with wget_tcp_connect(),
85  * or listen for incoming connections (and accept them) with wget_tcp_listen() and wget_tcp_accept().
86  * You end a connection with wget_tcp_close().
87  *
88  * There are several knobs you can use to customize the behavior of most functions here.
89  * The list that follows describes the most important parameters, although you can look at the getter and setter
90  * functions here to see them all (`wget_tcp_get_xxx`, `wget_tcp_set_xxx`).
91  *
92  *  - Timeout: maximum time to wait for an operation to complete. For example, for wget_tcp_read(), it sets the maximum time
93  *  to wait until some data is available to read. Most functions here can be non-blocking (with timeout = 0) returning immediately
94  *  or they can block indefinitely until something happens (with timeout = -1). For any value greater than zero,
95  *  the timeout is taken as milliseconds.
96  *  - Family and preferred family: these are used to determine which address family should be used when resolving a host name or
97  *  IP address. You probably use `AF_INET` or `AF_INET6` most of the time. The first one forces the library to use that family,
98  *  failing if it cannot find any IP address with it. The second one is just a hint, about which family you would prefer; it will try
99  *  to get an address of that family if possible, and will get another one if not.
100  *  - SSL/TLS: do you want to use TLS?
101  *
102  *  When you create a new `wget_tcp` with wget_tcp_init(), it is initialized with the following parameters:
103  *
104  *   - Timeout: -1
105  *   - Connection timeout (max. time to wait for a connection to be accepted by the remote host): -1
106  *   - DNS timeout (max. time to wait for a DNS query to return): -1
107  *   - Family: `AF_UNSPEC` (basically means "I don't care, pick the first one available").
108  */
109 
110 static struct wget_tcp_st global_tcp = {
111 	.sockfd = -1,
112 	.dns_timeout = -1,
113 	.connect_timeout = -1,
114 	.timeout = -1,
115 	.family = AF_UNSPEC,
116 #if defined TCP_FASTOPEN_OSX
117 	.tcp_fastopen = 1,
118 #elif defined TCP_FASTOPEN_LINUX_411
119 	.tcp_fastopen = 1,
120 #elif defined TCP_FASTOPEN_LINUX
121 	.tcp_fastopen = 1,
122 	.first_send = 1,
123 #endif
124 };
125 
126 /* for Windows compatibility */
127 #include "sockets.h"
128 /**
129  * \return 0 for success, else failure
130  *
131  * Initialize the resources needed for network operations.
132  */
wget_net_init(void)133 int wget_net_init(void)
134 {
135 	int rc = gl_sockets_startup(SOCKETS_2_2);
136 
137 	return rc ? -1 : 0;
138 }
139 
140 /**
141  * \return 0 for success, else failure
142  *
143  * Free the resources allocated by wget_net_init().
144  */
wget_net_deinit(void)145 int wget_net_deinit(void)
146 {
147 	int rc = gl_sockets_cleanup();
148 
149 	return rc ? -1 : 0;
150 }
151 
value_to_family(int value)152 static int WGET_GCC_CONST value_to_family(int value)
153 {
154 	switch (value) {
155 	case WGET_NET_FAMILY_IPV4:
156 		return AF_INET;
157 	case WGET_NET_FAMILY_IPV6:
158 		return AF_INET6;
159 	default:
160 		return AF_UNSPEC;
161 	}
162 }
163 
family_to_value(int family)164 static int WGET_GCC_CONST family_to_value(int family)
165 {
166 	switch (family) {
167 	case AF_INET:
168 		return WGET_NET_FAMILY_IPV4;
169 	case AF_INET6:
170 		return WGET_NET_FAMILY_IPV6;
171 	default:
172 		return WGET_NET_FAMILY_ANY;
173 	}
174 }
175 
176 /**
177  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
178  * \param[in] protocol The protocol, either WGET_PROTOCOL_HTTP_2_0 or WGET_PROTOCOL_HTTP_1_1.
179  *
180  * Set the protocol for the connection provided, or globally.
181  *
182  * If \p tcp is NULL, theprotocol will be set globally (for all connections). Otherwise,
183  * only for the provided connection (\p tcp).
184  */
wget_tcp_set_dns(wget_tcp * tcp,wget_dns * dns)185 void wget_tcp_set_dns(wget_tcp *tcp, wget_dns *dns)
186 {
187 	(tcp ? tcp : &global_tcp)->dns = dns;
188 }
189 
190 /**
191  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
192  * \param[in] tcp_fastopen 1 or 0, whether to enable or disable TCP Fast Open.
193  *
194  * Enable or disable TCP Fast Open ([RFC 7413](https://tools.ietf.org/html/rfc7413)), if available.
195  *
196  * This function is a no-op on systems where TCP Fast Open is not supported.
197  *
198  * If \p tcp is NULL, TCP Fast Open is enabled or disabled globally.
199  */
wget_tcp_set_tcp_fastopen(wget_tcp * tcp,bool tcp_fastopen)200 void wget_tcp_set_tcp_fastopen(wget_tcp *tcp, bool tcp_fastopen)
201 {
202 #if defined TCP_FASTOPEN_OSX || defined TCP_FASTOPEN_LINUX || defined TCP_FASTOPEN_LINUX_411
203 	(tcp ? tcp : &global_tcp)->tcp_fastopen = tcp_fastopen;
204 #else
205 	(void) tcp; (void) tcp_fastopen;
206 #endif
207 }
208 
209 /**
210  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
211  * \return 1 if TCP Fast Open is enabled, 0 otherwise.
212  *
213  * Tells whether TCP Fast Open is enabled or not.
214  *
215  * You can enable and disable it with wget_tcp_set_tcp_fastopen().
216  */
wget_tcp_get_tcp_fastopen(wget_tcp * tcp)217 bool wget_tcp_get_tcp_fastopen(wget_tcp *tcp)
218 {
219 	return (tcp ? tcp : &global_tcp)->tcp_fastopen;
220 }
221 
222 /**
223  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
224  * \param[in] false_start 1 or 0, whether to enable or disable TLS False Start.
225  *
226  * Enable or disable TLS False Start ([RFC 7918](https://tools.ietf.org/html/rfc7413)).
227  *
228  * If \p tcp is NULL, TLS False Start is enabled or disabled globally.
229  */
wget_tcp_set_tls_false_start(wget_tcp * tcp,bool false_start)230 void wget_tcp_set_tls_false_start(wget_tcp *tcp, bool false_start)
231 {
232 	(tcp ? tcp : &global_tcp)->tls_false_start = false_start;
233 }
234 
235 /**
236  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
237  * \return 1 if TLS False Start is enabled, 0 otherwise.
238  *
239  * Tells whether TLS False Start is enabled or not.
240  *
241  * You can enable and disable it with wget_tcp_set_tls_false_start().
242  */
wget_tcp_get_tls_false_start(wget_tcp * tcp)243 bool wget_tcp_get_tls_false_start(wget_tcp *tcp)
244 {
245 	return (tcp ? tcp : &global_tcp)->tls_false_start;
246 }
247 
248 /**
249  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
250  * \param[in] protocol The protocol, either WGET_PROTOCOL_HTTP_2_0 or WGET_PROTOCOL_HTTP_1_1.
251  *
252  * Set the protocol for the connection provided, or globally.
253  *
254  * If \p tcp is NULL, theprotocol will be set globally (for all connections). Otherwise,
255  * only for the provided connection (\p tcp).
256  */
wget_tcp_set_protocol(wget_tcp * tcp,int protocol)257 void wget_tcp_set_protocol(wget_tcp *tcp, int protocol)
258 {
259 	(tcp ? tcp : &global_tcp)->protocol = protocol;
260 }
261 
262 /**
263  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
264  * \return The protocol with this connection, currently WGET_PROTOCOL_HTTP_2_0 or WGET_PROTOCOL_HTTP_1_1.
265  *
266  * Get protocol used with the provided connection, or globally (if \p tcp is NULL).
267  */
wget_tcp_get_protocol(wget_tcp * tcp)268 int wget_tcp_get_protocol(wget_tcp *tcp)
269 {
270 	return (tcp ? tcp : &global_tcp)->protocol;
271 }
272 
273 /**
274  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
275  * \param[in] family One of the socket families defined in `<socket.h>`, such as `AF_INET` or `AF_INET6`.
276  *
277  * Tells the preferred address family that should be used when establishing a TCP connection.
278  *
279  * wget_tcp_resolve() will favor that and pick an address of that family if possible.
280  *
281  * If \p tcp is NULL, the preferred address family will be set globally.
282  */
wget_tcp_set_preferred_family(wget_tcp * tcp,int family)283 void wget_tcp_set_preferred_family(wget_tcp *tcp, int family)
284 {
285 	(tcp ? tcp : &global_tcp)->preferred_family = value_to_family(family);
286 }
287 
288 /**
289  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
290  * \return One of the socket families defined in `<socket.h>`, such as `AF_INET` or `AF_INET6`.
291  *
292  * Get the preferred address family that was previously set with wget_tcp_set_preferred_family().
293  */
wget_tcp_get_preferred_family(wget_tcp * tcp)294 int wget_tcp_get_preferred_family(wget_tcp *tcp)
295 {
296 	return family_to_value((tcp ? tcp : &global_tcp)->preferred_family);
297 }
298 
299 /**
300  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
301  * \param[in] family One of the socket families defined in `<socket.h>`, such as `AF_INET` or `AF_INET6`.
302  *
303  * Tell the address family that will be used when establishing a TCP connection.
304  *
305  * wget_tcp_resolve() will pick an address of that family, or fail if it cannot find one.
306  *
307  * If \p tcp is NULL, the address family will be set globally.
308  */
wget_tcp_set_family(wget_tcp * tcp,int family)309 void wget_tcp_set_family(wget_tcp *tcp, int family)
310 {
311 	(tcp ? tcp : &global_tcp)->family = value_to_family(family);
312 }
313 
314 /**
315  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
316  * \return One of the socket families defined in `<socket.h>`, such as `AF_INET` or `AF_INET6`.
317  *
318  * Get the address family that was previously set with wget_tcp_set_family().
319  */
wget_tcp_get_family(wget_tcp * tcp)320 int wget_tcp_get_family(wget_tcp *tcp)
321 {
322 	return family_to_value((tcp ? tcp : &global_tcp)->family);
323 }
324 
325 /**
326  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
327  * \return The local port.
328  *
329  * Get the port number the TCP connection \p tcp is bound to on the local machine.
330  */
wget_tcp_get_local_port(wget_tcp * tcp)331 int wget_tcp_get_local_port(wget_tcp *tcp)
332 {
333 	if (unlikely(!tcp))
334 		return 0;
335 
336 	struct sockaddr_storage addr_store;
337 	struct sockaddr *addr = (struct sockaddr *)&addr_store;
338 	socklen_t addr_len = sizeof(addr_store);
339 
340 	/* Get automatically retrieved port number */
341 	if (getsockname(tcp->sockfd, addr, &addr_len) == 0) {
342 		char s_port[NI_MAXSERV];
343 
344 		if (getnameinfo(addr, addr_len, NULL, 0, s_port, sizeof(s_port), NI_NUMERICSERV) == 0)
345 			return atoi(s_port);
346 	}
347 
348 	return 0;
349 }
350 
351 /**
352  * \param[in] tcp A TCP connection.
353  * \param[in] timeout The timeout value.
354  *
355  * Set the timeout for the TCP connection.
356  *
357  * This is the maximum time to wait until the remote host accepts our connection.
358  *
359  * The following two values are special:
360  *
361  *  - `0`: No timeout, immediate.
362  *  - `-1`: Infinite timeout. Wait indefinitely.
363  */
wget_tcp_set_connect_timeout(wget_tcp * tcp,int timeout)364 void wget_tcp_set_connect_timeout(wget_tcp *tcp, int timeout)
365 {
366 	(tcp ? tcp : &global_tcp)->connect_timeout = timeout;
367 }
368 
369 /**
370  * \param[in] tcp A TCP connection.
371  * \param[in] timeout The timeout value.
372  *
373  * Set the timeout (in milliseconds) for wget_tcp_read(), wget_tcp_write() and wget_tcp_accept().
374  *
375  * The following two values are special:
376  *
377  *  - `0`: No timeout, immediate.
378  *  - `-1`: Infinite timeout. Wait indefinitely.
379  */
wget_tcp_set_timeout(wget_tcp * tcp,int timeout)380 void wget_tcp_set_timeout(wget_tcp *tcp, int timeout)
381 {
382 	(tcp ? tcp : &global_tcp)->timeout = timeout;
383 }
384 
385 /**
386  * \param[in] tcp A TCP connection.
387  * \return The timeout value that was set with wget_tcp_set_timeout().
388  *
389  * Get the timeout value that was set with wget_tcp_set_timeout().
390  */
wget_tcp_get_timeout(wget_tcp * tcp)391 int wget_tcp_get_timeout(wget_tcp *tcp)
392 {
393 	return (tcp ? tcp : &global_tcp)->timeout;
394 }
395 
396 /**
397  * \param[in] tcp A TCP connection. Might be NULL.
398  * \param[in] bind_address An IP address or host name.
399  *
400  * Set the IP address/hostname the socket \p tcp will bind to on the local machine
401  * when connecting to a remote host.
402  *
403  * The hostname can explicitly set the port after a colon (':').
404  *
405  * This is mainly relevant to wget_tcp_connect().
406  */
wget_tcp_set_bind_address(wget_tcp * tcp,const char * bind_address)407 void wget_tcp_set_bind_address(wget_tcp *tcp, const char *bind_address)
408 {
409 	if (!tcp)
410 		tcp = &global_tcp;
411 
412 	wget_dns_freeaddrinfo(tcp->dns, &tcp->bind_addrinfo);
413 
414 	if (bind_address) {
415 		const char *host, *s = bind_address;
416 
417 		if (*s == '[') {
418 			/* IPv6 address within brackets */
419 			char *p = strrchr(s, ']');
420 			if (p) {
421 				host = s + 1;
422 				s = p + 1;
423 			} else {
424 				/* Something is broken */
425 				host = s + 1;
426 				while (*s)
427 					s++;
428 			}
429 		} else {
430 			host = s;
431 			while (*s && *s != ':')
432 				s++;
433 		}
434 
435 		if (*s == ':') {
436 			char port[6];
437 
438 			wget_strscpy(port, s + 1, sizeof(port));
439 
440 			if (c_isdigit(*port))
441 				tcp->bind_addrinfo = wget_dns_resolve(tcp->dns, host, (uint16_t) atoi(port), tcp->family, tcp->preferred_family);
442 		} else {
443 			tcp->bind_addrinfo = wget_dns_resolve(tcp->dns, host, 0, tcp->family, tcp->preferred_family);
444 		}
445 	}
446 }
447 
448 /**
449  * \param[in] tcp A TCP connection. Might be NULL.
450  * \param[in] bind_interface A network interface name.
451  *
452  * Set the Network Interface the socket \p tcp will bind to on the local machine
453  * when connecting to a remote host.
454  *
455  * This is mainly relevant to wget_tcp_connect().
456  */
wget_tcp_set_bind_interface(wget_tcp * tcp,const char * bind_interface)457 void wget_tcp_set_bind_interface(wget_tcp *tcp, const char *bind_interface)
458 {
459 	if (!tcp)
460 		tcp = &global_tcp;
461 
462 	tcp->bind_interface = bind_interface;
463 }
464 
465 /**
466  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
467  * \param[in] ssl Flag to enable or disable SSL/TLS on the given connection.
468  *
469  * Enable or disable SSL/TLS.
470  *
471  * If \p tcp is NULL, TLS will be enabled globally. Otherwise, TLS will be enabled only for the provided connection.
472  */
wget_tcp_set_ssl(wget_tcp * tcp,bool ssl)473 void wget_tcp_set_ssl(wget_tcp *tcp, bool ssl)
474 {
475 	(tcp ? tcp : &global_tcp)->ssl = ssl;
476 }
477 
478 /**
479  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
480  * \return 1 if TLs is enabled, 0 otherwise.
481  *
482  * Tells whether TLS is enabled or not.
483  */
wget_tcp_get_ssl(wget_tcp * tcp)484 bool wget_tcp_get_ssl(wget_tcp *tcp)
485 {
486 	return (tcp ? tcp : &global_tcp)->ssl;
487 }
488 
489 /**
490  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
491  * \return IP address as string, NULL if not available.
492  *
493  * Returns the IP address of a `wget_tcp` instance.
494  */
wget_tcp_get_ip(wget_tcp * tcp)495 const char *wget_tcp_get_ip(wget_tcp *tcp)
496 {
497 	return tcp ? tcp->ip : NULL;
498 }
499 
500 /**
501  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
502  * \param[in] hostname A hostname. The value of the SNI field.
503  *
504  * Sets the TLS Server Name Indication (SNI). For more info see [RFC 6066, sect. 3](https://tools.ietf.org/html/rfc6066#section-3).
505  *
506  * SNI basically does at the TLS layer what the `Host:` header field does at the application (HTTP) layer.
507  * The server might use this information to locate an appropriate X.509 certificate from a pool of certificates, or to direct
508  * the request to a specific virtual host, for instance.
509  */
wget_tcp_set_ssl_hostname(wget_tcp * tcp,const char * hostname)510 void wget_tcp_set_ssl_hostname(wget_tcp *tcp, const char *hostname)
511 {
512 	if (!tcp)
513 		tcp = &global_tcp;
514 
515 	xfree(tcp->ssl_hostname);
516 	tcp->ssl_hostname = wget_strdup(hostname);
517 }
518 
519 /**
520  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
521  * \return A hostname. The value of the SNI field.
522  *
523  * Returns the value that was set to SNI with a previous call to wget_tcp_set_ssl_hostname().
524  */
wget_tcp_get_ssl_hostname(wget_tcp * tcp)525 const char *wget_tcp_get_ssl_hostname(wget_tcp *tcp)
526 {
527 	return (tcp ? tcp : &global_tcp)->ssl_hostname;
528 }
529 
530 /**
531  * \return A new `wget_tcp` structure, with pre-defined parameters.
532  *
533  * Create a new `wget_tcp` structure, that represents a TCP connection.
534  * It can be destroyed with wget_tcp_deinit().
535  *
536  * This function does not establish or modify a TCP connection in any way.
537  * That can be done with the other functions in this file, such as
538  * wget_tcp_connect() or wget_tcp_listen() and wget_tcp_accept().
539  */
wget_tcp_init(void)540 wget_tcp *wget_tcp_init(void)
541 {
542 	wget_tcp *tcp = wget_malloc(sizeof(wget_tcp));
543 
544 	if (tcp) {
545 		*tcp = global_tcp;
546 		tcp->ssl_hostname = wget_strdup(global_tcp.ssl_hostname);
547 	}
548 
549 	return tcp;
550 }
551 
552 /**
553  * \param[in] _tcp A **pointer** to a `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init(). Might be NULL.
554  *
555  * Release a TCP connection (created with wget_tcp_init()).
556  *
557  * The `wget_tcp` structure will be freed and \p _tcp will be set to NULL.
558  *
559  * If \p _tcp is NULL, the SNI field will be cleared.
560  *
561  * Does not free the internal DNS cache, so that other connections can re-use it.
562  * Call wget_dns_cache_free() if you want to free it.
563  */
wget_tcp_deinit(wget_tcp ** _tcp)564 void wget_tcp_deinit(wget_tcp **_tcp)
565 {
566 	wget_tcp *tcp;
567 
568 	if (!_tcp) {
569 		xfree(global_tcp.ssl_hostname);
570 		return;
571 	}
572 
573 	if ((tcp = *_tcp)) {
574 		wget_tcp_close(tcp);
575 
576 		wget_dns_freeaddrinfo(tcp->dns, &tcp->bind_addrinfo);
577 
578 		xfree(tcp->ssl_hostname);
579 		xfree(tcp->ip);
580 		xfree(tcp);
581 
582 		*_tcp = NULL;
583 	}
584 }
585 
_set_async(int fd)586 static void _set_async(int fd)
587 {
588 #if ((defined _WIN32 || defined __WIN32__) && !defined __CYGWIN__)
589 	unsigned long blocking = 0;
590 
591 	if (ioctl(fd, FIONBIO, &blocking))
592 		error_printf_exit(_("Failed to set socket to non-blocking\n"));
593 #else
594 	int flags;
595 
596 	if ((flags = fcntl(fd, F_GETFL)) < 0)
597 		error_printf_exit(_("Failed to get socket flags\n"));
598 
599 	if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
600 		error_printf_exit(_("Failed to set socket to non-blocking\n"));
601 #endif
602 }
603 
set_socket_options(const wget_tcp * tcp,int fd)604 static void set_socket_options(const wget_tcp *tcp, int fd)
605 {
606 	int on = 1;
607 
608 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)) == -1)
609 		error_printf(_("Failed to set socket option REUSEADDR\n"));
610 
611 	on = 1;
612 	if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on)) == -1)
613 		error_printf(_("Failed to set socket option NODELAY\n"));
614 
615 #ifdef SO_BINDTODEVICE
616 	if (tcp->bind_interface) {
617 		if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, tcp->bind_interface, (socklen_t)strlen(tcp->bind_interface)) == -1)
618 			error_printf(_("Failed to set socket option BINDTODEVICE\n"));
619 	}
620 #else
621 	// Let's exit here instead of using a wrong interface (privacy concerns)
622 	if (tcp->bind_interface)
623 		error_printf_exit(_("Unsupported socket option BINDTODEVICE\n"));
624 #endif
625 
626 #ifdef TCP_FASTOPEN_LINUX_411
627 	on = 1;
628 	if (setsockopt(fd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT, (void *)&on, sizeof(on)) == -1)
629 		debug_printf("Failed to set socket option TCP_FASTOPEN_CONNECT\n");
630 #endif
631 }
632 
633 /**
634  * Test whether the given connection (\p tcp) is ready to read or write.
635  *
636  * The parameter \p flags can have one or both (with bitwise OR) of the following values:
637  *
638  *  - `WGET_IO_READABLE`: Is data available for reading?
639  *  - `WGET_IO_WRITABLE`: Can we write immediately (without having to wait until the TCP buffer frees)?
640  */
wget_tcp_ready_2_transfer(wget_tcp * tcp,int flags)641 int wget_tcp_ready_2_transfer(wget_tcp *tcp, int flags)
642 {
643 	if (likely(tcp))
644 		return wget_ready_2_transfer(tcp->sockfd, tcp->timeout, flags);
645 	else
646 		return -1;
647 }
648 
649 /**
650  * \param[in] tcp A `wget_tcp` structure representing a TCP connection, returned by wget_tcp_init().
651  * \param[in] host Hostname or IP address to connect to.
652  * \param[in] port port number
653  * \return WGET_E_SUCCESS (0) on success, or a negative integer on error (some of WGET_E_XXX defined in `<wget.h>`).
654  *
655  * Open a TCP connection with a remote host.
656  *
657  * This function will use TLS if it has been enabled for this `wget_tcp`. You can enable it
658  * with wget_tcp_set_ssl(). Additionally, you can also use wget_tcp_set_ssl_hostname() to set the
659  * Server Name Indication (SNI).
660  *
661  * You can set which IP address and port on the local machine will the socket be bound to
662  * with wget_tcp_set_bind_address(). Otherwise the socket will bind to any address and port
663  * chosen by the operating system.
664  *
665  * You can also set which Network Interface on the local machine will the socket be bound to
666  * with wget_tcp_bind_interface().
667  *
668  * This function will try to use TCP Fast Open if enabled and available. If TCP Fast Open fails,
669  * it will fall back to the normal TCP handshake, without raising an error. You can enable TCP Fast Open
670  * with wget_tcp_set_tcp_fastopen().
671  *
672  * If the connection fails, `WGET_E_CONNECT` is returned.
673  */
wget_tcp_connect(wget_tcp * tcp,const char * host,uint16_t port)674 int wget_tcp_connect(wget_tcp *tcp, const char *host, uint16_t port)
675 {
676 	struct addrinfo *ai;
677 	int rc, ret = WGET_E_UNKNOWN;
678 	char adr[NI_MAXHOST], s_port[NI_MAXSERV];
679 	int debug = wget_logger_is_active(wget_get_logger(WGET_LOGGER_DEBUG));
680 
681 	if (unlikely(!tcp))
682 		return WGET_E_INVALID;
683 
684 	wget_dns_freeaddrinfo(tcp->dns, &tcp->addrinfo);
685 
686 	tcp->addrinfo = wget_dns_resolve(tcp->dns, host, port, tcp->family, tcp->preferred_family);
687 
688 	for (ai = tcp->addrinfo; ai; ai = ai->ai_next) {
689 		if (debug) {
690 			rc = getnameinfo(ai->ai_addr, ai->ai_addrlen,
691 					adr, sizeof(adr),
692 					s_port, sizeof(s_port),
693 					NI_NUMERICHOST | NI_NUMERICSERV);
694 			if (rc == 0)
695 				debug_printf("trying %s:%s...\n", adr, s_port);
696 			else
697 				debug_printf("trying ???:%s (%s)...\n", s_port, gai_strerror(rc));
698 		}
699 
700 		int sockfd;
701 		if ((sockfd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) != -1) {
702 			_set_async(sockfd);
703 			set_socket_options(tcp, sockfd);
704 
705 			if (tcp->bind_addrinfo) {
706 				if (debug) {
707 					rc = getnameinfo(tcp->bind_addrinfo->ai_addr,
708 							tcp->bind_addrinfo->ai_addrlen,
709 							adr, sizeof(adr),
710 							s_port, sizeof(s_port),
711 							NI_NUMERICHOST | NI_NUMERICSERV);
712 					if (rc == 0)
713 						debug_printf("binding to %s:%s...\n", adr, s_port);
714 					else
715 						debug_printf("binding to ???:%s (%s)...\n", s_port, gai_strerror(rc));
716 				}
717 
718 				if (bind(sockfd, tcp->bind_addrinfo->ai_addr, tcp->bind_addrinfo->ai_addrlen) != 0) {
719 					error_printf(_("Failed to bind (%d)\n"), errno);
720 					close(sockfd);
721 
722 					return WGET_E_UNKNOWN;
723 				}
724 			}
725 
726 			/* Enable TCP Fast Open, if required by the user and available */
727 #ifdef TCP_FASTOPEN_OSX
728 			if (tcp->tcp_fastopen) {
729 				sa_endpoints_t endpoints = { .sae_dstaddr = ai->ai_addr, .sae_dstaddrlen = ai->ai_addrlen };
730 				rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY, CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT, NULL, 0, NULL, NULL);
731 				tcp->first_send = 0;
732 #elif defined TCP_FASTOPEN_LINUX
733 			if (tcp->tcp_fastopen) {
734 				errno = 0;
735 				tcp->connect_addrinfo = ai;
736 				rc = 0;
737 				tcp->first_send = 1;
738 #elif defined TCP_FASTOPEN_LINUX_411
739 			if (tcp->tcp_fastopen) {
740 				tcp->connect_addrinfo = ai;
741 				rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
742 				tcp->first_send = 0;
743 #else
744 			if (0) {
745 #endif
746 			} else {
747 				rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
748 				tcp->first_send = 0;
749 			}
750 
751 			if (rc < 0
752 				&& errno != EAGAIN
753 				&& errno != EINPROGRESS
754 			) {
755 				error_printf(_("Failed to connect (%d)\n"), errno);
756 				ret = WGET_E_CONNECT;
757 				close(sockfd);
758 			} else {
759 				tcp->sockfd = sockfd;
760 				if (tcp->ssl) {
761 					if ((ret = wget_ssl_open(tcp))) {
762 						if (ret == WGET_E_CERTIFICATE) {
763 							wget_tcp_close(tcp);
764 							break; /* stop here - the server cert couldn't be validated */
765 						}
766 
767 						/* do not free tcp->addrinfo when calling wget_tcp_close() */
768 						struct addrinfo *ai_tmp = tcp->addrinfo;
769 
770 						tcp->addrinfo = NULL;
771 						wget_tcp_close(tcp);
772 						tcp->addrinfo = ai_tmp;
773 
774 						continue;
775 					}
776 				}
777 
778 				if (getnameinfo(ai->ai_addr, ai->ai_addrlen, adr, sizeof(adr), s_port, sizeof(s_port), NI_NUMERICHOST | NI_NUMERICSERV) == 0)
779 					tcp->ip = wget_strdup(adr);
780 				else
781 					tcp->ip = NULL;
782 
783 				return WGET_E_SUCCESS;
784 			}
785 		} else
786 			error_printf(_("Failed to create socket (%d)\n"), errno);
787 	}
788 
789 	return ret;
790 }
791 
792 /**
793  * \param[in] tcp An active connection.
794  * \return WGET_E_SUCCESS (0) on success, or a negative integer on error (one of WGET_E_XXX, defined in `<wget.h>`).
795  * Start TLS for this connection.
796  *
797  * This will typically be called by wget_tcp_accept().
798  *
799  * If the socket is listening (e.g. wget_tcp_listen(), wget_tcp_accept()), it will expect the client to perform a TLS handshake,
800  * and fail if it doesn't.
801  *
802  * If this is a client connection (e.g. wget_tcp_connect()), it will try perform a TLS handshake with the server.
803  */
804 int wget_tcp_tls_start(wget_tcp *tcp)
805 {
806 	return wget_ssl_open(tcp);
807 }
808 
809 /**
810  * \param[in] tcp An active connection.
811  *
812  * Stops TLS, but does not close the connection. Data will be transmitted in the clear from now on.
813  */
814 void wget_tcp_tls_stop(wget_tcp *tcp)
815 {
816 	if (tcp)
817 		wget_ssl_close(&tcp->ssl_session);
818 }
819 
820 /**
821  * \param[in] tcp An active TCP connection.
822  * \param[in] buf Destination buffer, at least \p count bytes long.
823  * \param[in] count Length of the buffer \p buf.
824  * \return Number of bytes read
825  *
826  * Read \p count bytes of data from the TCP connection represented by \p tcp
827  * and store them in the buffer \p buf.
828  *
829  * This function knows whether the provided connection is over TLS or not
830  * and it will do the right thing.
831  *
832  * The `tcp->timeout` parameter is taken into account by this function as well.
833  * It specifies how long should this function wait until there's data available
834  * to read (in milliseconds). The default timeout is -1, which means to wait indefinitely.
835  *
836  * The following two values are special:
837  *
838  *  - `0`: No timeout, immediate.
839  *  - `-1`: Infinite timeout. Wait indefinitely until a new connection comes.
840  *
841  * You can set the timeout with wget_tcp_set_timeout().
842  *
843  * In particular, the returned value will be zero if no data was available for reading
844  * before the timeout elapsed.
845  */
846 ssize_t wget_tcp_read(wget_tcp *tcp, char *buf, size_t count)
847 {
848 	ssize_t rc;
849 
850 	if (unlikely(!tcp || !buf))
851 		return 0;
852 
853 	if (tcp->ssl_session) {
854 		rc = wget_ssl_read_timeout(tcp->ssl_session, buf, count, tcp->timeout);
855 	} else {
856 		if (tcp->timeout) {
857 			if ((rc = wget_ready_2_read(tcp->sockfd, tcp->timeout)) <= 0)
858 				return rc;
859 		}
860 
861 		rc = recvfrom(tcp->sockfd, buf, count, 0, NULL, NULL);
862 	}
863 
864 	if (rc < 0)
865 		error_printf(_("Failed to read %zu bytes (%d)\n"), count, errno);
866 
867 	return rc;
868 }
869 
870 /**
871  * \param[in] tcp An active TCP connection.
872  * \param[in] buf A buffer, at least \p count bytes long.
873  * \param[in] count Number of bytes from \p buf to send through \p tcp.
874  * \return The number of bytes written, or -1 on error.
875  *
876  * Write \p count bytes of data from the buffer \p buf to the TCP connection
877  * represented by \p tcp.
878  *
879  * This function knows whether the provided connection is over TLS or not
880  * and it will do the right thing.
881  *
882  * TCP Fast Open will be used if it's available and enabled. You can enable TCP Fast Open
883  * with wget_tcp_set_tcp_fastopen().
884  *
885  * This function honors the `timeout` parameter. If the write operation fails because the socket buffer is full,
886  * then it will wait at most that amount of milliseconds. If after the timeout the socket is still unavailable
887  * for writing, this function returns zero.
888  *
889  * The following two values are special:
890  *
891  *  - `0`: No timeout. The socket must be available immediately.
892  *  - `-1`: Infinite timeout. Wait indefinitely until the socket becomes available.
893  *
894  * You can set the timeout with wget_tcp_set_timeout().
895  */
896 ssize_t wget_tcp_write(wget_tcp *tcp, const char *buf, size_t count)
897 {
898 	ssize_t nwritten = 0;
899 
900 	if (unlikely(!tcp || !buf))
901 		return -1;
902 
903 	if (tcp->ssl_session)
904 		return wget_ssl_write_timeout(tcp->ssl_session, buf, count, tcp->timeout);
905 
906 	while (count) {
907 		ssize_t n;
908 
909 #ifdef TCP_FASTOPEN_LINUX
910 		if (tcp->tcp_fastopen && tcp->first_send) {
911 			n = sendto(tcp->sockfd, buf, count, MSG_FASTOPEN,
912 				tcp->connect_addrinfo->ai_addr, tcp->connect_addrinfo->ai_addrlen);
913 			tcp->first_send = 0;
914 
915 			if (n < 0 && errno == EOPNOTSUPP) {
916 				/* fallback from fastopen, e.g. when fastopen is disabled in system */
917 				tcp->tcp_fastopen = 0;
918 
919 				int rc = connect(tcp->sockfd, tcp->connect_addrinfo->ai_addr, tcp->connect_addrinfo->ai_addrlen);
920 				if (rc < 0
921 					&& errno != EAGAIN
922 					&& errno != ENOTCONN
923 					&& errno != EINPROGRESS)
924 				{
925 					error_printf(_("Failed to connect (%d)\n"), errno);
926 					return -1;
927 				}
928 				errno = EAGAIN;
929 			}
930 		} else
931 #endif
932 			n = send(tcp->sockfd, buf, count, 0);
933 
934 		if (n >= 0) {
935 			nwritten += n;
936 
937 			if ((size_t)n >= count)
938 				return nwritten;
939 
940 			count -= n;
941 			buf += n;
942 		} else {
943 			if (errno != EAGAIN
944 				&& errno != ENOTCONN
945 				&& errno != EINPROGRESS)
946 			{
947 				error_printf(_("Failed to write %zu bytes (%d)\n"), count, errno);
948 				return -1;
949 			}
950 
951 			if (tcp->timeout) {
952 				int rc = wget_ready_2_write(tcp->sockfd, tcp->timeout);
953 				if (rc <= 0)
954 					return rc;
955 			}
956 		}
957 	}
958 
959 	return 0;
960 }
961 
962 /**
963  * \param[in] tcp An active TCP connection.
964  * \param[in] fmt Format string (like in `printf(3)`).
965  * \param[in] args `va_args` argument list (like in `vprintf(3)`)
966  *
967  * Write data in vprintf-style format, to the connection \p tcp.
968  *
969  * It uses wget_tcp_write().
970  */
971 ssize_t wget_tcp_vprintf(wget_tcp *tcp, const char *fmt, va_list args)
972 {
973 	char sbuf[4096];
974 	wget_buffer buf;
975 	ssize_t len2;
976 
977 	wget_buffer_init(&buf, sbuf, sizeof(sbuf));
978 	wget_buffer_vprintf(&buf, fmt, args);
979 
980 	len2 = wget_tcp_write(tcp, buf.data, buf.length);
981 
982 	wget_buffer_deinit(&buf);
983 
984 	if (len2 > 0)
985 		debug_write(buf.data, len2);
986 
987 	if (len2 > 0 && (ssize_t) buf.length != len2)
988 		error_printf(_("%s: internal error: length mismatch %zu != %zd\n"), __func__, buf.length, len2);
989 
990 	return len2;
991 }
992 
993 /**
994  * \param[in] tcp An active TCP connection.
995  * \param[in] fmt Format string (like in `printf(3)`).
996  *
997  * Write data in printf-style format, to the connection \p tcp.
998  *
999  * It uses wget_tcp_vprintf(), which in turn uses wget_tcp_write().
1000  */
1001 ssize_t wget_tcp_printf(wget_tcp *tcp, const char *fmt, ...)
1002 {
1003 	va_list args;
1004 
1005 	va_start(args, fmt);
1006 	ssize_t len = wget_tcp_vprintf(tcp, fmt, args);
1007 	va_end(args);
1008 
1009 	return len;
1010 }
1011 
1012 /**
1013  * \param[in] tcp An active TCP connection
1014  *
1015  * Close a TCP connection.
1016  */
1017 void wget_tcp_close(wget_tcp *tcp)
1018 {
1019 	if (likely(tcp)) {
1020 		wget_tcp_tls_stop(tcp);
1021 		if (tcp->sockfd != -1) {
1022 			close(tcp->sockfd);
1023 			tcp->sockfd = -1;
1024 		}
1025 		wget_dns_freeaddrinfo(tcp->dns, &tcp->addrinfo);
1026 	}
1027 }
1028 /** @} */
1029