1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
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.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * SPDX-License-Identifier: curl
23 ***************************************************************************/
25 #include "curl_setup.h"
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
31 #include <sys/un.h> /* for sockaddr_un */
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
38 #ifdef HAVE_SYS_IOCTL_H
39 #include <sys/ioctl.h>
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
51 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
52 #include <sys/filio.h>
56 #define in_addr_t unsigned long
69 #include "url.h" /* for Curl_safefree() */
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() */
77 #include "conncache.h"
78 #include "multihandle.h"
80 #include "version_win32.h"
84 /* The last 3 #include files should be in this order */
85 #include "curl_printf.h"
86 #include "curl_memory.h"
89 static bool verifyconnect(curl_socket_t sockfd, int *error);
91 #if defined(__DragonFly__) || defined(HAVE_WINSOCK2_H)
92 /* DragonFlyBSD and Windows use millisecond units */
93 #define KEEPALIVE_FACTOR(x) (x *= 1000)
95 #define KEEPALIVE_FACTOR(x)
98 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
99 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
101 struct tcp_keepalive {
103 u_long keepalivetime;
104 u_long keepaliveinterval;
109 tcpkeepalive(struct Curl_easy *data,
110 curl_socket_t sockfd)
112 int optval = data->set.tcp_keepalive?1:0;
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);
120 #if defined(SIO_KEEPALIVE_VALS)
121 struct tcp_keepalive vals;
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());
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);
143 #elif defined(TCP_KEEPALIVE)
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);
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);
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 */
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
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!
183 #define TIMEOUT_CONNECT 1
184 #define TIMEOUT_MAXTIME 2
186 timediff_t Curl_timeleft(struct Curl_easy *data,
187 struct curltime *nowp,
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;
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. */
202 if(data->set.timeout > 0) {
203 timeout_set = TIMEOUT_MAXTIME;
204 maxtime_timeout_ms = data->set.timeout;
207 timeout_set |= TIMEOUT_CONNECT;
208 connect_timeout_ms = (data->set.connecttimeout > 0) ?
209 data->set.connecttimeout : DEFAULT_CONNECT_TIMEOUT;
220 if(timeout_set & TIMEOUT_MAXTIME) {
221 maxtime_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
222 timeout_ms = maxtime_timeout_ms;
225 if(timeout_set & TIMEOUT_CONNECT) {
226 connect_timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
228 if(!(timeout_set & TIMEOUT_MAXTIME) ||
229 (connect_timeout_ms < maxtime_timeout_ms))
230 timeout_ms = connect_timeout_ms;
234 /* avoid returning 0 as that means no timeout! */
240 static CURLcode bindlocal(struct Curl_easy *data,
241 curl_socket_t sockfd, int af, unsigned int scope)
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;
249 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
252 struct Curl_dns_entry *h = NULL;
253 unsigned short port = data->set.localport; /* use this port number, 0 for
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];
259 #ifdef IP_BIND_ADDRESS_NO_PORT
266 /*************************************************************
267 * Select device to bind socket to
268 *************************************************************/
270 /* no local kind of binding was requested */
273 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
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!";
283 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
284 dev += strlen(if_prefix);
287 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
288 dev += strlen(host_prefix);
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
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.
303 * Only bind to the interface when specified as interface, not just
304 * as a hostname or ip address.
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.
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
315 * If it succeeds it means the parameter was a valid interface and
316 * not an IP address. Return immediately.
322 switch(Curl_if2ip(af,
324 scope, conn->scope_id,
326 dev, myhost, sizeof(myhost))) {
327 case IF2IP_NOT_FOUND:
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;
334 case IF2IP_AF_NOT_SUPPORTED:
335 /* Signal the caller to try another address family if available */
336 return CURLE_UNSUPPORTED_PROTOCOL;
340 * We now have the numerical IP address in the 'myhost' buffer
342 infof(data, "Local Interface %s is ip %s using address family %i",
350 * This was not an interface, resolve the name as a host name
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.
357 unsigned char ipver = conn->ip_version;
361 conn->ip_version = CURL_IPRESOLVE_V4;
363 else if(af == AF_INET6)
364 conn->ip_version = CURL_IPRESOLVE_V6;
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;
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;
387 * provided dev was no interface (or interfaces are not supported
388 * e.g. solaris) no ip address and no domain we fail here
398 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
399 char *scope_ptr = strchr(myhost, '%');
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
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);
415 sizeof_sa = sizeof(struct sockaddr_in6);
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);
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;
438 /* no device was given, prepare sa to match af's needs */
441 si6->sin6_family = AF_INET6;
442 si6->sin6_port = htons(port);
443 sizeof_sa = sizeof(struct sockaddr_in6);
448 si4->sin_family = AF_INET;
449 si4->sin_port = htons(port);
450 sizeof_sa = sizeof(struct sockaddr_in);
453 #ifdef IP_BIND_ADDRESS_NO_PORT
454 (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
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;
469 infof(data, "Local port: %hu", port);
470 conn->bits.bound = TRUE;
475 port++; /* try next port */
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);
484 si6->sin6_port = ntohs(port);
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)));
497 return CURLE_INTERFACE_FAILED;
501 * verifyconnect() returns TRUE if the connect really has happened.
503 static bool verifyconnect(curl_socket_t sockfd, int *error)
508 curl_socklen_t errSize = sizeof(err);
512 * In October 2003 we effectively nullified this function on Windows due to
513 * problems with it using all CPU in multi-threaded cases.
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:
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.
524 * Someone got to verify this on Win-NT 4.0, 2000."
535 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
538 /* Old WinCE versions don't support SO_ERROR */
539 if(WSAENOPROTOOPT == err) {
544 #if defined(EBADIOCTL) && defined(__minix)
545 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
546 if(EBADIOCTL == err) {
551 if((0 == err) || (EISCONN == err))
552 /* we are connected, awesome! */
555 /* This wasn't a successful connect */
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,
571 bool next) /* use next entry? */
573 struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
576 while(ai && (ai->ai_family != conn->tempfamily[tempindex]))
578 conn->tempaddr[tempindex] = ai;
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,
589 CURLcode result = CURLE_COULDNT_CONNECT;
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;
598 if(sockindex == FIRSTSOCKET) {
599 struct Curl_addrinfo *ai = conn->tempaddr[tempindex];
602 result = singleipconnect(data, conn, ai, tempindex);
603 if(result == CURLE_COULDNT_CONNECT) {
604 ai = ainext(conn, tempindex, TRUE);
611 if(fd_to_close != CURL_SOCKET_BAD)
612 Curl_closesocket(data, conn, fd_to_close);
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)
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);
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;
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)
640 struct sockaddr_in *si = NULL;
642 struct sockaddr_in6 *si6 = NULL;
644 #if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(AF_UNIX)
645 struct sockaddr_un *su = NULL;
650 switch(sa->sa_family) {
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);
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);
671 #if (defined(HAVE_SYS_UN_H) || defined(WIN32_SOCKADDR_UN)) && defined(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);
678 addr[0] = 0; /* socket with no name */
688 errno = EAFNOSUPPORT;
692 /* retrieves the start/end point information of a socket of an established
694 void Curl_conninfo_remote(struct Curl_easy *data,
695 struct connectdata *conn, curl_socket_t sockfd)
697 #ifdef HAVE_GETPEERNAME
698 char buffer[STRERROR_LEN];
699 struct Curl_sockaddr_storage ssrem;
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)));
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)));
723 /* retrieves the start/end point information of a socket of an established
725 void Curl_conninfo_local(struct Curl_easy *data, curl_socket_t sockfd,
726 char *local_ip, int *local_port)
728 #ifdef HAVE_GETSOCKNAME
729 char buffer[STRERROR_LEN];
730 struct Curl_sockaddr_storage ssloc;
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)));
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)));
754 /* retrieves the start/end point information of a socket of an established
756 void Curl_updateconninfo(struct Curl_easy *data, struct connectdata *conn,
757 curl_socket_t sockfd)
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] = "";
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);
770 /* persist connection info in session handle */
771 Curl_persistconninfo(data, conn, local_ip, local_port);
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.
778 Note: this function's sub-functions call failf()
781 static CURLcode connect_SOCKS(struct Curl_easy *data, int sockindex,
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)
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;
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 :
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);
811 case CURLPROXY_SOCKS4:
812 case CURLPROXY_SOCKS4A:
813 pxresult = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
818 failf(data, "unknown proxytype option given");
819 result = CURLE_COULDNT_CONNECT;
820 } /* switch proxytype */
822 result = CURLE_PROXY;
823 data->info.pxcode = pxresult;
830 #endif /* CURL_DISABLE_PROXY */
831 *done = TRUE; /* no SOCKS proxy, so consider us connected */
837 * post_SOCKS() is called after a successful connect to the peer, which
838 * *could* be a SOCKS proxy
840 static void post_SOCKS(struct Curl_easy *data,
841 struct connectdata *conn,
845 conn->bits.tcpconnect[sockindex] = 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 */
856 * Curl_is_connected() checks if the socket has connected.
859 CURLcode Curl_is_connected(struct Curl_easy *data,
860 struct connectdata *conn,
864 CURLcode result = CURLE_OK;
871 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
873 *connected = FALSE; /* a very negative world view is best */
875 if(conn->bits.tcpconnect[sockindex]) {
876 /* we are connected already! */
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);
891 for(i = 0; i<2; i++) {
892 const int other = i ^ 1;
893 if(conn->tempsock[i] == CURL_SOCKET_BAD)
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);
910 /* When a QUIC connect attempt fails, the better error explanation is in
911 'result' and not in errno */
913 conn->tempsock[i] = CURL_SOCKET_BAD;
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
925 (void)verifyconnect(conn->tempsock[i], NULL);
928 /* check socket for connect */
929 rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
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]);
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);
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! */
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;
957 conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
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;
966 /* see if we need to kick off any SOCKS proxy magic once we
968 result = connect_SOCKS(data, sockindex, connected);
969 if(result || !*connected)
972 post_SOCKS(data, conn, sockindex, connected);
977 else if(rc & CURL_CSELECT_ERR) {
978 (void)verifyconnect(conn->tempsock[i], &error);
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.
986 data->state.os_errno = error;
987 SET_SOCKERRNO(error);
988 if(conn->tempaddr[i]) {
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,
996 if(conn->transport == TRNSPRT_QUIC) {
997 infof(data, "connect to %s port %u failed: %s",
998 ipaddress, conn->port, curl_easy_strerror(result));
1002 infof(data, "connect to %s port %u failed: %s",
1003 ipaddress, conn->port,
1004 Curl_strerror(error, buffer, sizeof(buffer)));
1007 allow = Curl_timeleft(data, &now, TRUE);
1008 conn->timeoutms_per_addr[i] = conn->tempaddr[i]->ai_next == NULL ?
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 */
1023 * Now that we've checked whether we are connected, check whether we've
1024 * already timed out.
1026 * First figure out how long time we have left to connect */
1028 allow = Curl_timeleft(data, &now, TRUE);
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;
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;
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);
1050 result = failreason;
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;
1059 if(conn->bits.conn_to_host)
1060 hostname = conn->conn_to_host.name;
1062 hostname = conn->host.name;
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));
1070 Curl_quic_disconnect(data, conn, 0);
1071 Curl_quic_disconnect(data, conn, 1);
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;
1082 result = CURLE_OK; /* still trying */
1087 static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
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];
1098 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
1100 infof(data, "Could not set TCP_NODELAY: %s",
1101 Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
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
1113 static void nosigpipe(struct Curl_easy *data,
1114 curl_socket_t sockfd)
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)));
1127 #define nosigpipe(x,y) Curl_nop_stmt
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.
1134 https://support.microsoft.com/kb/823764
1136 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
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.
1143 #define DETECT_OS_NONE 0
1144 #define DETECT_OS_PREVISTA 1
1145 #define DETECT_OS_VISTA_OR_LATER 2
1147 void Curl_sndbufset(curl_socket_t sockfd)
1149 int val = CURL_MAX_WRITE_SIZE + 32;
1151 int curlen = sizeof(curval);
1153 static int detectOsState = DETECT_OS_NONE;
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;
1160 detectOsState = DETECT_OS_PREVISTA;
1163 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
1166 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
1170 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
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.
1180 * singleipconnect() connects to the given IP only, and it may return without
1183 static CURLcode singleipconnect(struct Curl_easy *data,
1184 struct connectdata *conn,
1185 const struct Curl_addrinfo *ai,
1188 struct Curl_sockaddr_ex addr;
1191 bool isconnected = FALSE;
1192 curl_socket_t sockfd;
1194 char ipaddress[MAX_IPADR_LEN];
1197 #ifdef TCP_FASTOPEN_CONNECT
1201 char buffer[STRERROR_LEN];
1202 curl_socket_t *sockp = &conn->tempsock[tempindex];
1203 *sockp = CURL_SOCKET_BAD;
1205 result = Curl_socket(data, ai, &addr, &sockfd);
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);
1219 if(addr.family == AF_INET6)
1220 ipmsg = " Trying [%s]:%d...";
1223 ipmsg = " Trying %s:%d...";
1224 infof(data, ipmsg, ipaddress, port);
1227 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
1228 addr.socktype == SOCK_STREAM;
1230 is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
1232 if(is_tcp && data->set.tcp_nodelay)
1233 tcpnodelay(data, sockfd);
1235 nosigpipe(data, sockfd);
1237 Curl_sndbufset(sockfd);
1239 if(is_tcp && data->set.tcp_keepalive)
1240 tcpkeepalive(data, sockfd);
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,
1247 CURLSOCKTYPE_IPCXN);
1248 Curl_set_in_callback(data, false);
1250 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1253 Curl_closesocket(data, conn, sockfd); /* close the socket and bail out */
1254 return CURLE_ABORTED_BY_CALLBACK;
1258 /* possibly bind the local end to an IP, interface or port */
1259 if(addr.family == AF_INET
1261 || addr.family == AF_INET6
1264 result = bindlocal(data, sockfd, addr.family,
1265 Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
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;
1277 /* set socket non-blocking */
1278 (void)curlx_nonblock(sockfd, TRUE);
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);
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;
1302 rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
1303 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1304 NULL, 0, NULL, NULL);
1307 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
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);
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);
1322 rc = 0; /* Do nothing */
1326 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
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);
1352 #if (EAGAIN) != (EWOULDBLOCK)
1353 /* On some platforms EAGAIN and EWOULDBLOCK are the
1354 * same value, and on others they are different, hence
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;
1369 /* connect failed */
1370 Curl_closesocket(data, conn, sockfd);
1371 result = CURLE_COULDNT_CONNECT;
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.
1387 CURLcode Curl_connecthost(struct Curl_easy *data,
1388 struct connectdata *conn, /* context */
1389 const struct Curl_dns_entry *remotehost)
1391 CURLcode result = CURLE_COULDNT_CONNECT;
1393 timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
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;
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;
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;
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;
1416 conn->tempfamily[1] = conn->tempfamily[0] == AF_INET6 ?
1419 conn->tempfamily[1] = AF_UNSPEC;
1423 /* only one IP version is allowed */
1424 conn->tempfamily[0] = (conn->ip_version == CURL_IPRESOLVE_V4) ?
1431 conn->tempfamily[1] = AF_UNSPEC;
1433 ainext(conn, 0, FALSE); /* find first address of the right type */
1436 ainext(conn, 1, FALSE); /* assigns conn->tempaddr[1] accordingly */
1438 DEBUGF(infof(data, "family0 == %s, family1 == %s",
1439 conn->tempfamily[0] == AF_INET ? "v4" : "v6",
1440 conn->tempfamily[1] == AF_INET ? "v4" : "v6"));
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);
1448 ainext(conn, i, TRUE);
1454 Curl_expire(data, data->set.happy_eyeballs_timeout,
1455 EXPIRE_HAPPY_EYEBALLS);
1462 struct connectdata *found;
1465 static int conn_is_conn(struct Curl_easy *data,
1466 struct connectdata *conn, void *param)
1468 struct connfind *f = (struct connfind *)param;
1470 if(conn->connection_id == f->id_tofind) {
1478 * Used to extract socket and connectdata struct for the most recent
1479 * transfer on the given Curl_easy.
1481 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1483 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
1484 struct connectdata **connp)
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
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;
1499 Curl_conncache_foreach(data,
1500 data->share && (data->share->specifier
1501 & (1<< CURL_LOCK_DATA_CONNECT))?
1502 &data->share->conn_cache:
1504 &data->multi_easy->conn_cache:
1505 &data->multi->conn_cache, &find, conn_is_conn);
1508 data->state.lastconnect_id = -1;
1509 return CURL_SOCKET_BAD;
1514 /* only store this if the caller cares for it */
1516 return c->sock[FIRSTSOCKET];
1518 return CURL_SOCKET_BAD;
1522 * Check if a connection seems to be alive.
1524 bool Curl_connalive(struct connectdata *conn)
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 */
1532 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1534 else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
1537 /* use the socket */
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 */
1551 * 'conn' can be NULL, beware!
1553 int Curl_closesocket(struct Curl_easy *data, struct connectdata *conn,
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
1561 conn->bits.sock_accepted = FALSE;
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);
1573 /* tell the multi-socket code about this */
1574 Curl_multi_closed(data, sock);
1582 * Create a socket based on info from 'conn' and 'ai'.
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.
1587 * If the open socket callback is set, used that!
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)
1595 struct connectdata *conn = data->conn;
1596 struct Curl_sockaddr_ex dummy;
1599 /* if the caller doesn't want info back, use a local temp copy */
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.
1610 addr->family = ai->ai_family;
1611 switch(conn->transport) {
1613 addr->socktype = SOCK_STREAM;
1614 addr->protocol = IPPROTO_TCP;
1617 addr->socktype = SOCK_STREAM;
1618 addr->protocol = IPPROTO_IP;
1620 default: /* UDP and QUIC */
1621 addr->socktype = SOCK_DGRAM;
1622 addr->protocol = IPPROTO_UDP;
1625 addr->addrlen = ai->ai_addrlen;
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);
1631 if(data->set.fopensocket) {
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
1641 Curl_set_in_callback(data, true);
1642 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1644 (struct curl_sockaddr *)addr);
1645 Curl_set_in_callback(data, false);
1648 /* opensocket callback not set, so simply create the socket now */
1649 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1651 if(*sockfd == CURL_SOCKET_BAD)
1652 /* no socket, no connection */
1653 return CURLE_COULDNT_CONNECT;
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)
1661 int val = IP_PMTUDISC_DO;
1662 (void)setsockopt(*sockfd, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1667 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1669 int val = IPV6_PMTUDISC_DO;
1670 (void)setsockopt(*sockfd, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
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;
1689 * Curl_conncontrol() marks streams or connection for closure.
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
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. */
1703 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1704 (void)reason; /* useful for debugging */
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))
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 */
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)
1723 if(Curl_ssl_data_pending(conn, sockindex) ||
1724 Curl_recv_has_postponed_data(conn, sockindex))
1727 readable = SOCKET_READABLE(conn->sock[sockindex], 0);
1728 return (readable > 0 && (readable & CURL_CSELECT_IN));