9bcf525ebb39f8b010d6491e0eb2b6a940be65c3
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / connect.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
22
23 #include "curl_setup.h"
24
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
27 #endif
28 #ifdef HAVE_SYS_UN_H
29 #include <sys/un.h> /* for sockaddr_un */
30 #endif
31 #ifdef HAVE_LINUX_TCP_H
32 #include <linux/tcp.h>
33 #elif defined(HAVE_NETINET_TCP_H)
34 #include <netinet/tcp.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #ifdef HAVE_FCNTL_H
43 #include <fcntl.h>
44 #endif
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
47 #endif
48
49 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
50 #include <sys/filio.h>
51 #endif
52 #ifdef NETWARE
53 #undef in_addr_t
54 #define in_addr_t unsigned long
55 #endif
56 #ifdef __VMS
57 #include <in.h>
58 #include <inet.h>
59 #endif
60
61 #include "urldata.h"
62 #include "sendf.h"
63 #include "if2ip.h"
64 #include "strerror.h"
65 #include "connect.h"
66 #include "select.h"
67 #include "url.h" /* for Curl_safefree() */
68 #include "multiif.h"
69 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
70 #include "inet_ntop.h"
71 #include "inet_pton.h"
72 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
73 #include "progress.h"
74 #include "warnless.h"
75 #include "conncache.h"
76 #include "multihandle.h"
77 #include "share.h"
78 #include "version_win32.h"
79 #include "quic.h"
80 #include "socks.h"
81
82 /* The last 3 #include files should be in this order */
83 #include "curl_printf.h"
84 #include "curl_memory.h"
85 #include "memdebug.h"
86
87 static bool verifyconnect(curl_socket_t sockfd, int *error);
88
89 #if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
90 /* DragonFlyBSD and Windows use millisecond units */
91 #define KEEPALIVE_FACTOR(x) (x *= 1000)
92 #else
93 #define KEEPALIVE_FACTOR(x)
94 #endif
95
96 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
97 #define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
98
99 struct tcp_keepalive {
100   u_long onoff;
101   u_long keepalivetime;
102   u_long keepaliveinterval;
103 };
104 #endif
105
106 static void
107 tcpkeepalive(struct Curl_easy *data,
108              curl_socket_t sockfd)
109 {
110   int optval = data->set.tcp_keepalive?1:0;
111
112   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
113   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
114         (void *)&optval, sizeof(optval)) < 0) {
115     infof(data, "Failed to set SO_KEEPALIVE on fd %d", sockfd);
116   }
117   else {
118 #if defined(SIO_KEEPALIVE_VALS)
119     struct tcp_keepalive vals;
120     DWORD dummy;
121     vals.onoff = 1;
122     optval = curlx_sltosi(data->set.tcp_keepidle);
123     KEEPALIVE_FACTOR(optval);
124     vals.keepalivetime = optval;
125     optval = curlx_sltosi(data->set.tcp_keepintvl);
126     KEEPALIVE_FACTOR(optval);
127     vals.keepaliveinterval = optval;
128     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
129                 NULL, 0, &dummy, NULL, NULL) != 0) {
130       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d",
131             (int)sockfd, WSAGetLastError());
132     }
133 #else
134 #ifdef TCP_KEEPIDLE
135     optval = curlx_sltosi(data->set.tcp_keepidle);
136     KEEPALIVE_FACTOR(optval);
137     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
138           (void *)&optval, sizeof(optval)) < 0) {
139       infof(data, "Failed to set TCP_KEEPIDLE on fd %d", sockfd);
140     }
141 #elif defined(TCP_KEEPALIVE)
142     /* Mac OS X style */
143     optval = curlx_sltosi(data->set.tcp_keepidle);
144     KEEPALIVE_FACTOR(optval);
145     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
146       (void *)&optval, sizeof(optval)) < 0) {
147       infof(data, "Failed to set TCP_KEEPALIVE on fd %d", sockfd);
148     }
149 #endif
150 #ifdef TCP_KEEPINTVL
151     optval = curlx_sltosi(data->set.tcp_keepintvl);
152     KEEPALIVE_FACTOR(optval);
153     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
154           (void *)&optval, sizeof(optval)) < 0) {
155       infof(data, "Failed to set TCP_KEEPINTVL on fd %d", sockfd);
156     }
157 #endif
158 #endif
159   }
160 }
161
162 static CURLcode
163 singleipconnect(struct Curl_easy *data,
164                 struct connectdata *conn,
165                 const struct Curl_addrinfo *ai, /* start connecting to this */
166                 int tempindex);          /* 0 or 1 among the temp ones */
167
168 /*
169  * Curl_timeleft() returns the amount of milliseconds left allowed for the
170  * transfer/connection. If the value is 0, there's no timeout (ie there's
171  * infinite time left). If the value is negative, the timeout time has already
172  * elapsed.
173  *
174  * If 'nowp' is non-NULL, it points to the current time.
175  * 'duringconnect' is FALSE if not during a connect, as then of course the
176  * connect timeout is not taken into account!
177  *
178  * @unittest: 1303
179  */
180
181 #define TIMEOUT_CONNECT 1
182 #define TIMEOUT_MAXTIME 2
183
184 timediff_t Curl_timeleft(struct Curl_easy *data,
185                          struct curltime *nowp,
186                          bool duringconnect)
187 {
188   unsigned int timeout_set = 0;
189   timediff_t connect_timeout_ms = 0;
190   timediff_t maxtime_timeout_ms = 0;
191   timediff_t timeout_ms = 0;
192   struct curltime now;
193
194   /* The duration of a connect and the total transfer are calculated from two
195      different time-stamps. It can end up with the total timeout being reached
196      before the connect timeout expires and we must acknowledge whichever
197      timeout that is reached first. The total timeout is set per entire
198      operation, while the connect timeout is set per connect. */
199
200   if(data->set.timeout > 0) {
201     timeout_set = TIMEOUT_MAXTIME;
202     maxtime_timeout_ms = data->set.timeout;
203   }
204   if(duringconnect) {
205     timeout_set |= TIMEOUT_CONNECT;
206     connect_timeout_ms = (data->set.connecttimeout > 0) ?
207       data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
208   }
209   if(!timeout_set)
210     /* no timeout  */
211     return 0;
212
213   if(!nowp) {
214     now = Curl_now();
215     nowp = &now;
216   }
217
218   if(timeout_set & TIMEOUT_MAXTIME) {
219     maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
220     timeout_ms = maxtime_timeout_ms;
221   }
222
223   if(timeout_set & TIMEOUT_CONNECT) {
224     connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
225
226     if(!(timeout_set & TIMEOUT_MAXTIME) ||
227        (connect_timeout_ms < maxtime_timeout_ms))
228       timeout_ms = connect_timeout_ms;
229   }
230
231   if(!timeout_ms)
232     /* avoid returning 0 as that means no timeout! */
233     return -1;
234
235   return timeout_ms;
236 }
237
238 static CURLcode bindlocal(struct Curl_easy *data,
239                           curl_socket_t sockfd, int af, unsigned int scope)
240 {
241   struct connectdata *conn = data->conn;
242   struct Curl_sockaddr_storage sa;
243   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
244   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
245   struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
246 #ifdef ENABLE_IPV6
247   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
248 #endif
249
250   struct Curl_dns_entry *h = NULL;
251   unsigned short port = data->set.localport; /* use this port number, 0 for
252                                                 "random" */
253   /* how many port numbers to try to bind to, increasing one at a time */
254   int portnum = data->set.localportrange;
255   const char *dev = data->set.str[STRING_DEVICE];
256   int error;
257 #ifdef IP_BIND_ADDRESS_NO_PORT
258   int on = 1;
259 #endif
260 #ifndef ENABLE_IPV6
261   (void)scope;
262 #endif
263
264   /*************************************************************
265    * Select device to bind socket to
266    *************************************************************/
267   if(!dev && !port)
268     /* no local kind of binding was requested */
269     return CURLE_OK;
270
271   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
272
273   if(dev && (strlen(dev)<255) ) {
274     char myhost[256] = "";
275     int done = 0; /* -1 for error, 1 for address found */
276     bool is_interface = FALSE;
277     bool is_host = FALSE;
278     static const char *if_prefix = "if!";
279     static const char *host_prefix = "host!";
280
281     if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
282       dev += strlen(if_prefix);
283       is_interface = TRUE;
284     }
285     else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
286       dev += strlen(host_prefix);
287       is_host = TRUE;
288     }
289
290     /* interface */
291     if(!is_host) {
292 #ifdef SO_BINDTODEVICE
293       /* I am not sure any other OSs than Linux that provide this feature,
294        * and at the least I cannot test. --Ben
295        *
296        * This feature allows one to tightly bind the local socket to a
297        * particular interface.  This will force even requests to other
298        * local interfaces to go out the external interface.
299        *
300        *
301        * Only bind to the interface when specified as interface, not just
302        * as a hostname or ip address.
303        *
304        * interface might be a VRF, eg: vrf-blue, which means it cannot be
305        * converted to an IP address and would fail Curl_if2ip. Simply try
306        * to use it straight away.
307        */
308       if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
309                     dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
310         /* This is typically "errno 1, error: Operation not permitted" if
311          * you're not running as root or another suitable privileged
312          * user.
313          * If it succeeds it means the parameter was a valid interface and
314          * not an IP address. Return immediately.
315          */
316         return CURLE_OK;
317       }
318 #endif
319
320       switch(Curl_if2ip(af,
321 #ifdef ENABLE_IPV6
322                         scope, conn->scope_id,
323 #endif
324                         dev, myhost, sizeof(myhost))) {
325         case IF2IP_NOT_FOUND:
326           if(is_interface) {
327             /* Do not fall back to treating it as a host name */
328             failf(data, "Couldn't bind to interface '%s'", dev);
329             return CURLE_INTERFACE_FAILED;
330           }
331           break;
332         case IF2IP_AF_NOT_SUPPORTED:
333           /* Signal the caller to try another address family if available */
334           return CURLE_UNSUPPORTED_PROTOCOL;
335         case IF2IP_FOUND:
336           is_interface = TRUE;
337           /*
338            * We now have the numerical IP address in the 'myhost' buffer
339            */
340           infof(data, "Local Interface %s is ip %s using address family %i",
341                 dev, myhost, af);
342           done = 1;
343           break;
344       }
345     }
346     if(!is_interface) {
347       /*
348        * This was not an interface, resolve the name as a host name
349        * or IP number
350        *
351        * Temporarily force name resolution to use only the address type
352        * of the connection. The resolve functions should really be changed
353        * to take a type parameter instead.
354        */
355       unsigned char ipver = conn->ip_version;
356       int rc;
357
358       if(af == AF_INET)
359         conn->ip_version = CURL_IPRESOLVE_V4;
360 #ifdef ENABLE_IPV6
361       else if(af == AF_INET6)
362         conn->ip_version = CURL_IPRESOLVE_V6;
363 #endif
364
365       rc = Curl_resolv(data, dev, 0, FALSE, &h);
366       if(rc == CURLRESOLV_PENDING)
367         (void)Curl_resolver_wait_resolv(data, &h);
368       conn->ip_version = ipver;
369
370       if(h) {
371         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
372         Curl_printable_address(h->addr, myhost, sizeof(myhost));
373         infof(data, "Name '%s' family %i resolved to '%s' family %i",
374               dev, af, myhost, h->addr->ai_family);
375         Curl_resolv_unlock(data, h);
376         if(af != h->addr->ai_family) {
377           /* bad IP version combo, signal the caller to try another address
378              family if available */
379           return CURLE_UNSUPPORTED_PROTOCOL;
380         }
381         done = 1;
382       }
383       else {
384         /*
385          * provided dev was no interface (or interfaces are not supported
386          * e.g. solaris) no ip address and no domain we fail here
387          */
388         done = -1;
389       }
390     }
391
392     if(done > 0) {
393 #ifdef ENABLE_IPV6
394       /* IPv6 address */
395       if(af == AF_INET6) {
396 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
397         char *scope_ptr = strchr(myhost, '%');
398         if(scope_ptr)
399           *(scope_ptr++) = 0;
400 #endif
401         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
402           si6->sin6_family = AF_INET6;
403           si6->sin6_port = htons(port);
404 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
405           if(scope_ptr)
406             /* The "myhost" string either comes from Curl_if2ip or from
407                Curl_printable_address. The latter returns only numeric scope
408                IDs and the former returns none at all.  So the scope ID, if
409                present, is known to be numeric */
410             si6->sin6_scope_id = atoi(scope_ptr);
411 #endif
412         }
413         sizeof_sa = sizeof(struct sockaddr_in6);
414       }
415       else
416 #endif
417       /* IPv4 address */
418       if((af == AF_INET) &&
419          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
420         si4->sin_family = AF_INET;
421         si4->sin_port = htons(port);
422         sizeof_sa = sizeof(struct sockaddr_in);
423       }
424     }
425
426     if(done < 1) {
427       /* errorbuf is set false so failf will overwrite any message already in
428          the error buffer, so the user receives this error message instead of a
429          generic resolve error. */
430       data->state.errorbuf = FALSE;
431       failf(data, "Couldn't bind to '%s'", dev);
432       return CURLE_INTERFACE_FAILED;
433     }
434   }
435   else {
436     /* no device was given, prepare sa to match af's needs */
437 #ifdef ENABLE_IPV6
438     if(af == AF_INET6) {
439       si6->sin6_family = AF_INET6;
440       si6->sin6_port = htons(port);
441       sizeof_sa = sizeof(struct sockaddr_in6);
442     }
443     else
444 #endif
445     if(af == AF_INET) {
446       si4->sin_family = AF_INET;
447       si4->sin_port = htons(port);
448       sizeof_sa = sizeof(struct sockaddr_in);
449     }
450   }
451 #ifdef IP_BIND_ADDRESS_NO_PORT
452   (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
453 #endif
454   for(;;) {
455     if(bind(sockfd, sock, sizeof_sa) >= 0) {
456       /* we succeeded to bind */
457       struct Curl_sockaddr_storage add;
458       curl_socklen_t size = sizeof(add);
459       memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
460       if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
461         char buffer[STRERROR_LEN];
462         data->state.os_errno = error = SOCKERRNO;
463         failf(data, "getsockname() failed with errno %d: %s",
464               error, Curl_strerror(error, buffer, sizeof(buffer)));
465         return CURLE_INTERFACE_FAILED;
466       }
467       infof(data, "Local port: %hu", port);
468       conn->bits.bound = TRUE;
469       return CURLE_OK;
470     }
471
472     if(--portnum > 0) {
473       infof(data, "Bind to local port %hu failed, trying next", port);
474       port++; /* try next port */
475       /* We re-use/clobber the port variable here below */
476       if(sock->sa_family == AF_INET)
477         si4->sin_port = ntohs(port);
478 #ifdef ENABLE_IPV6
479       else
480         si6->sin6_port = ntohs(port);
481 #endif
482     }
483     else
484       break;
485   }
486   {
487     char buffer[STRERROR_LEN];
488     data->state.os_errno = error = SOCKERRNO;
489     failf(data, "bind failed with errno %d: %s",
490           error, Curl_strerror(error, buffer, sizeof(buffer)));
491   }
492
493   return CURLE_INTERFACE_FAILED;
494 }
495
496 /*
497  * verifyconnect() returns TRUE if the connect really has happened.
498  */
499 static bool verifyconnect(curl_socket_t sockfd, int *error)
500 {
501   bool rc = TRUE;
502 #ifdef SO_ERROR
503   int err = 0;
504   curl_socklen_t errSize = sizeof(err);
505
506 #ifdef WIN32
507   /*
508    * In October 2003 we effectively nullified this function on Windows due to
509    * problems with it using all CPU in multi-threaded cases.
510    *
511    * In May 2004, we bring it back to offer more info back on connect failures.
512    * Gisle Vanem could reproduce the former problems with this function, but
513    * could avoid them by adding this SleepEx() call below:
514    *
515    *    "I don't have Rational Quantify, but the hint from his post was
516    *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
517    *    just Sleep(0) would be enough?) would release whatever
518    *    mutex/critical-section the ntdll call is waiting on.
519    *
520    *    Someone got to verify this on Win-NT 4.0, 2000."
521    */
522
523 #ifdef _WIN32_WCE
524   Sleep(0);
525 #else
526   SleepEx(0, FALSE);
527 #endif
528
529 #endif
530
531   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
532     err = SOCKERRNO;
533 #ifdef _WIN32_WCE
534   /* Old WinCE versions don't support SO_ERROR */
535   if(WSAENOPROTOOPT == err) {
536     SET_SOCKERRNO(0);
537     err = 0;
538   }
539 #endif
540 #if defined(EBADIOCTL) && defined(__minix)
541   /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
542   if(EBADIOCTL == err) {
543     SET_SOCKERRNO(0);
544     err = 0;
545   }
546 #endif
547   if((0 == err) || (EISCONN == err))
548     /* we are connected, awesome! */
549     rc = TRUE;
550   else
551     /* This wasn't a successful connect */
552     rc = FALSE;
553   if(error)
554     *error = err;
555 #else
556   (void)sockfd;
557   if(error)
558     *error = SOCKERRNO;
559 #endif
560   return rc;
561 }
562
563 /* update tempaddr[tempindex] (to the next entry), makes sure to stick
564    to the correct family */
565 static struct Curl_addrinfo *ainext(struct connectdata *conn,
566                                     int tempindex,
567                                     bool next) /* use next entry? */
568 {
569   struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
570   if(ai && next)
571     ai = ai->ai_next;
572   while(ai && (ai->ai_family != conn->tempfamily[tempindex]))
573     ai = ai->ai_next;
574   conn->tempaddr[tempindex] = ai;
575   return ai;
576 }
577
578 /* Used within the multi interface. Try next IP address, returns error if no
579    more address exists or error */
580 static CURLcode trynextip(struct Curl_easy *data,
581                           struct connectdata *conn,
582                           int sockindex,
583                           int tempindex)
584 {
585   CURLcode result = CURLE_COULDNT_CONNECT;
586
587   /* First clean up after the failed socket.
588      Don't close it yet to ensure that the next IP's socket gets a different
589      file descriptor, which can prevent bugs when the curl_multi_socket_action
590      interface is used with certain select() replacements such as kqueue. */
591   curl_socket_t fd_to_close = conn->tempsock[tempindex];
592   conn->tempsock[tempindex] = CURL_SOCKET_BAD;
593
594   if(sockindex == FIRSTSOCKET) {
595     struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
596
597     while(ai) {
598       result = singleipconnect(data, conn, ai, tempindex);
599       if(result == CURLE_COULDNT_CONNECT) {
600         ai = ainext(conn, tempindex, TRUE);
601         continue;
602       }
603       break;
604     }
605   }
606
607   if(fd_to_close != CURL_SOCKET_BAD)
608     Curl_closesocket(data, conn, fd_to_close);
609
610   return result;
611 }
612
613 /* Copies connection info into the transfer handle to make it available when
614    the transfer handle is no longer associated with the connection. */
615 void Curl_persistconninfo(struct Curl_easy *data, struct connectdata *conn,
616                           char *local_ip, int local_port)
617 {
618   memcpy(data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
619   if(local_ip && local_ip[0])
620     memcpy(data->info.conn_local_ip, local_ip, MAX_IPADR_LEN);
621   else
622     data->info.conn_local_ip[0] = 0;
623   data->info.conn_scheme = conn->handler->scheme;
624   data->info.conn_protocol = conn->handler->protocol;
625   data->info.conn_primary_port = conn->port;
626   data->info.conn_remote_port = conn->remote_port;
627   data->info.conn_local_port = local_port;
628 }
629
630 /* retrieves ip address and port from a sockaddr structure.
631    note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
632 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
633                       char *addr, int *port)
634 {
635   struct sockaddr_in *si = NULL;
636 #ifdef ENABLE_IPV6
637   struct sockaddr_in6 *si6 = NULL;
638 #endif
639 #if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
640   struct sockaddr_un *su = NULL;
641 #else
642   (void)salen;
643 #endif
644
645   switch(sa->sa_family) {
646     case AF_INET:
647       si = (struct sockaddr_in *)(void *) sa;
648       if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
649                         addr, MAX_IPADR_LEN)) {
650         unsigned short us_port = ntohs(si->sin_port);
651         *port = us_port;
652         return TRUE;
653       }
654       break;
655 #ifdef ENABLE_IPV6
656     case AF_INET6:
657       si6 = (struct sockaddr_in6 *)(void *) sa;
658       if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
659                         addr, MAX_IPADR_LEN)) {
660         unsigned short us_port = ntohs(si6->sin6_port);
661         *port = us_port;
662         return TRUE;
663       }
664       break;
665 #endif
666 #if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
667     case AF_UNIX:
668       if(salen > (curl_socklen_t)sizeof(CURL_SA_FAMILY_T)) {
669         su = (struct sockaddr_un*)sa;
670         msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
671       }
672       else
673         addr[0] = 0; /* socket with no name */
674       *port = 0;
675       return TRUE;
676 #endif
677     default:
678       break;
679   }
680
681   addr[0] = '\0';
682   *port = 0;
683   errno = EAFNOSUPPORT;
684   return FALSE;
685 }
686
687 /* retrieves the start/end point information of a socket of an established
688    connection */
689 void Curl_conninfo_remote(struct Curl_easy *data,
690                           struct connectdata *conn, curl_socket_t sockfd)
691 {
692 #ifdef HAVE_GETPEERNAME
693   char buffer[STRERROR_LEN];
694   struct Curl_sockaddr_storage ssrem;
695   curl_socklen_t plen;
696   int port;
697   plen = sizeof(struct Curl_sockaddr_storage);
698   memset(&ssrem, 0, sizeof(ssrem));
699   if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
700     int error = SOCKERRNO;
701     failf(data, "getpeername() failed with errno %d: %s",
702           error, Curl_strerror(error, buffer, sizeof(buffer)));
703     return;
704   }
705   if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
706                        conn->primary_ip, &port)) {
707     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
708           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
709     return;
710   }
711 #else
712   (void)data;
713   (void)conn;
714   (void)sockfd;
715 #endif
716 }
717
718 /* retrieves the start/end point information of a socket of an established
719    connection */
720 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
721                          char *local_ip, int *local_port)
722 {
723 #ifdef HAVE_GETSOCKNAME
724   char buffer[STRERROR_LEN];
725   struct Curl_sockaddr_storage ssloc;
726   curl_socklen_t slen;
727   slen = sizeof(struct Curl_sockaddr_storage);
728   memset(&ssloc, 0, sizeof(ssloc));
729   if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
730     int error = SOCKERRNO;
731     failf(data, "getsockname() failed with errno %d: %s",
732           error, Curl_strerror(error, buffer, sizeof(buffer)));
733     return;
734   }
735   if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
736                        local_ip, local_port)) {
737     failf(data, "ssloc inet_ntop() failed with errno %d: %s",
738           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
739     return;
740   }
741 #else
742   (void)data;
743   (void)sockfd;
744   (void)local_ip;
745   (void)local_port;
746 #endif
747 }
748
749 /* retrieves the start/end point information of a socket of an established
750    connection */
751 void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
752                          curl_socket_t sockfd)
753 {
754   /* 'local_ip' and 'local_port' get filled with local's numerical
755      ip address and port number whenever an outgoing connection is
756      **established** from the primary socket to a remote address. */
757   char local_ip[MAX_IPADR_LEN] = "";
758   int local_port = -1;
759
760   if(conn->transport == TRNSPRT_TCP) {
761     if(!conn->bits.reuse && !conn->bits.tcp_fastopen)
762       Curl_conninfo_remote(data, conn, sockfd);
763     Curl_conninfo_local(data, sockfd, local_ip, &local_port);
764   } /* end of TCP-only section */
765
766   /* persist connection info in session handle */
767   Curl_persistconninfo(data, conn, local_ip, local_port);
768 }
769
770 /* After a TCP connection to the proxy has been verified, this function does
771    the next magic steps. If 'done' isn't set TRUE, it is not done yet and
772    must be called again.
773
774    Note: this function's sub-functions call failf()
775
776 */
777 static CURLcode connect_SOCKS(struct Curl_easy *data, int sockindex,
778                               bool *done)
779 {
780   CURLcode result = CURLE_OK;
781 #ifndef CURL_DISABLE_PROXY
782   CURLproxycode pxresult = CURLPX_OK;
783   struct connectdata *conn = data->conn;
784   if(conn->bits.socksproxy) {
785     /* for the secondary socket (FTP), use the "connect to host"
786      * but ignore the "connect to port" (use the secondary port)
787      */
788     const char * const host =
789       conn->bits.httpproxy ?
790       conn->http_proxy.host.name :
791       conn->bits.conn_to_host ?
792       conn->conn_to_host.name :
793       sockindex == SECONDARYSOCKET ?
794       conn->secondaryhostname : conn->host.name;
795     const int port =
796       conn->bits.httpproxy ? (int)conn->http_proxy.port :
797       sockindex == SECONDARYSOCKET ? conn->secondary_port :
798       conn->bits.conn_to_port ? conn->conn_to_port :
799       conn->remote_port;
800     switch(conn->socks_proxy.proxytype) {
801     case CURLPROXY_SOCKS5:
802     case CURLPROXY_SOCKS5_HOSTNAME:
803       pxresult = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
804                              host, port, sockindex, data, done);
805       break;
806
807     case CURLPROXY_SOCKS4:
808     case CURLPROXY_SOCKS4A:
809       pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
810                              data, done);
811       break;
812
813     default:
814       failf(data, "unknown proxytype option given");
815       result = CURLE_COULDNT_CONNECT;
816     } /* switch proxytype */
817     if(pxresult) {
818       result = CURLE_PROXY;
819       data->info.pxcode = pxresult;
820     }
821   }
822   else
823 #else
824     (void)data;
825     (void)sockindex;
826 #endif /* CURL_DISABLE_PROXY */
827     *done = TRUE; /* no SOCKS proxy, so consider us connected */
828
829   return result;
830 }
831
832 /*
833  * post_SOCKS() is called after a successful connect to the peer, which
834  * *could* be a SOCKS proxy
835  */
836 static void post_SOCKS(struct Curl_easy *data,
837                        struct connectdata *conn,
838                        int sockindex,
839                        bool *connected)
840 {
841   conn->bits.tcpconnect[sockindex] = TRUE;
842
843   *connected = TRUE;
844   if(sockindex == FIRSTSOCKET)
845     Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
846   Curl_updateconninfo(data, conn, conn->sock[sockindex]);
847   Curl_verboseconnect(data, conn);
848   data->info.numconnects++; /* to track the number of connections made */
849 }
850
851 /*
852  * Curl_is_connected() checks if the socket has connected.
853  */
854
855 CURLcode Curl_is_connected(struct Curl_easy *data,
856                            struct connectdata *conn,
857                            int sockindex,
858                            bool *connected)
859 {
860   CURLcode result = CURLE_OK;
861   timediff_t allow;
862   int error = 0;
863   struct curltime now;
864   int rc = 0;
865   unsigned int i;
866
867   DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
868
869   *connected = FALSE; /* a very negative world view is best */
870
871   if(conn->bits.tcpconnect[sockindex]) {
872     /* we are connected already! */
873     *connected = TRUE;
874     return CURLE_OK;
875   }
876
877   now = Curl_now();
878
879   if(SOCKS_STATE(conn->cnnct.state)) {
880     /* still doing SOCKS */
881     result = connect_SOCKS(data, sockindex, connected);
882     if(!result && *connected)
883       post_SOCKS(data, conn, sockindex, connected);
884     return result;
885   }
886
887   for(i = 0; i<2; i++) {
888     const int other = i ^ 1;
889     if(conn->tempsock[i] == CURL_SOCKET_BAD)
890       continue;
891     error = 0;
892 #ifdef ENABLE_QUIC
893     if(conn->transport == TRNSPRT_QUIC) {
894       result = Curl_quic_is_connected(data, conn, i, connected);
895       if(!result && *connected) {
896         /* use this socket from now on */
897         conn->sock[sockindex] = conn->tempsock[i];
898         conn->ip_addr = conn->tempaddr[i];
899         conn->tempsock[i] = CURL_SOCKET_BAD;
900         post_SOCKS(data, conn, sockindex, connected);
901         connkeep(conn, "HTTP/3 default");
902         return CURLE_OK;
903       }
904       /* When a QUIC connect attempt fails, the better error explanation is in
905          'result' and not in errno */
906       if(result) {
907         conn->tempsock[i] = CURL_SOCKET_BAD;
908         error = SOCKERRNO;
909       }
910     }
911     else
912 #endif
913     {
914 #ifdef mpeix
915       /* Call this function once now, and ignore the results. We do this to
916          "clear" the error state on the socket so that we can later read it
917          reliably. This is reported necessary on the MPE/iX operating
918          system. */
919       (void)verifyconnect(conn->tempsock[i], NULL);
920 #endif
921
922       /* check socket for connect */
923       rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
924     }
925
926     if(rc == 0) { /* no connection yet */
927       if(Curl_timediff(now, conn->connecttime) >=
928          conn->timeoutms_per_addr[i]) {
929         infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
930               "ms connect time, move on!", conn->timeoutms_per_addr[i]);
931         error = ETIMEDOUT;
932       }
933
934       /* should we try another protocol family? */
935       if(i == 0 && !conn->bits.parallel_connect &&
936          (Curl_timediff(now, conn->connecttime) >=
937           data->set.happy_eyeballs_timeout)) {
938         conn->bits.parallel_connect = TRUE; /* starting now */
939         trynextip(data, conn, sockindex, 1);
940       }
941     }
942     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
943       if(verifyconnect(conn->tempsock[i], &error)) {
944         /* we are connected with TCP, awesome! */
945
946         /* use this socket from now on */
947         conn->sock[sockindex] = conn->tempsock[i];
948         conn->ip_addr = conn->tempaddr[i];
949         conn->tempsock[i] = CURL_SOCKET_BAD;
950 #ifdef ENABLE_IPV6
951         conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
952 #endif
953
954         /* close the other socket, if open */
955         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
956           Curl_closesocket(data, conn, conn->tempsock[other]);
957           conn->tempsock[other] = CURL_SOCKET_BAD;
958         }
959
960         /* see if we need to kick off any SOCKS proxy magic once we
961            connected */
962         result = connect_SOCKS(data, sockindex, connected);
963         if(result || !*connected)
964           return result;
965
966         post_SOCKS(data, conn, sockindex, connected);
967
968         return CURLE_OK;
969       }
970     }
971     else if(rc & CURL_CSELECT_ERR) {
972       (void)verifyconnect(conn->tempsock[i], &error);
973     }
974
975     /*
976      * The connection failed here, we should attempt to connect to the "next
977      * address" for the given host. But first remember the latest error.
978      */
979     if(error) {
980       data->state.os_errno = error;
981       SET_SOCKERRNO(error);
982       if(conn->tempaddr[i]) {
983         CURLcode status;
984 #ifndef CURL_DISABLE_VERBOSE_STRINGS
985         char ipaddress[MAX_IPADR_LEN];
986         char buffer[STRERROR_LEN];
987         Curl_printable_address(conn->tempaddr[i], ipaddress,
988                                sizeof(ipaddress));
989 #ifdef ENABLE_QUIC
990         if(conn->transport == TRNSPRT_QUIC) {
991           infof(data, "connect to %s port %u failed: %s",
992                 ipaddress, conn->port, curl_easy_strerror(result));
993         }
994         else
995 #endif
996         infof(data, "connect to %s port %u failed: %s",
997               ipaddress, conn->port,
998               Curl_strerror(error, buffer, sizeof(buffer)));
999 #endif
1000
1001         allow = Curl_timeleft(data, &now, TRUE);
1002         conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
1003           allow : allow / 2;
1004         ainext(conn, i, TRUE);
1005         status = trynextip(data, conn, sockindex, i);
1006         if((status != CURLE_COULDNT_CONNECT) ||
1007            conn->tempsock[other] == CURL_SOCKET_BAD) {
1008           /* the last attempt failed and no other sockets remain open */
1009           if(!result)
1010             result = status;
1011         }
1012       }
1013     }
1014   }
1015
1016   /*
1017    * Now that we've checked whether we are connected, check whether we've
1018    * already timed out.
1019    *
1020    * First figure out how long time we have left to connect */
1021
1022   allow = Curl_timeleft(data, &now, TRUE);
1023
1024   if(allow < 0) {
1025     /* time-out, bail out, go home */
1026     failf(data, "Connection timeout after %ld ms",
1027           Curl_timediff(now, data->progress.t_startsingle));
1028     return CURLE_OPERATION_TIMEDOUT;
1029   }
1030
1031   if(result &&
1032      (conn->tempsock[0] == CURL_SOCKET_BAD) &&
1033      (conn->tempsock[1] == CURL_SOCKET_BAD)) {
1034     /* no more addresses to try */
1035     const char *hostname;
1036     char buffer[STRERROR_LEN];
1037     CURLcode failreason = result;
1038
1039     /* if the first address family runs out of addresses to try before the
1040        happy eyeball timeout, go ahead and try the next family now */
1041     result = trynextip(data, conn, sockindex, 1);
1042     if(!result)
1043       return result;
1044
1045     result = failreason;
1046
1047 #ifndef CURL_DISABLE_PROXY
1048     if(conn->bits.socksproxy)
1049       hostname = conn->socks_proxy.host.name;
1050     else if(conn->bits.httpproxy)
1051       hostname = conn->http_proxy.host.name;
1052     else
1053 #endif
1054       if(conn->bits.conn_to_host)
1055         hostname = conn->conn_to_host.name;
1056     else
1057       hostname = conn->host.name;
1058
1059     failf(data, "Failed to connect to %s port %u after "
1060           "%" CURL_FORMAT_TIMEDIFF_T " ms: %s",
1061           hostname, conn->port,
1062           Curl_timediff(now, data->progress.t_startsingle),
1063 #ifdef ENABLE_QUIC
1064           (conn->transport == TRNSPRT_QUIC) ?
1065           curl_easy_strerror(result) :
1066 #endif
1067           Curl_strerror(error, buffer, sizeof(buffer)));
1068
1069     Curl_quic_disconnect(data, conn, 0);
1070     Curl_quic_disconnect(data, conn, 1);
1071
1072 #ifdef WSAETIMEDOUT
1073     if(WSAETIMEDOUT == data->state.os_errno)
1074       result = CURLE_OPERATION_TIMEDOUT;
1075 #elif defined(ETIMEDOUT)
1076     if(ETIMEDOUT == data->state.os_errno)
1077       result = CURLE_OPERATION_TIMEDOUT;
1078 #endif
1079   }
1080   else
1081     result = CURLE_OK; /* still trying */
1082
1083   return result;
1084 }
1085
1086 static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
1087 {
1088 #if defined(TCP_NODELAY)
1089   curl_socklen_t onoff = (curl_socklen_t) 1;
1090   int level = IPPROTO_TCP;
1091 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
1092   char buffer[STRERROR_LEN];
1093 #else
1094   (void) data;
1095 #endif
1096
1097   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
1098                 sizeof(onoff)) < 0)
1099     infof(data, "Could not set TCP_NODELAY: %s",
1100           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1101 #else
1102   (void)data;
1103   (void)sockfd;
1104 #endif
1105 }
1106
1107 #ifdef SO_NOSIGPIPE
1108 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
1109    sending data to a dead peer (instead of relying on the 4th argument to send
1110    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
1111    systems? */
1112 static void nosigpipe(struct Curl_easy *data,
1113                       curl_socket_t sockfd)
1114 {
1115   int onoff = 1;
1116   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
1117                 sizeof(onoff)) < 0) {
1118 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
1119     char buffer[STRERROR_LEN];
1120     infof(data, "Could not set SO_NOSIGPIPE: %s",
1121           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1122 #endif
1123   }
1124 }
1125 #else
1126 #define nosigpipe(x,y) Curl_nop_stmt
1127 #endif
1128
1129 #ifdef USE_WINSOCK
1130 /* When you run a program that uses the Windows Sockets API, you may
1131    experience slow performance when you copy data to a TCP server.
1132
1133    https://support.microsoft.com/kb/823764
1134
1135    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
1136    Buffer Size
1137
1138    The problem described in this knowledge-base is applied only to pre-Vista
1139    Windows.  Following function trying to detect OS version and skips
1140    SO_SNDBUF adjustment for Windows Vista and above.
1141 */
1142 #define DETECT_OS_NONE 0
1143 #define DETECT_OS_PREVISTA 1
1144 #define DETECT_OS_VISTA_OR_LATER 2
1145
1146 void Curl_sndbufset(curl_socket_t sockfd)
1147 {
1148   int val = CURL_MAX_WRITE_SIZE + 32;
1149   int curval = 0;
1150   int curlen = sizeof(curval);
1151
1152   static int detectOsState = DETECT_OS_NONE;
1153
1154   if(detectOsState == DETECT_OS_NONE) {
1155     if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
1156                                     VERSION_GREATER_THAN_EQUAL))
1157       detectOsState = DETECT_OS_VISTA_OR_LATER;
1158     else
1159       detectOsState = DETECT_OS_PREVISTA;
1160   }
1161
1162   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
1163     return;
1164
1165   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
1166     if(curval > val)
1167       return;
1168
1169   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
1170 }
1171 #endif
1172
1173 /*
1174  * singleipconnect()
1175  *
1176  * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
1177  * CURL_SOCKET_BAD. Other errors will however return proper errors.
1178  *
1179  * singleipconnect() connects to the given IP only, and it may return without
1180  * having connected.
1181  */
1182 static CURLcode singleipconnect(struct Curl_easy *data,
1183                                 struct connectdata *conn,
1184                                 const struct Curl_addrinfo *ai,
1185                                 int tempindex)
1186 {
1187   struct Curl_sockaddr_ex addr;
1188   int rc = -1;
1189   int error = 0;
1190   bool isconnected = FALSE;
1191   curl_socket_t sockfd;
1192   CURLcode result;
1193   char ipaddress[MAX_IPADR_LEN];
1194   int port;
1195   bool is_tcp;
1196 #ifdef TCP_FASTOPEN_CONNECT
1197   int optval = 1;
1198 #endif
1199   char buffer[STRERROR_LEN];
1200   curl_socket_t *sockp = &conn->tempsock[tempindex];
1201   *sockp = CURL_SOCKET_BAD;
1202
1203   result = Curl_socket(data, ai, &addr, &sockfd);
1204   if(result)
1205     return result;
1206
1207   /* store remote address and port used in this connection attempt */
1208   if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen,
1209                        ipaddress, &port)) {
1210     /* malformed address or bug in inet_ntop, try next address */
1211     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
1212           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1213     Curl_closesocket(data, conn, sockfd);
1214     return CURLE_OK;
1215   }
1216   infof(data, "  Trying %s:%d...", ipaddress, port);
1217
1218 #ifdef ENABLE_IPV6
1219   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
1220     addr.socktype == SOCK_STREAM;
1221 #else
1222   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
1223 #endif
1224   if(is_tcp && data->set.tcp_nodelay)
1225     tcpnodelay(data, sockfd);
1226
1227   nosigpipe(data, sockfd);
1228
1229   Curl_sndbufset(sockfd);
1230
1231   if(is_tcp && data->set.tcp_keepalive)
1232     tcpkeepalive(data, sockfd);
1233
1234   if(data->set.fsockopt) {
1235     /* activate callback for setting socket options */
1236     Curl_set_in_callback(data, true);
1237     error = data->set.fsockopt(data->set.sockopt_client,
1238                                sockfd,
1239                                CURLSOCKTYPE_IPCXN);
1240     Curl_set_in_callback(data, false);
1241
1242     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1243       isconnected = TRUE;
1244     else if(error) {
1245       Curl_closesocket(data, conn, sockfd); /* close the socket and bail out */
1246       return CURLE_ABORTED_BY_CALLBACK;
1247     }
1248   }
1249
1250   /* possibly bind the local end to an IP, interface or port */
1251   if(addr.family == AF_INET
1252 #ifdef ENABLE_IPV6
1253      || addr.family == AF_INET6
1254 #endif
1255     ) {
1256     result = bindlocal(data, sockfd, addr.family,
1257                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
1258     if(result) {
1259       Curl_closesocket(data, conn, sockfd); /* close socket and bail out */
1260       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1261         /* The address family is not supported on this interface.
1262            We can continue trying addresses */
1263         return CURLE_COULDNT_CONNECT;
1264       }
1265       return result;
1266     }
1267   }
1268
1269   /* set socket non-blocking */
1270   (void)curlx_nonblock(sockfd, TRUE);
1271
1272   conn->connecttime = Curl_now();
1273   if(conn->num_addr > 1) {
1274     Curl_expire(data, conn->timeoutms_per_addr[0], EXPIRE_DNS_PER_NAME);
1275     Curl_expire(data, conn->timeoutms_per_addr[1], EXPIRE_DNS_PER_NAME2);
1276   }
1277
1278   /* Connect TCP and QUIC sockets */
1279   if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
1280     if(conn->bits.tcp_fastopen) {
1281 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1282 #  if defined(HAVE_BUILTIN_AVAILABLE)
1283       /* while connectx function is available since macOS 10.11 / iOS 9,
1284          it did not have the interface declared correctly until
1285          Xcode 9 / macOS SDK 10.13 */
1286       if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1287         sa_endpoints_t endpoints;
1288         endpoints.sae_srcif = 0;
1289         endpoints.sae_srcaddr = NULL;
1290         endpoints.sae_srcaddrlen = 0;
1291         endpoints.sae_dstaddr = &addr.sa_addr;
1292         endpoints.sae_dstaddrlen = addr.addrlen;
1293
1294         rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
1295                       CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1296                       NULL, 0, NULL, NULL);
1297       }
1298       else {
1299         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1300       }
1301 #  else
1302       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1303 #  endif /* HAVE_BUILTIN_AVAILABLE */
1304 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1305       if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1306                     (void *)&optval, sizeof(optval)) < 0)
1307         infof(data, "Failed to enable TCP Fast Open on fd %d", sockfd);
1308
1309       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1310 #elif defined(MSG_FASTOPEN) /* old Linux */
1311       if(conn->given->flags & PROTOPT_SSL)
1312         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1313       else
1314         rc = 0; /* Do nothing */
1315 #endif
1316     }
1317     else {
1318       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1319     }
1320
1321     if(-1 == rc)
1322       error = SOCKERRNO;
1323 #ifdef ENABLE_QUIC
1324     else if(conn->transport == TRNSPRT_QUIC) {
1325       /* pass in 'sockfd' separately since it hasn't been put into the
1326          tempsock array at this point */
1327       result = Curl_quic_connect(data, conn, sockfd, tempindex,
1328                                  &addr.sa_addr, addr.addrlen);
1329       if(result)
1330         error = SOCKERRNO;
1331     }
1332 #endif
1333   }
1334   else {
1335     *sockp = sockfd;
1336     return CURLE_OK;
1337   }
1338
1339   if(-1 == rc) {
1340     switch(error) {
1341     case EINPROGRESS:
1342     case EWOULDBLOCK:
1343 #if defined(EAGAIN)
1344 #if (EAGAIN) != (EWOULDBLOCK)
1345       /* On some platforms EAGAIN and EWOULDBLOCK are the
1346        * same value, and on others they are different, hence
1347        * the odd #if
1348        */
1349     case EAGAIN:
1350 #endif
1351 #endif
1352       result = CURLE_OK;
1353       break;
1354
1355     default:
1356       /* unknown error, fallthrough and try another address! */
1357       infof(data, "Immediate connect fail for %s: %s",
1358             ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
1359       data->state.os_errno = error;
1360
1361       /* connect failed */
1362       Curl_closesocket(data, conn, sockfd);
1363       result = CURLE_COULDNT_CONNECT;
1364     }
1365   }
1366
1367   if(!result)
1368     *sockp = sockfd;
1369
1370   return result;
1371 }
1372
1373 /*
1374  * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1375  * There might be more than one IP address to try out. Fill in the passed
1376  * pointer with the connected socket.
1377  */
1378
1379 CURLcode Curl_connecthost(struct Curl_easy *data,
1380                           struct connectdata *conn,  /* context */
1381                           const struct Curl_dns_entry *remotehost)
1382 {
1383   CURLcode result = CURLE_COULDNT_CONNECT;
1384   int i;
1385   timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
1386
1387   if(timeout_ms < 0) {
1388     /* a precaution, no need to continue if time already is up */
1389     failf(data, "Connection time-out");
1390     return CURLE_OPERATION_TIMEDOUT;
1391   }
1392
1393   conn->num_addr = Curl_num_addresses(remotehost->addr);
1394   conn->tempaddr[0] = conn->tempaddr[1] = remotehost->addr;
1395   conn->tempsock[0] = conn->tempsock[1] = CURL_SOCKET_BAD;
1396
1397   /* Max time for the next connection attempt */
1398   conn->timeoutms_per_addr[0] =
1399     conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
1400   conn->timeoutms_per_addr[1] =
1401     conn->tempaddr[1]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
1402
1403   if(conn->ip_version == CURL_IPRESOLVE_WHATEVER) {
1404     /* any IP version is allowed */
1405     conn->tempfamily[0] = conn->tempaddr[0]?
1406       conn->tempaddr[0]->ai_family:0;
1407 #ifdef ENABLE_IPV6
1408     conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
1409       AF_INET : AF_INET6;
1410 #else
1411     conn->tempfamily[1] = AF_UNSPEC;
1412 #endif
1413   }
1414   else {
1415     /* only one IP version is allowed */
1416     conn->tempfamily[0] = (conn->ip_version == CURL_IPRESOLVE_V4) ?
1417       AF_INET :
1418 #ifdef ENABLE_IPV6
1419       AF_INET6;
1420 #else
1421       AF_UNSPEC;
1422 #endif
1423     conn->tempfamily[1] = AF_UNSPEC;
1424
1425     ainext(conn, 0, FALSE); /* find first address of the right type */
1426   }
1427
1428   ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
1429
1430   DEBUGF(infof(data, "family0 == %s, family1 == %s",
1431                conn->tempfamily[0] == AF_INET ? "v4" : "v6",
1432                conn->tempfamily[1] == AF_INET ? "v4" : "v6"));
1433
1434   /* get through the list in family order in case of quick failures */
1435   for(i = 0; (i < 2) && result; i++) {
1436     while(conn->tempaddr[i]) {
1437       result = singleipconnect(data, conn, conn->tempaddr[i], i);
1438       if(!result)
1439         break;
1440       ainext(conn, i, TRUE);
1441     }
1442   }
1443   if(result)
1444     return result;
1445
1446   Curl_expire(data, data->set.happy_eyeballs_timeout,
1447               EXPIRE_HAPPY_EYEBALLS);
1448
1449   return CURLE_OK;
1450 }
1451
1452 struct connfind {
1453   long id_tofind;
1454   struct connectdata *found;
1455 };
1456
1457 static int conn_is_conn(struct Curl_easy *data,
1458                         struct connectdata *conn, void *param)
1459 {
1460   struct connfind *f = (struct connfind *)param;
1461   (void)data;
1462   if(conn->connection_id == f->id_tofind) {
1463     f->found = conn;
1464     return 1;
1465   }
1466   return 0;
1467 }
1468
1469 /*
1470  * Used to extract socket and connectdata struct for the most recent
1471  * transfer on the given Curl_easy.
1472  *
1473  * The returned socket will be CURL_SOCKET_BAD in case of failure!
1474  */
1475 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
1476                                   struct connectdata **connp)
1477 {
1478   DEBUGASSERT(data);
1479
1480   /* this works for an easy handle:
1481    * - that has been used for curl_easy_perform()
1482    * - that is associated with a multi handle, and whose connection
1483    *   was detached with CURLOPT_CONNECT_ONLY
1484    */
1485   if((data->state.lastconnect_id != -1) && (data->multi_easy || data->multi)) {
1486     struct connectdata *c;
1487     struct connfind find;
1488     find.id_tofind = data->state.lastconnect_id;
1489     find.found = NULL;
1490
1491     Curl_conncache_foreach(data,
1492                            data->share && (data->share->specifier
1493                            & (1<< CURL_LOCK_DATA_CONNECT))?
1494                            &data->share->conn_cache:
1495                            data->multi_easy?
1496                            &data->multi_easy->conn_cache:
1497                            &data->multi->conn_cache, &find, conn_is_conn);
1498
1499     if(!find.found) {
1500       data->state.lastconnect_id = -1;
1501       return CURL_SOCKET_BAD;
1502     }
1503
1504     c = find.found;
1505     if(connp)
1506       /* only store this if the caller cares for it */
1507       *connp = c;
1508     return c->sock[FIRSTSOCKET];
1509   }
1510   return CURL_SOCKET_BAD;
1511 }
1512
1513 /*
1514  * Check if a connection seems to be alive.
1515  */
1516 bool Curl_connalive(struct connectdata *conn)
1517 {
1518   /* First determine if ssl */
1519   if(conn->ssl[FIRSTSOCKET].use) {
1520     /* use the SSL context */
1521     if(!Curl_ssl_check_cxn(conn))
1522       return false;   /* FIN received */
1523   }
1524 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1525 #ifdef MSG_PEEK
1526   else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
1527     return false;
1528   else {
1529     /* use the socket */
1530     char buf;
1531     if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1532             (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1533       return false;   /* FIN received */
1534     }
1535   }
1536 #endif
1537   return true;
1538 }
1539
1540 /*
1541  * Close a socket.
1542  *
1543  * 'conn' can be NULL, beware!
1544  */
1545 int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
1546                      curl_socket_t sock)
1547 {
1548   if(conn && conn->fclosesocket) {
1549     if((sock == conn->sock[SECONDARYSOCKET]) && conn->bits.sock_accepted)
1550       /* if this socket matches the second socket, and that was created with
1551          accept, then we MUST NOT call the callback but clear the accepted
1552          status */
1553       conn->bits.sock_accepted = FALSE;
1554     else {
1555       int rc;
1556       Curl_multi_closed(data, sock);
1557       Curl_set_in_callback(data, true);
1558       rc = conn->fclosesocket(conn->closesocket_client, sock);
1559       Curl_set_in_callback(data, false);
1560       return rc;
1561     }
1562   }
1563
1564   if(conn)
1565     /* tell the multi-socket code about this */
1566     Curl_multi_closed(data, sock);
1567
1568   sclose(sock);
1569
1570   return 0;
1571 }
1572
1573 /*
1574  * Create a socket based on info from 'conn' and 'ai'.
1575  *
1576  * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1577  * 'sockfd' must be a pointer to a socket descriptor.
1578  *
1579  * If the open socket callback is set, used that!
1580  *
1581  */
1582 CURLcode Curl_socket(struct Curl_easy *data,
1583                      const struct Curl_addrinfo *ai,
1584                      struct Curl_sockaddr_ex *addr,
1585                      curl_socket_t *sockfd)
1586 {
1587   struct connectdata *conn = data->conn;
1588   struct Curl_sockaddr_ex dummy;
1589
1590   if(!addr)
1591     /* if the caller doesn't want info back, use a local temp copy */
1592     addr = &dummy;
1593
1594   /*
1595    * The Curl_sockaddr_ex structure is basically libcurl's external API
1596    * curl_sockaddr structure with enough space available to directly hold
1597    * any protocol-specific address structures. The variable declared here
1598    * will be used to pass / receive data to/from the fopensocket callback
1599    * if this has been set, before that, it is initialized from parameters.
1600    */
1601
1602   addr->family = ai->ai_family;
1603   addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1604   addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP :
1605     ai->ai_protocol;
1606   addr->addrlen = ai->ai_addrlen;
1607
1608   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1609      addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1610   memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1611
1612   if(data->set.fopensocket) {
1613    /*
1614     * If the opensocket callback is set, all the destination address
1615     * information is passed to the callback. Depending on this information the
1616     * callback may opt to abort the connection, this is indicated returning
1617     * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1618     * the callback returns a valid socket the destination address information
1619     * might have been changed and this 'new' address will actually be used
1620     * here to connect.
1621     */
1622     Curl_set_in_callback(data, true);
1623     *sockfd = data->set.fopensocket(data->set.opensocket_client,
1624                                     CURLSOCKTYPE_IPCXN,
1625                                     (struct curl_sockaddr *)addr);
1626     Curl_set_in_callback(data, false);
1627   }
1628   else
1629     /* opensocket callback not set, so simply create the socket now */
1630     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1631
1632   if(*sockfd == CURL_SOCKET_BAD)
1633     /* no socket, no connection */
1634     return CURLE_COULDNT_CONNECT;
1635
1636   if(conn->transport == TRNSPRT_QUIC) {
1637     /* QUIC sockets need to be nonblocking */
1638     (void)curlx_nonblock(*sockfd, TRUE);
1639   }
1640
1641 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1642   if(conn->scope_id && (addr->family == AF_INET6)) {
1643     struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1644     sa6->sin6_scope_id = conn->scope_id;
1645   }
1646 #endif
1647
1648 #if defined(__linux__) && defined(IP_RECVERR)
1649   if(addr->socktype == SOCK_DGRAM) {
1650     int one = 1;
1651     switch(addr->family) {
1652     case AF_INET:
1653       (void)setsockopt(*sockfd, SOL_IP, IP_RECVERR, &one, sizeof(one));
1654       break;
1655     case AF_INET6:
1656       (void)setsockopt(*sockfd, SOL_IPV6, IPV6_RECVERR, &one, sizeof(one));
1657       break;
1658     }
1659   }
1660 #endif
1661
1662   return CURLE_OK;
1663 }
1664
1665 /*
1666  * Curl_conncontrol() marks streams or connection for closure.
1667  */
1668 void Curl_conncontrol(struct connectdata *conn,
1669                       int ctrl /* see defines in header */
1670 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1671                       , const char *reason
1672 #endif
1673   )
1674 {
1675   /* close if a connection, or a stream that isn't multiplexed. */
1676   /* This function will be called both before and after this connection is
1677      associated with a transfer. */
1678   bool closeit;
1679   DEBUGASSERT(conn);
1680 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1681   (void)reason; /* useful for debugging */
1682 #endif
1683   closeit = (ctrl == CONNCTRL_CONNECTION) ||
1684     ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
1685   if((ctrl == CONNCTRL_STREAM) &&
1686      (conn->handler->flags & PROTOPT_STREAM))
1687     ;
1688   else if((bit)closeit != conn->bits.close) {
1689     conn->bits.close = closeit; /* the only place in the source code that
1690                                    should assign this bit */
1691   }
1692 }
1693
1694 /* Data received can be cached at various levels, so check them all here. */
1695 bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
1696 {
1697   int readable;
1698   DEBUGASSERT(conn);
1699
1700   if(Curl_ssl_data_pending(conn, sockindex) ||
1701      Curl_recv_has_postponed_data(conn, sockindex))
1702     return true;
1703
1704   readable = SOCKET_READABLE(conn->sock[sockindex], 0);
1705   return (readable > 0 && (readable & CURL_CSELECT_IN));
1706 }