1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, 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 http://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
59 #define _MPRINTF_REPLACE /* use our functions only */
60 #include <curl/mprintf.h>
67 #include "curl_memory.h"
69 #include "url.h" /* for Curl_safefree() */
71 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
72 #include "inet_ntop.h"
73 #include "inet_pton.h"
74 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
77 #include "conncache.h"
78 #include "multihandle.h"
80 /* The last #include file should be: */
84 /* This isn't actually supported under Symbian OS */
88 static bool verifyconnect(curl_socket_t sockfd, int *error);
90 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
91 /* DragonFlyBSD and Windows use millisecond units */
92 #define KEEPALIVE_FACTOR(x) (x *= 1000)
94 #define KEEPALIVE_FACTOR(x)
97 #if defined(HAVE_WINSOCK_H) && !defined(SIO_KEEPALIVE_VALS)
98 #define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
100 struct tcp_keepalive {
102 u_long keepalivetime;
103 u_long keepaliveinterval;
108 tcpkeepalive(struct SessionHandle *data,
109 curl_socket_t sockfd)
111 int optval = data->set.tcp_keepalive?1:0;
113 /* only set IDLE and INTVL if setting KEEPALIVE is successful */
114 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
115 (void *)&optval, sizeof(optval)) < 0) {
116 infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
119 #if defined(SIO_KEEPALIVE_VALS)
120 struct tcp_keepalive vals;
123 optval = curlx_sltosi(data->set.tcp_keepidle);
124 KEEPALIVE_FACTOR(optval);
125 vals.keepalivetime = optval;
126 optval = curlx_sltosi(data->set.tcp_keepintvl);
127 KEEPALIVE_FACTOR(optval);
128 vals.keepaliveinterval = optval;
129 if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
130 NULL, 0, &dummy, NULL, NULL) != 0) {
131 infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
132 (int)sockfd, WSAGetLastError());
136 optval = curlx_sltosi(data->set.tcp_keepidle);
137 KEEPALIVE_FACTOR(optval);
138 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
139 (void *)&optval, sizeof(optval)) < 0) {
140 infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
144 optval = curlx_sltosi(data->set.tcp_keepintvl);
145 KEEPALIVE_FACTOR(optval);
146 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
147 (void *)&optval, sizeof(optval)) < 0) {
148 infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
153 optval = curlx_sltosi(data->set.tcp_keepidle);
154 KEEPALIVE_FACTOR(optval);
155 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
156 (void *)&optval, sizeof(optval)) < 0) {
157 infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
165 singleipconnect(struct connectdata *conn,
166 const Curl_addrinfo *ai, /* start connecting to this */
171 * Curl_timeleft() returns the amount of milliseconds left allowed for the
172 * transfer/connection. If the value is negative, the timeout time has already
175 * The start time is stored in progress.t_startsingle - as set with
176 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
178 * If 'nowp' is non-NULL, it points to the current time.
179 * 'duringconnect' is FALSE if not during a connect, as then of course the
180 * connect timeout is not taken into account!
184 long Curl_timeleft(struct SessionHandle *data,
185 struct timeval *nowp,
189 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
192 /* if a timeout is set, use the most restrictive one */
194 if(data->set.timeout > 0)
196 if(duringconnect && (data->set.connecttimeout > 0))
199 switch (timeout_set) {
201 timeout_ms = data->set.timeout;
204 timeout_ms = data->set.connecttimeout;
207 if(data->set.timeout < data->set.connecttimeout)
208 timeout_ms = data->set.timeout;
210 timeout_ms = data->set.connecttimeout;
213 /* use the default */
215 /* if we're not during connect, there's no default timeout so if we're
216 at zero we better just return zero and not make it a negative number
227 /* subtract elapsed time */
228 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
230 /* avoid returning 0 as that means no timeout! */
237 * checkconnect() checks for a TCP connect on the given socket.
242 CHKCONN_SELECT_ERROR = -1,
243 CHKCONN_CONNECTED = 0,
245 CHKCONN_FDSET_ERROR = 2
248 static enum chkconn_t
249 checkconnect(curl_socket_t sockfd)
253 /* Call this function once now, and ignore the results. We do this to
254 "clear" the error state on the socket so that we can later read it
255 reliably. This is reported necessary on the MPE/iX operating system. */
256 (void)verifyconnect(sockfd, NULL);
259 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 0);
262 /* error, no connect here, try next */
263 return CHKCONN_SELECT_ERROR;
265 else if(rc & CURL_CSELECT_ERR)
266 /* error condition caught */
267 return CHKCONN_FDSET_ERROR;
270 return CHKCONN_CONNECTED;
275 static CURLcode bindlocal(struct connectdata *conn,
276 curl_socket_t sockfd, int af)
278 struct SessionHandle *data = conn->data;
280 struct Curl_sockaddr_storage sa;
281 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
282 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
283 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
285 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
288 struct Curl_dns_entry *h=NULL;
289 unsigned short port = data->set.localport; /* use this port number, 0 for
291 /* how many port numbers to try to bind to, increasing one at a time */
292 int portnum = data->set.localportrange;
293 const char *dev = data->set.str[STRING_DEVICE];
295 char myhost[256] = "";
296 int done = 0; /* -1 for error, 1 for address found */
297 bool is_interface = FALSE;
298 bool is_host = FALSE;
299 static const char *if_prefix = "if!";
300 static const char *host_prefix = "host!";
302 /*************************************************************
303 * Select device to bind socket to
304 *************************************************************/
306 /* no local kind of binding was requested */
309 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
311 if(dev && (strlen(dev)<255) ) {
312 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
313 dev += strlen(if_prefix);
316 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
317 dev += strlen(host_prefix);
323 switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) {
324 case IF2IP_NOT_FOUND:
326 /* Do not fall back to treating it as a host name */
327 failf(data, "Couldn't bind to interface '%s'", dev);
328 return CURLE_INTERFACE_FAILED;
331 case IF2IP_AF_NOT_SUPPORTED:
332 /* Signal the caller to try another address family if available */
333 return CURLE_UNSUPPORTED_PROTOCOL;
337 * We now have the numerical IP address in the 'myhost' buffer
339 infof(data, "Local Interface %s is ip %s using address family %i\n",
343 #ifdef SO_BINDTODEVICE
344 /* I am not sure any other OSs than Linux that provide this feature,
345 * and at the least I cannot test. --Ben
347 * This feature allows one to tightly bind the local socket to a
348 * particular interface. This will force even requests to other
349 * local interfaces to go out the external interface.
352 * Only bind to the interface when specified as interface, not just
353 * as a hostname or ip address.
355 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
356 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
358 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
359 " will do regular bind\n",
360 dev, error, Curl_strerror(conn, error));
361 /* This is typically "errno 1, error: Operation not permitted" if
362 you're not running as root or another suitable privileged
371 * This was not an interface, resolve the name as a host name
374 * Temporarily force name resolution to use only the address type
375 * of the connection. The resolve functions should really be changed
376 * to take a type parameter instead.
378 long ipver = conn->ip_version;
382 conn->ip_version = CURL_IPRESOLVE_V4;
384 else if(af == AF_INET6)
385 conn->ip_version = CURL_IPRESOLVE_V6;
388 rc = Curl_resolv(conn, dev, 0, &h);
389 if(rc == CURLRESOLV_PENDING)
390 (void)Curl_resolver_wait_resolv(conn, &h);
391 conn->ip_version = ipver;
394 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
395 Curl_printable_address(h->addr, myhost, sizeof(myhost));
396 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
397 dev, af, myhost, h->addr->ai_family);
398 Curl_resolv_unlock(data, h);
403 * provided dev was no interface (or interfaces are not supported
404 * e.g. solaris) no ip address and no domain we fail here
414 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
415 char *scope_ptr = strchr(myhost, '%');
419 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
420 si6->sin6_family = AF_INET6;
421 si6->sin6_port = htons(port);
422 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
424 /* The "myhost" string either comes from Curl_if2ip or from
425 Curl_printable_address. The latter returns only numeric scope
426 IDs and the former returns none at all. So the scope ID, if
427 present, is known to be numeric */
428 si6->sin6_scope_id = atoi(scope_ptr);
431 sizeof_sa = sizeof(struct sockaddr_in6);
436 if((af == AF_INET) &&
437 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
438 si4->sin_family = AF_INET;
439 si4->sin_port = htons(port);
440 sizeof_sa = sizeof(struct sockaddr_in);
445 failf(data, "Couldn't bind to '%s'", dev);
446 return CURLE_INTERFACE_FAILED;
450 /* no device was given, prepare sa to match af's needs */
453 si6->sin6_family = AF_INET6;
454 si6->sin6_port = htons(port);
455 sizeof_sa = sizeof(struct sockaddr_in6);
460 si4->sin_family = AF_INET;
461 si4->sin_port = htons(port);
462 sizeof_sa = sizeof(struct sockaddr_in);
467 if(bind(sockfd, sock, sizeof_sa) >= 0) {
468 /* we succeeded to bind */
469 struct Curl_sockaddr_storage add;
470 curl_socklen_t size = sizeof(add);
471 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
472 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
473 data->state.os_errno = error = SOCKERRNO;
474 failf(data, "getsockname() failed with errno %d: %s",
475 error, Curl_strerror(conn, error));
476 return CURLE_INTERFACE_FAILED;
478 infof(data, "Local port: %hu\n", port);
479 conn->bits.bound = TRUE;
484 infof(data, "Bind to local port %hu failed, trying next\n", port);
485 port++; /* try next port */
486 /* We re-use/clobber the port variable here below */
487 if(sock->sa_family == AF_INET)
488 si4->sin_port = ntohs(port);
491 si6->sin6_port = ntohs(port);
498 data->state.os_errno = error = SOCKERRNO;
499 failf(data, "bind failed with errno %d: %s",
500 error, Curl_strerror(conn, error));
502 return CURLE_INTERFACE_FAILED;
506 * verifyconnect() returns TRUE if the connect really has happened.
508 static bool verifyconnect(curl_socket_t sockfd, int *error)
513 curl_socklen_t errSize = sizeof(err);
517 * In October 2003 we effectively nullified this function on Windows due to
518 * problems with it using all CPU in multi-threaded cases.
520 * In May 2004, we bring it back to offer more info back on connect failures.
521 * Gisle Vanem could reproduce the former problems with this function, but
522 * could avoid them by adding this SleepEx() call below:
524 * "I don't have Rational Quantify, but the hint from his post was
525 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
526 * just Sleep(0) would be enough?) would release whatever
527 * mutex/critical-section the ntdll call is waiting on.
529 * Someone got to verify this on Win-NT 4.0, 2000."
540 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
543 /* Old WinCE versions don't support SO_ERROR */
544 if(WSAENOPROTOOPT == err) {
550 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
551 if(EBADIOCTL == err) {
556 if((0 == err) || (EISCONN == err))
557 /* we are connected, awesome! */
560 /* This wasn't a successful connect */
572 /* Used within the multi interface. Try next IP address, return TRUE if no
573 more address exists or error */
574 static CURLcode trynextip(struct connectdata *conn,
578 curl_socket_t sockfd;
581 /* First clean up after the failed socket.
582 Don't close it yet to ensure that the next IP's socket gets a different
583 file descriptor, which can prevent bugs when the curl_multi_socket_action
584 interface is used with certain select() replacements such as kqueue. */
585 curl_socket_t fd_to_close = conn->sock[sockindex];
586 conn->sock[sockindex] = CURL_SOCKET_BAD;
589 if(sockindex != FIRSTSOCKET) {
590 Curl_closesocket(conn, fd_to_close);
591 return CURLE_COULDNT_CONNECT; /* no next */
594 /* try the next address */
595 ai = conn->ip_addr->ai_next;
598 CURLcode res = singleipconnect(conn, ai, &sockfd, connected);
601 if(sockfd != CURL_SOCKET_BAD) {
602 /* store the new socket descriptor */
603 conn->sock[sockindex] = sockfd;
605 Curl_closesocket(conn, fd_to_close);
610 Curl_closesocket(conn, fd_to_close);
611 return CURLE_COULDNT_CONNECT;
614 /* Copies connection info into the session handle to make it available
615 when the session handle is no longer associated with a connection. */
616 void Curl_persistconninfo(struct connectdata *conn)
618 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
619 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
620 conn->data->info.conn_primary_port = conn->primary_port;
621 conn->data->info.conn_local_port = conn->local_port;
624 /* retrieves ip address and port from a sockaddr structure */
625 static bool getaddressinfo(struct sockaddr* sa, char* addr,
628 unsigned short us_port;
629 struct sockaddr_in* si = NULL;
631 struct sockaddr_in6* si6 = NULL;
633 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
634 struct sockaddr_un* su = NULL;
637 switch (sa->sa_family) {
639 si = (struct sockaddr_in*) sa;
640 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
641 addr, MAX_IPADR_LEN)) {
642 us_port = ntohs(si->sin_port);
649 si6 = (struct sockaddr_in6*)sa;
650 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
651 addr, MAX_IPADR_LEN)) {
652 us_port = ntohs(si6->sin6_port);
658 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
660 su = (struct sockaddr_un*)sa;
661 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
675 /* retrieves the start/end point information of a socket of an established
677 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
681 struct Curl_sockaddr_storage ssrem;
682 struct Curl_sockaddr_storage ssloc;
683 struct SessionHandle *data = conn->data;
685 if(!conn->bits.reuse) {
687 len = sizeof(struct Curl_sockaddr_storage);
688 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
690 failf(data, "getpeername() failed with errno %d: %s",
691 error, Curl_strerror(conn, error));
695 len = sizeof(struct Curl_sockaddr_storage);
696 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
698 failf(data, "getsockname() failed with errno %d: %s",
699 error, Curl_strerror(conn, error));
703 if(!getaddressinfo((struct sockaddr*)&ssrem,
704 conn->primary_ip, &conn->primary_port)) {
706 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
707 error, Curl_strerror(conn, error));
711 if(!getaddressinfo((struct sockaddr*)&ssloc,
712 conn->local_ip, &conn->local_port)) {
714 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
715 error, Curl_strerror(conn, error));
721 /* persist connection info in session handle */
722 Curl_persistconninfo(conn);
726 * Curl_is_connected() checks if the socket has connected.
729 CURLcode Curl_is_connected(struct connectdata *conn,
733 struct SessionHandle *data = conn->data;
734 CURLcode code = CURLE_OK;
735 curl_socket_t sockfd = conn->sock[sockindex];
736 long allow = DEFAULT_CONNECT_TIMEOUT;
741 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
743 *connected = FALSE; /* a very negative world view is best */
745 if(conn->bits.tcpconnect[sockindex]) {
746 /* we are connected already! */
753 /* figure out how long time we have left to connect */
754 allow = Curl_timeleft(data, &now, TRUE);
757 /* time-out, bail out, go home */
758 failf(data, "Connection time-out");
759 return CURLE_OPERATION_TIMEDOUT;
762 /* check socket for connect */
763 chk = checkconnect(sockfd);
764 if(CHKCONN_IDLE == chk) {
765 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
766 infof(data, "After %ldms connect time, move on!\n",
767 conn->timeoutms_per_addr);
771 /* not an error, but also no connection yet */
775 if(CHKCONN_CONNECTED == chk) {
776 if(verifyconnect(sockfd, &error)) {
777 /* we are connected with TCP, awesome! */
779 /* see if we need to do any proxy magic first once we connected */
780 code = Curl_connected_proxy(conn);
784 conn->bits.tcpconnect[sockindex] = TRUE;
787 if(sockindex == FIRSTSOCKET)
788 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
789 Curl_verboseconnect(conn);
790 Curl_updateconninfo(conn, sockfd);
794 /* nope, not connected for real */
797 /* nope, not connected */
798 if(CHKCONN_FDSET_ERROR == chk) {
799 (void)verifyconnect(sockfd, &error);
800 infof(data, "%s\n",Curl_strerror(conn, error));
803 infof(data, "Connection failed\n");
807 * The connection failed here, we should attempt to connect to the "next
808 * address" for the given host. But first remember the latest error.
811 data->state.os_errno = error;
812 SET_SOCKERRNO(error);
816 conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
818 code = trynextip(conn, sockindex, connected);
822 data->state.os_errno = error;
823 failf(data, "Failed connect to %s:%ld; %s",
824 conn->host.name, conn->port, Curl_strerror(conn, error));
830 static void tcpnodelay(struct connectdata *conn,
831 curl_socket_t sockfd)
834 struct SessionHandle *data= conn->data;
835 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
836 int level = IPPROTO_TCP;
839 /* The use of getprotobyname() is disabled since it isn't thread-safe on
840 numerous systems. On these getprotobyname_r() should be used instead, but
841 that exists in at least one 4 arg version and one 5 arg version, and
842 since the proto number rarely changes anyway we now just use the hard
843 coded number. The "proper" fix would need a configure check for the
844 correct function much in the same style the gethostbyname_r versions are
846 struct protoent *pe = getprotobyname("tcp");
851 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
853 infof(data, "Could not set TCP_NODELAY: %s\n",
854 Curl_strerror(conn, SOCKERRNO));
856 infof(data,"TCP_NODELAY set\n");
864 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
865 sending data to a dead peer (instead of relying on the 4th argument to send
866 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
868 static void nosigpipe(struct connectdata *conn,
869 curl_socket_t sockfd)
871 struct SessionHandle *data= conn->data;
873 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
875 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
876 Curl_strerror(conn, SOCKERRNO));
879 #define nosigpipe(x,y) Curl_nop_stmt
883 /* When you run a program that uses the Windows Sockets API, you may
884 experience slow performance when you copy data to a TCP server.
886 http://support.microsoft.com/kb/823764
888 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
891 The problem described in this knowledge-base is applied only to pre-Vista
892 Windows. Following function trying to detect OS version and skips
893 SO_SNDBUF adjustment for Windows Vista and above.
895 #define DETECT_OS_NONE 0
896 #define DETECT_OS_PREVISTA 1
897 #define DETECT_OS_VISTA_OR_LATER 2
899 void Curl_sndbufset(curl_socket_t sockfd)
901 int val = CURL_MAX_WRITE_SIZE + 32;
903 int curlen = sizeof(curval);
906 static int detectOsState = DETECT_OS_NONE;
908 if(detectOsState == DETECT_OS_NONE) {
909 memset(&osver, 0, sizeof(osver));
910 osver.dwOSVersionInfoSize = sizeof(osver);
911 detectOsState = DETECT_OS_PREVISTA;
912 if(GetVersionEx(&osver)) {
913 if(osver.dwMajorVersion >= 6)
914 detectOsState = DETECT_OS_VISTA_OR_LATER;
917 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
920 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
924 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
932 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
933 * CURL_SOCKET_BAD. Other errors will however return proper errors.
935 * singleipconnect() connects to the given IP only, and it may return without
939 singleipconnect(struct connectdata *conn,
940 const Curl_addrinfo *ai,
941 curl_socket_t *sockp,
944 struct Curl_sockaddr_ex addr;
947 bool isconnected = FALSE;
948 struct SessionHandle *data = conn->data;
949 curl_socket_t sockfd;
950 CURLcode res = CURLE_OK;
952 *sockp = CURL_SOCKET_BAD;
953 *connected = FALSE; /* default is not connected */
955 res = Curl_socket(conn, ai, &addr, &sockfd);
957 /* Failed to create the socket, but still return OK since we signal the
958 lack of socket as well. This allows the parent function to keep looping
959 over alternative addresses/socket families etc. */
962 /* store remote address and port used in this connection attempt */
963 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
964 conn->primary_ip, &conn->primary_port)) {
965 /* malformed address or bug in inet_ntop, try next address */
967 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
968 error, Curl_strerror(conn, error));
969 Curl_closesocket(conn, sockfd);
972 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
973 infof(data, " Trying %s...\n", conn->ip_addr_str);
975 Curl_persistconninfo(conn);
977 if(data->set.tcp_nodelay)
978 tcpnodelay(conn, sockfd);
980 nosigpipe(conn, sockfd);
982 Curl_sndbufset(sockfd);
984 if(data->set.tcp_keepalive)
985 tcpkeepalive(data, sockfd);
987 if(data->set.fsockopt) {
988 /* activate callback for setting socket options */
989 error = data->set.fsockopt(data->set.sockopt_client,
993 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
996 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
997 return CURLE_ABORTED_BY_CALLBACK;
1001 /* possibly bind the local end to an IP, interface or port */
1002 res = bindlocal(conn, sockfd, addr.family);
1004 Curl_closesocket(conn, sockfd); /* close socket and bail out */
1005 if(res == CURLE_UNSUPPORTED_PROTOCOL) {
1006 /* The address family is not supported on this interface.
1007 We can continue trying addresses */
1013 /* set socket non-blocking */
1014 curlx_nonblock(sockfd, TRUE);
1016 conn->connecttime = Curl_tvnow();
1017 if(conn->num_addr > 1)
1018 Curl_expire(data, conn->timeoutms_per_addr);
1020 /* Connect TCP sockets, bind UDP */
1021 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
1022 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1032 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
1040 #if (EAGAIN) != (EWOULDBLOCK)
1041 /* On some platforms EAGAIN and EWOULDBLOCK are the
1042 * same value, and on others they are different, hence
1052 /* unknown error, fallthrough and try another address! */
1053 failf(data, "Failed to connect to %s: %s",
1054 conn->ip_addr_str, Curl_strerror(conn,error));
1055 data->state.os_errno = error;
1057 /* connect failed */
1058 Curl_closesocket(conn, sockfd);
1070 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1071 * There might be more than one IP address to try out. Fill in the passed
1072 * pointer with the connected socket.
1075 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1076 const struct Curl_dns_entry *remotehost,
1077 curl_socket_t *sockconn, /* the connected socket */
1078 Curl_addrinfo **addr, /* the one we used */
1079 bool *connected) /* really connected? */
1081 struct SessionHandle *data = conn->data;
1082 curl_socket_t sockfd = CURL_SOCKET_BAD;
1084 Curl_addrinfo *curr_addr;
1086 struct timeval after;
1087 struct timeval before = Curl_tvnow();
1089 /*************************************************************
1090 * Figure out what maximum time we have left
1091 *************************************************************/
1094 DEBUGASSERT(sockconn);
1095 *connected = FALSE; /* default to not connected */
1097 /* get the timeout left */
1098 timeout_ms = Curl_timeleft(data, &before, TRUE);
1100 if(timeout_ms < 0) {
1101 /* a precaution, no need to continue if time already is up */
1102 failf(data, "Connection time-out");
1103 return CURLE_OPERATION_TIMEDOUT;
1106 conn->num_addr = Curl_num_addresses(remotehost->addr);
1108 ai = remotehost->addr;
1110 /* Below is the loop that attempts to connect to all IP-addresses we
1111 * know for the given host. One by one until one IP succeeds.
1115 * Connecting with a Curl_addrinfo chain
1117 for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
1120 /* Max time for the next address */
1121 conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
1122 timeout_ms : timeout_ms / 2;
1124 /* start connecting to the IP curr_addr points to */
1125 res = singleipconnect(conn, curr_addr,
1126 &sockfd, connected);
1130 if(sockfd != CURL_SOCKET_BAD)
1133 /* get a new timeout for next attempt */
1134 after = Curl_tvnow();
1135 timeout_ms -= Curl_tvdiff(after, before);
1136 if(timeout_ms < 0) {
1137 failf(data, "connect() timed out!");
1138 return CURLE_OPERATION_TIMEDOUT;
1141 } /* end of connect-to-each-address loop */
1143 *sockconn = sockfd; /* the socket descriptor we've connected */
1145 if(sockfd == CURL_SOCKET_BAD) {
1146 /* no good connect was made */
1147 failf(data, "couldn't connect to %s at %s:%ld",
1148 conn->bits.proxy?"proxy":"host",
1149 conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port);
1150 return CURLE_COULDNT_CONNECT;
1153 /* leave the socket in non-blocking mode */
1155 /* store the address we use */
1159 data->info.numconnects++; /* to track the number of connections made */
1165 struct connectdata *tofind;
1169 static int conn_is_conn(struct connectdata *conn, void *param)
1171 struct connfind *f = (struct connfind *)param;
1172 if(conn == f->tofind) {
1180 * Used to extract socket and connectdata struct for the most recent
1181 * transfer on the given SessionHandle.
1183 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1185 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1186 struct connectdata **connp)
1188 curl_socket_t sockfd;
1192 /* this only works for an easy handle that has been used for
1193 curl_easy_perform()! */
1194 if(data->state.lastconnect && data->multi_easy) {
1195 struct connectdata *c = data->state.lastconnect;
1196 struct connfind find;
1197 find.tofind = data->state.lastconnect;
1200 Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
1203 data->state.lastconnect = NULL;
1204 return CURL_SOCKET_BAD;
1208 /* only store this if the caller cares for it */
1210 sockfd = c->sock[FIRSTSOCKET];
1211 /* we have a socket connected, let's determine if the server shut down */
1212 /* determine if ssl */
1213 if(c->ssl[FIRSTSOCKET].use) {
1214 /* use the SSL context */
1215 if(!Curl_ssl_check_cxn(c))
1216 return CURL_SOCKET_BAD; /* FIN received */
1218 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1221 /* use the socket */
1223 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1224 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1225 return CURL_SOCKET_BAD; /* FIN received */
1231 return CURL_SOCKET_BAD;
1239 * 'conn' can be NULL, beware!
1241 int Curl_closesocket(struct connectdata *conn,
1244 if(conn && conn->fclosesocket) {
1245 if((sock == conn->sock[SECONDARYSOCKET]) &&
1246 conn->sock_accepted[SECONDARYSOCKET])
1247 /* if this socket matches the second socket, and that was created with
1248 accept, then we MUST NOT call the callback but clear the accepted
1250 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1252 return conn->fclosesocket(conn->closesocket_client, sock);
1257 /* tell the multi-socket code about this */
1258 Curl_multi_closed(conn, sock);
1264 * Create a socket based on info from 'conn' and 'ai'.
1266 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1267 * 'sockfd' must be a pointer to a socket descriptor.
1269 * If the open socket callback is set, used that!
1272 CURLcode Curl_socket(struct connectdata *conn,
1273 const Curl_addrinfo *ai,
1274 struct Curl_sockaddr_ex *addr,
1275 curl_socket_t *sockfd)
1277 struct SessionHandle *data = conn->data;
1278 struct Curl_sockaddr_ex dummy;
1281 /* if the caller doesn't want info back, use a local temp copy */
1285 * The Curl_sockaddr_ex structure is basically libcurl's external API
1286 * curl_sockaddr structure with enough space available to directly hold
1287 * any protocol-specific address structures. The variable declared here
1288 * will be used to pass / receive data to/from the fopensocket callback
1289 * if this has been set, before that, it is initialized from parameters.
1292 addr->family = ai->ai_family;
1293 addr->socktype = conn->socktype;
1294 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1295 addr->addrlen = ai->ai_addrlen;
1297 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1298 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1299 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1301 if(data->set.fopensocket)
1303 * If the opensocket callback is set, all the destination address
1304 * information is passed to the callback. Depending on this information the
1305 * callback may opt to abort the connection, this is indicated returning
1306 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1307 * the callback returns a valid socket the destination address information
1308 * might have been changed and this 'new' address will actually be used
1311 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1313 (struct curl_sockaddr *)addr);
1315 /* opensocket callback not set, so simply create the socket now */
1316 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1318 if(*sockfd == CURL_SOCKET_BAD)
1319 /* no socket, no connection */
1320 return CURLE_COULDNT_CONNECT;
1322 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1323 if(conn->scope && (addr->family == AF_INET6)) {
1324 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1325 sa6->sin6_scope_id = conn->scope;