VirtualBox

source: vbox/trunk/src/libs/curl-7.83.1/lib/connect.c@ 95312

Last change on this file since 95312 was 95312, checked in by vboxsync, 2 years ago

libs/{curl,libxml2}: OSE export fixes, bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette