1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #include <sys/un.h> /* for sockaddr_un */
31 #ifdef HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h> /* for TCP_NODELAY */
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
47 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
48 #include <sys/filio.h>
52 #define in_addr_t unsigned long
65 #include "url.h" /* for Curl_safefree() */
67 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
70 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
73 #include "conncache.h"
74 #include "multihandle.h"
75 #include "system_win32.h"
77 /* The last 3 #include files should be in this order */
78 #include "curl_printf.h"
79 #include "curl_memory.h"
83 /* This isn't actually supported under Symbian OS */
87 static bool verifyconnect(curl_socket_t sockfd, int *error);
89 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
90 /* DragonFlyBSD and Windows use millisecond units */
91 #define KEEPALIVE_FACTOR(x) (x *= 1000)
93 #define KEEPALIVE_FACTOR(x)
96 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
97 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
99 struct tcp_keepalive {
101 u_long keepalivetime;
102 u_long keepaliveinterval;
107 tcpkeepalive(struct Curl_easy *data,
108 curl_socket_t sockfd)
110 int optval = data->set.tcp_keepalive?1:0;
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\n", sockfd);
118 #if defined(SIO_KEEPALIVE_VALS)
119 struct tcp_keepalive vals;
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\n",
131 (int)sockfd, WSAGetLastError());
133 #elif defined(CURL_WINDOWS_APP)
135 detectOsState = DETECT_OS_VISTA_OR_LATER;
138 optval = curlx_sltosi(data->set.tcp_keepidle);
139 KEEPALIVE_FACTOR(optval);
140 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
141 (void *)&optval, sizeof(optval)) < 0) {
142 infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
146 optval = curlx_sltosi(data->set.tcp_keepintvl);
147 KEEPALIVE_FACTOR(optval);
148 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
149 (void *)&optval, sizeof(optval)) < 0) {
150 infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
155 optval = curlx_sltosi(data->set.tcp_keepidle);
156 KEEPALIVE_FACTOR(optval);
157 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
158 (void *)&optval, sizeof(optval)) < 0) {
159 infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
167 singleipconnect(struct connectdata *conn,
168 const Curl_addrinfo *ai, /* start connecting to this */
169 curl_socket_t *sock);
172 * Curl_timeleft() returns the amount of milliseconds left allowed for the
173 * transfer/connection. If the value is negative, the timeout time has already
176 * The start time is stored in progress.t_startsingle - as set with
177 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
179 * If 'nowp' is non-NULL, it points to the current time.
180 * 'duringconnect' is FALSE if not during a connect, as then of course the
181 * connect timeout is not taken into account!
185 long Curl_timeleft(struct Curl_easy *data,
186 struct timeval *nowp,
190 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
193 /* if a timeout is set, use the most restrictive one */
195 if(data->set.timeout > 0)
197 if(duringconnect && (data->set.connecttimeout > 0))
200 switch (timeout_set) {
202 timeout_ms = data->set.timeout;
205 timeout_ms = data->set.connecttimeout;
208 if(data->set.timeout < data->set.connecttimeout)
209 timeout_ms = data->set.timeout;
211 timeout_ms = data->set.connecttimeout;
214 /* use the default */
216 /* if we're not during connect, there's no default timeout so if we're
217 at zero we better just return zero and not make it a negative number
228 /* subtract elapsed time */
230 /* since this most recent connect started */
231 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
233 /* since the entire operation started */
234 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startop);
236 /* avoid returning 0 as that means no timeout! */
242 static CURLcode bindlocal(struct connectdata *conn,
243 curl_socket_t sockfd, int af, unsigned int scope)
245 struct Curl_easy *data = conn->data;
247 struct Curl_sockaddr_storage sa;
248 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
249 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
250 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
252 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
255 struct Curl_dns_entry *h=NULL;
256 unsigned short port = data->set.localport; /* use this port number, 0 for
258 /* how many port numbers to try to bind to, increasing one at a time */
259 int portnum = data->set.localportrange;
260 const char *dev = data->set.str[STRING_DEVICE];
263 /*************************************************************
264 * Select device to bind socket to
265 *************************************************************/
267 /* no local kind of binding was requested */
270 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
272 if(dev && (strlen(dev)<255) ) {
273 char myhost[256] = "";
274 int done = 0; /* -1 for error, 1 for address found */
275 bool is_interface = FALSE;
276 bool is_host = FALSE;
277 static const char *if_prefix = "if!";
278 static const char *host_prefix = "host!";
280 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
281 dev += strlen(if_prefix);
284 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
285 dev += strlen(host_prefix);
291 switch(Curl_if2ip(af, scope, conn->scope_id, dev,
292 myhost, sizeof(myhost))) {
293 case IF2IP_NOT_FOUND:
295 /* Do not fall back to treating it as a host name */
296 failf(data, "Couldn't bind to interface '%s'", dev);
297 return CURLE_INTERFACE_FAILED;
300 case IF2IP_AF_NOT_SUPPORTED:
301 /* Signal the caller to try another address family if available */
302 return CURLE_UNSUPPORTED_PROTOCOL;
306 * We now have the numerical IP address in the 'myhost' buffer
308 infof(data, "Local Interface %s is ip %s using address family %i\n",
312 #ifdef SO_BINDTODEVICE
313 /* I am not sure any other OSs than Linux that provide this feature,
314 * and at the least I cannot test. --Ben
316 * This feature allows one to tightly bind the local socket to a
317 * particular interface. This will force even requests to other
318 * local interfaces to go out the external interface.
321 * Only bind to the interface when specified as interface, not just
322 * as a hostname or ip address.
324 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
325 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
327 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
328 " will do regular bind\n",
329 dev, error, Curl_strerror(conn, error));
330 /* This is typically "errno 1, error: Operation not permitted" if
331 you're not running as root or another suitable privileged
340 * This was not an interface, resolve the name as a host name
343 * Temporarily force name resolution to use only the address type
344 * of the connection. The resolve functions should really be changed
345 * to take a type parameter instead.
347 long ipver = conn->ip_version;
351 conn->ip_version = CURL_IPRESOLVE_V4;
353 else if(af == AF_INET6)
354 conn->ip_version = CURL_IPRESOLVE_V6;
357 rc = Curl_resolv(conn, dev, 0, &h);
358 if(rc == CURLRESOLV_PENDING)
359 (void)Curl_resolver_wait_resolv(conn, &h);
360 conn->ip_version = ipver;
363 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
364 Curl_printable_address(h->addr, myhost, sizeof(myhost));
365 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
366 dev, af, myhost, h->addr->ai_family);
367 Curl_resolv_unlock(data, h);
372 * provided dev was no interface (or interfaces are not supported
373 * e.g. solaris) no ip address and no domain we fail here
383 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
384 char *scope_ptr = strchr(myhost, '%');
388 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
389 si6->sin6_family = AF_INET6;
390 si6->sin6_port = htons(port);
391 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
393 /* The "myhost" string either comes from Curl_if2ip or from
394 Curl_printable_address. The latter returns only numeric scope
395 IDs and the former returns none at all. So the scope ID, if
396 present, is known to be numeric */
397 si6->sin6_scope_id = atoi(scope_ptr);
400 sizeof_sa = sizeof(struct sockaddr_in6);
405 if((af == AF_INET) &&
406 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
407 si4->sin_family = AF_INET;
408 si4->sin_port = htons(port);
409 sizeof_sa = sizeof(struct sockaddr_in);
414 failf(data, "Couldn't bind to '%s'", dev);
415 return CURLE_INTERFACE_FAILED;
419 /* no device was given, prepare sa to match af's needs */
422 si6->sin6_family = AF_INET6;
423 si6->sin6_port = htons(port);
424 sizeof_sa = sizeof(struct sockaddr_in6);
429 si4->sin_family = AF_INET;
430 si4->sin_port = htons(port);
431 sizeof_sa = sizeof(struct sockaddr_in);
436 if(bind(sockfd, sock, sizeof_sa) >= 0) {
437 /* we succeeded to bind */
438 struct Curl_sockaddr_storage add;
439 curl_socklen_t size = sizeof(add);
440 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
441 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
442 data->state.os_errno = error = SOCKERRNO;
443 failf(data, "getsockname() failed with errno %d: %s",
444 error, Curl_strerror(conn, error));
445 return CURLE_INTERFACE_FAILED;
447 infof(data, "Local port: %hu\n", port);
448 conn->bits.bound = TRUE;
453 infof(data, "Bind to local port %hu failed, trying next\n", port);
454 port++; /* try next port */
455 /* We re-use/clobber the port variable here below */
456 if(sock->sa_family == AF_INET)
457 si4->sin_port = ntohs(port);
460 si6->sin6_port = ntohs(port);
467 data->state.os_errno = error = SOCKERRNO;
468 failf(data, "bind failed with errno %d: %s",
469 error, Curl_strerror(conn, error));
471 return CURLE_INTERFACE_FAILED;
475 * verifyconnect() returns TRUE if the connect really has happened.
477 static bool verifyconnect(curl_socket_t sockfd, int *error)
482 curl_socklen_t errSize = sizeof(err);
486 * In October 2003 we effectively nullified this function on Windows due to
487 * problems with it using all CPU in multi-threaded cases.
489 * In May 2004, we bring it back to offer more info back on connect failures.
490 * Gisle Vanem could reproduce the former problems with this function, but
491 * could avoid them by adding this SleepEx() call below:
493 * "I don't have Rational Quantify, but the hint from his post was
494 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
495 * just Sleep(0) would be enough?) would release whatever
496 * mutex/critical-section the ntdll call is waiting on.
498 * Someone got to verify this on Win-NT 4.0, 2000."
509 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
512 /* Old WinCE versions don't support SO_ERROR */
513 if(WSAENOPROTOOPT == err) {
519 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
520 if(EBADIOCTL == err) {
525 if((0 == err) || (EISCONN == err))
526 /* we are connected, awesome! */
529 /* This wasn't a successful connect */
541 /* Used within the multi interface. Try next IP address, return TRUE if no
542 more address exists or error */
543 static CURLcode trynextip(struct connectdata *conn,
547 const int other = tempindex ^ 1;
548 CURLcode result = CURLE_COULDNT_CONNECT;
550 /* First clean up after the failed socket.
551 Don't close it yet to ensure that the next IP's socket gets a different
552 file descriptor, which can prevent bugs when the curl_multi_socket_action
553 interface is used with certain select() replacements such as kqueue. */
554 curl_socket_t fd_to_close = conn->tempsock[tempindex];
555 conn->tempsock[tempindex] = CURL_SOCKET_BAD;
557 if(sockindex == FIRSTSOCKET) {
558 Curl_addrinfo *ai = NULL;
559 int family = AF_UNSPEC;
561 if(conn->tempaddr[tempindex]) {
562 /* find next address in the same protocol family */
563 family = conn->tempaddr[tempindex]->ai_family;
564 ai = conn->tempaddr[tempindex]->ai_next;
567 else if(conn->tempaddr[0]) {
568 /* happy eyeballs - try the other protocol family */
569 int firstfamily = conn->tempaddr[0]->ai_family;
570 family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
571 ai = conn->tempaddr[0]->ai_next;
576 if(conn->tempaddr[other]) {
577 /* we can safely skip addresses of the other protocol family */
578 while(ai && ai->ai_family != family)
583 result = singleipconnect(conn, ai, &conn->tempsock[tempindex]);
584 if(result == CURLE_COULDNT_CONNECT) {
589 conn->tempaddr[tempindex] = ai;
595 if(fd_to_close != CURL_SOCKET_BAD)
596 Curl_closesocket(conn, fd_to_close);
601 /* Copies connection info into the session handle to make it available
602 when the session handle is no longer associated with a connection. */
603 void Curl_persistconninfo(struct connectdata *conn)
605 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
606 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
607 conn->data->info.conn_primary_port = conn->primary_port;
608 conn->data->info.conn_local_port = conn->local_port;
611 /* retrieves ip address and port from a sockaddr structure */
612 static bool getaddressinfo(struct sockaddr* sa, char* addr,
615 unsigned short us_port;
616 struct sockaddr_in* si = NULL;
618 struct sockaddr_in6* si6 = NULL;
620 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
621 struct sockaddr_un* su = NULL;
624 switch (sa->sa_family) {
626 si = (struct sockaddr_in*)(void*) sa;
627 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
628 addr, MAX_IPADR_LEN)) {
629 us_port = ntohs(si->sin_port);
636 si6 = (struct sockaddr_in6*)(void*) sa;
637 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
638 addr, MAX_IPADR_LEN)) {
639 us_port = ntohs(si6->sin6_port);
645 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
647 su = (struct sockaddr_un*)sa;
648 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
662 /* retrieves the start/end point information of a socket of an established
664 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
667 struct Curl_sockaddr_storage ssrem;
668 struct Curl_sockaddr_storage ssloc;
669 struct Curl_easy *data = conn->data;
671 if(conn->socktype == SOCK_DGRAM)
672 /* there's no connection! */
675 if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
678 len = sizeof(struct Curl_sockaddr_storage);
679 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
681 failf(data, "getpeername() failed with errno %d: %s",
682 error, Curl_strerror(conn, error));
686 len = sizeof(struct Curl_sockaddr_storage);
687 memset(&ssloc, 0, sizeof(ssloc));
688 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
690 failf(data, "getsockname() failed with errno %d: %s",
691 error, Curl_strerror(conn, error));
695 if(!getaddressinfo((struct sockaddr*)&ssrem,
696 conn->primary_ip, &conn->primary_port)) {
698 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
699 error, Curl_strerror(conn, error));
702 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
704 if(!getaddressinfo((struct sockaddr*)&ssloc,
705 conn->local_ip, &conn->local_port)) {
707 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
708 error, Curl_strerror(conn, error));
714 /* persist connection info in session handle */
715 Curl_persistconninfo(conn);
719 * Curl_is_connected() checks if the socket has connected.
722 CURLcode Curl_is_connected(struct connectdata *conn,
726 struct Curl_easy *data = conn->data;
727 CURLcode result = CURLE_OK;
734 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
736 *connected = FALSE; /* a very negative world view is best */
738 if(conn->bits.tcpconnect[sockindex]) {
739 /* we are connected already! */
746 /* figure out how long time we have left to connect */
747 allow = Curl_timeleft(data, &now, TRUE);
750 /* time-out, bail out, go home */
751 failf(data, "Connection time-out");
752 return CURLE_OPERATION_TIMEDOUT;
756 const int other = i ^ 1;
757 if(conn->tempsock[i] == CURL_SOCKET_BAD)
761 /* Call this function once now, and ignore the results. We do this to
762 "clear" the error state on the socket so that we can later read it
763 reliably. This is reported necessary on the MPE/iX operating system. */
764 (void)verifyconnect(conn->tempsock[i], NULL);
767 /* check socket for connect */
768 rc = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
770 if(rc == 0) { /* no connection yet */
772 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
773 infof(data, "After %ldms connect time, move on!\n",
774 conn->timeoutms_per_addr);
778 /* should we try another protocol family? */
779 if(i == 0 && conn->tempaddr[1] == NULL &&
780 curlx_tvdiff(now, conn->connecttime) >= HAPPY_EYEBALLS_TIMEOUT) {
781 trynextip(conn, sockindex, 1);
784 else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
785 if(verifyconnect(conn->tempsock[i], &error)) {
786 /* we are connected with TCP, awesome! */
788 /* use this socket from now on */
789 conn->sock[sockindex] = conn->tempsock[i];
790 conn->ip_addr = conn->tempaddr[i];
791 conn->tempsock[i] = CURL_SOCKET_BAD;
793 /* close the other socket, if open */
794 if(conn->tempsock[other] != CURL_SOCKET_BAD) {
795 Curl_closesocket(conn, conn->tempsock[other]);
796 conn->tempsock[other] = CURL_SOCKET_BAD;
799 /* see if we need to do any proxy magic first once we connected */
800 result = Curl_connected_proxy(conn, sockindex);
804 conn->bits.tcpconnect[sockindex] = TRUE;
807 if(sockindex == FIRSTSOCKET)
808 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
809 Curl_updateconninfo(conn, conn->sock[sockindex]);
810 Curl_verboseconnect(conn);
815 infof(data, "Connection failed\n");
817 else if(rc & CURL_CSELECT_ERR)
818 (void)verifyconnect(conn->tempsock[i], &error);
821 * The connection failed here, we should attempt to connect to the "next
822 * address" for the given host. But first remember the latest error.
825 data->state.os_errno = error;
826 SET_SOCKERRNO(error);
827 if(conn->tempaddr[i]) {
829 char ipaddress[MAX_IPADR_LEN];
830 Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
831 infof(data, "connect to %s port %ld failed: %s\n",
832 ipaddress, conn->port, Curl_strerror(conn, error));
834 conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
837 status = trynextip(conn, sockindex, i);
838 if(status != CURLE_COULDNT_CONNECT
839 || conn->tempsock[other] == CURL_SOCKET_BAD)
840 /* the last attempt failed and no other sockets remain open */
847 /* no more addresses to try */
849 const char* hostname;
851 /* if the first address family runs out of addresses to try before
852 the happy eyeball timeout, go ahead and try the next family now */
853 if(conn->tempaddr[1] == NULL) {
854 result = trynextip(conn, sockindex, 1);
860 hostname = conn->proxy.name;
861 else if(conn->bits.conn_to_host)
862 hostname = conn->conn_to_host.name;
864 hostname = conn->host.name;
866 failf(data, "Failed to connect to %s port %ld: %s",
867 hostname, conn->port, Curl_strerror(conn, error));
873 void Curl_tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
875 #if defined(TCP_NODELAY)
876 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
877 struct Curl_easy *data = conn->data;
879 curl_socklen_t onoff = (curl_socklen_t) 1;
880 int level = IPPROTO_TCP;
883 /* The use of getprotobyname() is disabled since it isn't thread-safe on
884 numerous systems. On these getprotobyname_r() should be used instead, but
885 that exists in at least one 4 arg version and one 5 arg version, and
886 since the proto number rarely changes anyway we now just use the hard
887 coded number. The "proper" fix would need a configure check for the
888 correct function much in the same style the gethostbyname_r versions are
890 struct protoent *pe = getprotobyname("tcp");
895 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
899 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
901 infof(data, "Could not set TCP_NODELAY: %s\n",
902 Curl_strerror(conn, SOCKERRNO));
904 infof(data, "TCP_NODELAY set\n");
912 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
913 sending data to a dead peer (instead of relying on the 4th argument to send
914 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
916 static void nosigpipe(struct connectdata *conn,
917 curl_socket_t sockfd)
919 struct Curl_easy *data= conn->data;
921 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
923 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
924 Curl_strerror(conn, SOCKERRNO));
927 #define nosigpipe(x,y) Curl_nop_stmt
931 /* When you run a program that uses the Windows Sockets API, you may
932 experience slow performance when you copy data to a TCP server.
934 https://support.microsoft.com/kb/823764
936 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
939 The problem described in this knowledge-base is applied only to pre-Vista
940 Windows. Following function trying to detect OS version and skips
941 SO_SNDBUF adjustment for Windows Vista and above.
943 #define DETECT_OS_NONE 0
944 #define DETECT_OS_PREVISTA 1
945 #define DETECT_OS_VISTA_OR_LATER 2
947 void Curl_sndbufset(curl_socket_t sockfd)
949 int val = CURL_MAX_WRITE_SIZE + 32;
951 int curlen = sizeof(curval);
953 static int detectOsState = DETECT_OS_NONE;
955 if(detectOsState == DETECT_OS_NONE) {
956 if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
957 VERSION_GREATER_THAN_EQUAL))
958 detectOsState = DETECT_OS_VISTA_OR_LATER;
960 detectOsState = DETECT_OS_PREVISTA;
963 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
966 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
970 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
977 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
978 * CURL_SOCKET_BAD. Other errors will however return proper errors.
980 * singleipconnect() connects to the given IP only, and it may return without
983 static CURLcode singleipconnect(struct connectdata *conn,
984 const Curl_addrinfo *ai,
985 curl_socket_t *sockp)
987 struct Curl_sockaddr_ex addr;
990 bool isconnected = FALSE;
991 struct Curl_easy *data = conn->data;
992 curl_socket_t sockfd;
994 char ipaddress[MAX_IPADR_LEN];
998 *sockp = CURL_SOCKET_BAD;
1000 result = Curl_socket(conn, ai, &addr, &sockfd);
1002 /* Failed to create the socket, but still return OK since we signal the
1003 lack of socket as well. This allows the parent function to keep looping
1004 over alternative addresses/socket families etc. */
1007 /* store remote address and port used in this connection attempt */
1008 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
1009 ipaddress, &port)) {
1010 /* malformed address or bug in inet_ntop, try next address */
1012 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
1013 error, Curl_strerror(conn, error));
1014 Curl_closesocket(conn, sockfd);
1017 infof(data, " Trying %s...\n", ipaddress);
1020 is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
1021 addr.socktype == SOCK_STREAM;
1023 is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
1025 if(is_tcp && data->set.tcp_nodelay)
1026 Curl_tcpnodelay(conn, sockfd);
1028 nosigpipe(conn, sockfd);
1030 Curl_sndbufset(sockfd);
1032 if(is_tcp && data->set.tcp_keepalive)
1033 tcpkeepalive(data, sockfd);
1035 if(data->set.fsockopt) {
1036 /* activate callback for setting socket options */
1037 error = data->set.fsockopt(data->set.sockopt_client,
1039 CURLSOCKTYPE_IPCXN);
1041 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1044 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
1045 return CURLE_ABORTED_BY_CALLBACK;
1049 /* possibly bind the local end to an IP, interface or port */
1050 if(addr.family == AF_INET
1052 || addr.family == AF_INET6
1055 result = bindlocal(conn, sockfd, addr.family,
1056 Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
1058 Curl_closesocket(conn, sockfd); /* close socket and bail out */
1059 if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1060 /* The address family is not supported on this interface.
1061 We can continue trying addresses */
1062 return CURLE_COULDNT_CONNECT;
1068 /* set socket non-blocking */
1069 (void)curlx_nonblock(sockfd, TRUE);
1071 conn->connecttime = Curl_tvnow();
1072 if(conn->num_addr > 1)
1073 Curl_expire_latest(data, conn->timeoutms_per_addr);
1075 /* Connect TCP sockets, bind UDP */
1076 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
1077 if(conn->bits.tcp_fastopen) {
1078 #if defined(CONNECT_DATA_IDEMPOTENT) /* OS X */
1079 sa_endpoints_t endpoints;
1080 endpoints.sae_srcif = 0;
1081 endpoints.sae_srcaddr = NULL;
1082 endpoints.sae_srcaddrlen = 0;
1083 endpoints.sae_dstaddr = &addr.sa_addr;
1084 endpoints.sae_dstaddrlen = addr.addrlen;
1086 rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
1087 CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1088 NULL, 0, NULL, NULL);
1089 #elif defined(MSG_FASTOPEN) /* Linux */
1090 if(conn->given->flags & PROTOPT_SSL)
1091 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1093 rc = 0; /* Do nothing */
1097 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1109 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
1117 #if (EAGAIN) != (EWOULDBLOCK)
1118 /* On some platforms EAGAIN and EWOULDBLOCK are the
1119 * same value, and on others they are different, hence
1129 /* unknown error, fallthrough and try another address! */
1130 infof(data, "Immediate connect fail for %s: %s\n",
1131 ipaddress, Curl_strerror(conn, error));
1132 data->state.os_errno = error;
1134 /* connect failed */
1135 Curl_closesocket(conn, sockfd);
1136 result = CURLE_COULDNT_CONNECT;
1147 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1148 * There might be more than one IP address to try out. Fill in the passed
1149 * pointer with the connected socket.
1152 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1153 const struct Curl_dns_entry *remotehost)
1155 struct Curl_easy *data = conn->data;
1156 struct timeval before = Curl_tvnow();
1157 CURLcode result = CURLE_COULDNT_CONNECT;
1159 long timeout_ms = Curl_timeleft(data, &before, TRUE);
1161 if(timeout_ms < 0) {
1162 /* a precaution, no need to continue if time already is up */
1163 failf(data, "Connection time-out");
1164 return CURLE_OPERATION_TIMEDOUT;
1167 conn->num_addr = Curl_num_addresses(remotehost->addr);
1168 conn->tempaddr[0] = remotehost->addr;
1169 conn->tempaddr[1] = NULL;
1170 conn->tempsock[0] = CURL_SOCKET_BAD;
1171 conn->tempsock[1] = CURL_SOCKET_BAD;
1172 Curl_expire(conn->data, HAPPY_EYEBALLS_TIMEOUT);
1174 /* Max time for the next connection attempt */
1175 conn->timeoutms_per_addr =
1176 conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
1178 /* start connecting to first IP */
1179 while(conn->tempaddr[0]) {
1180 result = singleipconnect(conn, conn->tempaddr[0], &(conn->tempsock[0]));
1183 conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
1186 if(conn->tempsock[0] == CURL_SOCKET_BAD) {
1188 result = CURLE_COULDNT_CONNECT;
1192 data->info.numconnects++; /* to track the number of connections made */
1198 struct connectdata *tofind;
1202 static int conn_is_conn(struct connectdata *conn, void *param)
1204 struct connfind *f = (struct connfind *)param;
1205 if(conn == f->tofind) {
1213 * Used to extract socket and connectdata struct for the most recent
1214 * transfer on the given Curl_easy.
1216 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1218 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
1219 struct connectdata **connp)
1221 curl_socket_t sockfd;
1225 /* this works for an easy handle:
1226 * - that has been used for curl_easy_perform()
1227 * - that is associated with a multi handle, and whose connection
1228 * was detached with CURLOPT_CONNECT_ONLY
1230 if(data->state.lastconnect && (data->multi_easy || data->multi)) {
1231 struct connectdata *c = data->state.lastconnect;
1232 struct connfind find;
1233 find.tofind = data->state.lastconnect;
1236 Curl_conncache_foreach(data->multi_easy?
1237 &data->multi_easy->conn_cache:
1238 &data->multi->conn_cache, &find, conn_is_conn);
1241 data->state.lastconnect = NULL;
1242 return CURL_SOCKET_BAD;
1246 /* only store this if the caller cares for it */
1248 sockfd = c->sock[FIRSTSOCKET];
1249 /* we have a socket connected, let's determine if the server shut down */
1250 /* determine if ssl */
1251 if(c->ssl[FIRSTSOCKET].use) {
1252 /* use the SSL context */
1253 if(!Curl_ssl_check_cxn(c))
1254 return CURL_SOCKET_BAD; /* FIN received */
1256 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1258 else if(sockfd != CURL_SOCKET_BAD) {
1259 /* use the socket */
1261 if(recv((RECV_TYPE_ARG1)sockfd, (RECV_TYPE_ARG2)&buf,
1262 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1263 return CURL_SOCKET_BAD; /* FIN received */
1269 return CURL_SOCKET_BAD;
1277 * 'conn' can be NULL, beware!
1279 int Curl_closesocket(struct connectdata *conn,
1282 if(conn && conn->fclosesocket) {
1283 if((sock == conn->sock[SECONDARYSOCKET]) &&
1284 conn->sock_accepted[SECONDARYSOCKET])
1285 /* if this socket matches the second socket, and that was created with
1286 accept, then we MUST NOT call the callback but clear the accepted
1288 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1290 Curl_multi_closed(conn, sock);
1291 return conn->fclosesocket(conn->closesocket_client, sock);
1296 /* tell the multi-socket code about this */
1297 Curl_multi_closed(conn, sock);
1305 * Create a socket based on info from 'conn' and 'ai'.
1307 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1308 * 'sockfd' must be a pointer to a socket descriptor.
1310 * If the open socket callback is set, used that!
1313 CURLcode Curl_socket(struct connectdata *conn,
1314 const Curl_addrinfo *ai,
1315 struct Curl_sockaddr_ex *addr,
1316 curl_socket_t *sockfd)
1318 struct Curl_easy *data = conn->data;
1319 struct Curl_sockaddr_ex dummy;
1322 /* if the caller doesn't want info back, use a local temp copy */
1326 * The Curl_sockaddr_ex structure is basically libcurl's external API
1327 * curl_sockaddr structure with enough space available to directly hold
1328 * any protocol-specific address structures. The variable declared here
1329 * will be used to pass / receive data to/from the fopensocket callback
1330 * if this has been set, before that, it is initialized from parameters.
1333 addr->family = ai->ai_family;
1334 addr->socktype = conn->socktype;
1335 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1336 addr->addrlen = ai->ai_addrlen;
1338 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1339 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1340 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1342 if(data->set.fopensocket)
1344 * If the opensocket callback is set, all the destination address
1345 * information is passed to the callback. Depending on this information the
1346 * callback may opt to abort the connection, this is indicated returning
1347 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1348 * the callback returns a valid socket the destination address information
1349 * might have been changed and this 'new' address will actually be used
1352 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1354 (struct curl_sockaddr *)addr);
1356 /* opensocket callback not set, so simply create the socket now */
1357 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1359 if(*sockfd == CURL_SOCKET_BAD)
1360 /* no socket, no connection */
1361 return CURLE_COULDNT_CONNECT;
1363 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1364 if(conn->scope_id && (addr->family == AF_INET6)) {
1365 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1366 sa6->sin6_scope_id = conn->scope_id;
1375 * Curl_conncontrol() marks streams or connection for closure.
1377 void Curl_conncontrol(struct connectdata *conn,
1378 int ctrl /* see defines in header */
1380 , const char *reason
1384 /* close if a connection, or a stream that isn't multiplexed */
1385 bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
1386 ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
1387 if((ctrl == CONNCTRL_STREAM) &&
1388 (conn->handler->flags & PROTOPT_STREAM))
1389 DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
1390 else if(closeit != conn->bits.close) {
1391 DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
1392 closeit?"closure":"keep alive", reason));
1393 conn->bits.close = closeit; /* the only place in the source code that
1394 should assign this bit */