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