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