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