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! */
236 static CURLcode bindlocal(struct connectdata *conn,
237 curl_socket_t sockfd, int af)
239 struct SessionHandle *data = conn->data;
241 struct Curl_sockaddr_storage sa;
242 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
243 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
244 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
246 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
249 struct Curl_dns_entry *h=NULL;
250 unsigned short port = data->set.localport; /* use this port number, 0 for
252 /* how many port numbers to try to bind to, increasing one at a time */
253 int portnum = data->set.localportrange;
254 const char *dev = data->set.str[STRING_DEVICE];
256 char myhost[256] = "";
257 int done = 0; /* -1 for error, 1 for address found */
258 bool is_interface = FALSE;
259 bool is_host = FALSE;
260 static const char *if_prefix = "if!";
261 static const char *host_prefix = "host!";
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 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
274 dev += strlen(if_prefix);
277 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
278 dev += strlen(host_prefix);
284 switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) {
285 case IF2IP_NOT_FOUND:
287 /* Do not fall back to treating it as a host name */
288 failf(data, "Couldn't bind to interface '%s'", dev);
289 return CURLE_INTERFACE_FAILED;
292 case IF2IP_AF_NOT_SUPPORTED:
293 /* Signal the caller to try another address family if available */
294 return CURLE_UNSUPPORTED_PROTOCOL;
298 * We now have the numerical IP address in the 'myhost' buffer
300 infof(data, "Local Interface %s is ip %s using address family %i\n",
304 #ifdef SO_BINDTODEVICE
305 /* I am not sure any other OSs than Linux that provide this feature,
306 * and at the least I cannot test. --Ben
308 * This feature allows one to tightly bind the local socket to a
309 * particular interface. This will force even requests to other
310 * local interfaces to go out the external interface.
313 * Only bind to the interface when specified as interface, not just
314 * as a hostname or ip address.
316 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
317 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
319 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
320 " will do regular bind\n",
321 dev, error, Curl_strerror(conn, error));
322 /* This is typically "errno 1, error: Operation not permitted" if
323 you're not running as root or another suitable privileged
332 * This was not an interface, resolve the name as a host name
335 * Temporarily force name resolution to use only the address type
336 * of the connection. The resolve functions should really be changed
337 * to take a type parameter instead.
339 long ipver = conn->ip_version;
343 conn->ip_version = CURL_IPRESOLVE_V4;
345 else if(af == AF_INET6)
346 conn->ip_version = CURL_IPRESOLVE_V6;
349 rc = Curl_resolv(conn, dev, 0, &h);
350 if(rc == CURLRESOLV_PENDING)
351 (void)Curl_resolver_wait_resolv(conn, &h);
352 conn->ip_version = ipver;
355 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
356 Curl_printable_address(h->addr, myhost, sizeof(myhost));
357 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
358 dev, af, myhost, h->addr->ai_family);
359 Curl_resolv_unlock(data, h);
364 * provided dev was no interface (or interfaces are not supported
365 * e.g. solaris) no ip address and no domain we fail here
375 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
376 char *scope_ptr = strchr(myhost, '%');
380 if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
381 si6->sin6_family = AF_INET6;
382 si6->sin6_port = htons(port);
383 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
385 /* The "myhost" string either comes from Curl_if2ip or from
386 Curl_printable_address. The latter returns only numeric scope
387 IDs and the former returns none at all. So the scope ID, if
388 present, is known to be numeric */
389 si6->sin6_scope_id = atoi(scope_ptr);
392 sizeof_sa = sizeof(struct sockaddr_in6);
397 if((af == AF_INET) &&
398 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
399 si4->sin_family = AF_INET;
400 si4->sin_port = htons(port);
401 sizeof_sa = sizeof(struct sockaddr_in);
406 failf(data, "Couldn't bind to '%s'", dev);
407 return CURLE_INTERFACE_FAILED;
411 /* no device was given, prepare sa to match af's needs */
414 si6->sin6_family = AF_INET6;
415 si6->sin6_port = htons(port);
416 sizeof_sa = sizeof(struct sockaddr_in6);
421 si4->sin_family = AF_INET;
422 si4->sin_port = htons(port);
423 sizeof_sa = sizeof(struct sockaddr_in);
428 if(bind(sockfd, sock, sizeof_sa) >= 0) {
429 /* we succeeded to bind */
430 struct Curl_sockaddr_storage add;
431 curl_socklen_t size = sizeof(add);
432 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
433 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
434 data->state.os_errno = error = SOCKERRNO;
435 failf(data, "getsockname() failed with errno %d: %s",
436 error, Curl_strerror(conn, error));
437 return CURLE_INTERFACE_FAILED;
439 infof(data, "Local port: %hu\n", port);
440 conn->bits.bound = TRUE;
445 infof(data, "Bind to local port %hu failed, trying next\n", port);
446 port++; /* try next port */
447 /* We re-use/clobber the port variable here below */
448 if(sock->sa_family == AF_INET)
449 si4->sin_port = ntohs(port);
452 si6->sin6_port = ntohs(port);
459 data->state.os_errno = error = SOCKERRNO;
460 failf(data, "bind failed with errno %d: %s",
461 error, Curl_strerror(conn, error));
463 return CURLE_INTERFACE_FAILED;
467 * verifyconnect() returns TRUE if the connect really has happened.
469 static bool verifyconnect(curl_socket_t sockfd, int *error)
474 curl_socklen_t errSize = sizeof(err);
478 * In October 2003 we effectively nullified this function on Windows due to
479 * problems with it using all CPU in multi-threaded cases.
481 * In May 2004, we bring it back to offer more info back on connect failures.
482 * Gisle Vanem could reproduce the former problems with this function, but
483 * could avoid them by adding this SleepEx() call below:
485 * "I don't have Rational Quantify, but the hint from his post was
486 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
487 * just Sleep(0) would be enough?) would release whatever
488 * mutex/critical-section the ntdll call is waiting on.
490 * Someone got to verify this on Win-NT 4.0, 2000."
501 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
504 /* Old WinCE versions don't support SO_ERROR */
505 if(WSAENOPROTOOPT == err) {
511 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
512 if(EBADIOCTL == err) {
517 if((0 == err) || (EISCONN == err))
518 /* we are connected, awesome! */
521 /* This wasn't a successful connect */
533 /* Used within the multi interface. Try next IP address, return TRUE if no
534 more address exists or error */
535 static CURLcode trynextip(struct connectdata *conn,
540 curl_socket_t sockfd;
542 int family = tempindex ? AF_INET6 : AF_INET;
544 /* First clean up after the failed socket.
545 Don't close it yet to ensure that the next IP's socket gets a different
546 file descriptor, which can prevent bugs when the curl_multi_socket_action
547 interface is used with certain select() replacements such as kqueue. */
548 curl_socket_t fd_to_close = conn->tempsock[tempindex];
549 conn->tempsock[tempindex] = CURL_SOCKET_BAD;
552 if(sockindex != FIRSTSOCKET) {
553 Curl_closesocket(conn, fd_to_close);
554 return CURLE_COULDNT_CONNECT; /* no next */
557 /* try the next address with same family */
558 ai = conn->tempaddr[tempindex]->ai_next;
559 while(ai && ai->ai_family != family)
562 while(ai && ai->ai_family == family) {
563 CURLcode res = singleipconnect(conn, ai, &sockfd, connected);
566 if(sockfd != CURL_SOCKET_BAD) {
567 /* store the new socket descriptor */
568 conn->tempsock[tempindex] = sockfd;
569 conn->tempaddr[tempindex] = ai;
570 Curl_closesocket(conn, fd_to_close);
576 } while(ai && ai->ai_family != family);
578 Curl_closesocket(conn, fd_to_close);
579 return CURLE_COULDNT_CONNECT;
582 /* Copies connection info into the session handle to make it available
583 when the session handle is no longer associated with a connection. */
584 void Curl_persistconninfo(struct connectdata *conn)
586 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
587 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
588 conn->data->info.conn_primary_port = conn->primary_port;
589 conn->data->info.conn_local_port = conn->local_port;
592 /* retrieves ip address and port from a sockaddr structure */
593 static bool getaddressinfo(struct sockaddr* sa, char* addr,
596 unsigned short us_port;
597 struct sockaddr_in* si = NULL;
599 struct sockaddr_in6* si6 = NULL;
601 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
602 struct sockaddr_un* su = NULL;
605 switch (sa->sa_family) {
607 si = (struct sockaddr_in*) sa;
608 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
609 addr, MAX_IPADR_LEN)) {
610 us_port = ntohs(si->sin_port);
617 si6 = (struct sockaddr_in6*)sa;
618 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
619 addr, MAX_IPADR_LEN)) {
620 us_port = ntohs(si6->sin6_port);
626 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
628 su = (struct sockaddr_un*)sa;
629 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
643 /* retrieves the start/end point information of a socket of an established
645 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
649 struct Curl_sockaddr_storage ssrem;
650 struct Curl_sockaddr_storage ssloc;
651 struct SessionHandle *data = conn->data;
653 if(!conn->bits.reuse) {
655 len = sizeof(struct Curl_sockaddr_storage);
656 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
658 failf(data, "getpeername() failed with errno %d: %s",
659 error, Curl_strerror(conn, error));
663 len = sizeof(struct Curl_sockaddr_storage);
664 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
666 failf(data, "getsockname() failed with errno %d: %s",
667 error, Curl_strerror(conn, error));
671 if(!getaddressinfo((struct sockaddr*)&ssrem,
672 conn->primary_ip, &conn->primary_port)) {
674 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
675 error, Curl_strerror(conn, error));
678 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
680 if(!getaddressinfo((struct sockaddr*)&ssloc,
681 conn->local_ip, &conn->local_port)) {
683 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
684 error, Curl_strerror(conn, error));
690 /* persist connection info in session handle */
691 Curl_persistconninfo(conn);
695 * Curl_is_connected() checks if the socket has connected.
698 CURLcode Curl_is_connected(struct connectdata *conn,
702 struct SessionHandle *data = conn->data;
703 CURLcode code = CURLE_OK;
704 long allow = DEFAULT_CONNECT_TIMEOUT;
710 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
712 *connected = FALSE; /* a very negative world view is best */
714 if(conn->bits.tcpconnect[sockindex]) {
715 /* we are connected already! */
722 /* figure out how long time we have left to connect */
723 allow = Curl_timeleft(data, &now, TRUE);
726 /* time-out, bail out, go home */
727 failf(data, "Connection time-out");
728 return CURLE_OPERATION_TIMEDOUT;
732 if(conn->tempsock[i] == CURL_SOCKET_BAD)
736 /* Call this function once now, and ignore the results. We do this to
737 "clear" the error state on the socket so that we can later read it
738 reliably. This is reported necessary on the MPE/iX operating system. */
739 (void)verifyconnect(conn->tempsock[i], NULL);
742 /* check socket for connect */
743 result = Curl_socket_ready(CURL_SOCKET_BAD, conn->tempsock[i], 0);
745 if(result == 0) { /* no connection yet */
746 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
747 infof(data, "After %ldms connect time, move on!\n",
748 conn->timeoutms_per_addr);
752 else if(result == CURL_CSELECT_OUT) {
753 if(verifyconnect(conn->tempsock[i], &error)) {
754 /* we are connected with TCP, awesome! */
757 /* use this socket from now on */
758 conn->sock[sockindex] = conn->tempsock[i];
759 conn->ip_addr = conn->tempaddr[i];
761 /* close the other socket, if open */
762 if(conn->tempsock[other] != CURL_SOCKET_BAD) {
763 if(conn->fclosesocket)
764 conn->fclosesocket(conn->closesocket_client,
765 conn->tempsock[other]);
767 sclose(conn->tempsock[other]);
770 /* see if we need to do any proxy magic first once we connected */
771 code = Curl_connected_proxy(conn, sockindex);
775 conn->bits.tcpconnect[sockindex] = TRUE;
778 if(sockindex == FIRSTSOCKET)
779 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
780 Curl_updateconninfo(conn, conn->sock[sockindex]);
781 Curl_verboseconnect(conn);
786 infof(data, "Connection failed\n");
788 else if((result & CURL_CSELECT_ERR) == CURL_CSELECT_ERR)
789 (void)verifyconnect(conn->tempsock[i], &error);
792 * The connection failed here, we should attempt to connect to the "next
793 * address" for the given host. But first remember the latest error.
796 char ipaddress[MAX_IPADR_LEN];
797 data->state.os_errno = error;
798 SET_SOCKERRNO(error);
799 Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
800 infof(data, "connect to %s port %ld: %s\n",
801 ipaddress, conn->port, Curl_strerror(conn, error));
803 conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
806 code = trynextip(conn, sockindex, i, connected);
811 /* no more addresses to try */
812 failf(data, "Failed to connect to %s port %ld: %s",
813 conn->host.name, conn->port, Curl_strerror(conn, error));
819 static void tcpnodelay(struct connectdata *conn,
820 curl_socket_t sockfd)
823 struct SessionHandle *data= conn->data;
824 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
825 int level = IPPROTO_TCP;
828 /* The use of getprotobyname() is disabled since it isn't thread-safe on
829 numerous systems. On these getprotobyname_r() should be used instead, but
830 that exists in at least one 4 arg version and one 5 arg version, and
831 since the proto number rarely changes anyway we now just use the hard
832 coded number. The "proper" fix would need a configure check for the
833 correct function much in the same style the gethostbyname_r versions are
835 struct protoent *pe = getprotobyname("tcp");
840 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
842 infof(data, "Could not set TCP_NODELAY: %s\n",
843 Curl_strerror(conn, SOCKERRNO));
845 infof(data,"TCP_NODELAY set\n");
853 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
854 sending data to a dead peer (instead of relying on the 4th argument to send
855 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
857 static void nosigpipe(struct connectdata *conn,
858 curl_socket_t sockfd)
860 struct SessionHandle *data= conn->data;
862 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
864 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
865 Curl_strerror(conn, SOCKERRNO));
868 #define nosigpipe(x,y) Curl_nop_stmt
872 /* When you run a program that uses the Windows Sockets API, you may
873 experience slow performance when you copy data to a TCP server.
875 http://support.microsoft.com/kb/823764
877 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
880 The problem described in this knowledge-base is applied only to pre-Vista
881 Windows. Following function trying to detect OS version and skips
882 SO_SNDBUF adjustment for Windows Vista and above.
884 #define DETECT_OS_NONE 0
885 #define DETECT_OS_PREVISTA 1
886 #define DETECT_OS_VISTA_OR_LATER 2
888 void Curl_sndbufset(curl_socket_t sockfd)
890 int val = CURL_MAX_WRITE_SIZE + 32;
892 int curlen = sizeof(curval);
895 static int detectOsState = DETECT_OS_NONE;
897 if(detectOsState == DETECT_OS_NONE) {
898 memset(&osver, 0, sizeof(osver));
899 osver.dwOSVersionInfoSize = sizeof(osver);
900 detectOsState = DETECT_OS_PREVISTA;
901 if(GetVersionEx(&osver)) {
902 if(osver.dwMajorVersion >= 6)
903 detectOsState = DETECT_OS_VISTA_OR_LATER;
906 if(detectOsState == DETECT_OS_VISTA_OR_LATER)
909 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
913 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
921 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
922 * CURL_SOCKET_BAD. Other errors will however return proper errors.
924 * singleipconnect() connects to the given IP only, and it may return without
928 singleipconnect(struct connectdata *conn,
929 const Curl_addrinfo *ai,
930 curl_socket_t *sockp,
933 struct Curl_sockaddr_ex addr;
936 bool isconnected = FALSE;
937 struct SessionHandle *data = conn->data;
938 curl_socket_t sockfd;
939 CURLcode res = CURLE_OK;
940 char ipaddress[MAX_IPADR_LEN];
943 *sockp = CURL_SOCKET_BAD;
944 *connected = FALSE; /* default is not connected */
946 res = Curl_socket(conn, ai, &addr, &sockfd);
948 /* Failed to create the socket, but still return OK since we signal the
949 lack of socket as well. This allows the parent function to keep looping
950 over alternative addresses/socket families etc. */
953 /* store remote address and port used in this connection attempt */
954 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
956 /* malformed address or bug in inet_ntop, try next address */
958 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
959 error, Curl_strerror(conn, error));
960 Curl_closesocket(conn, sockfd);
963 infof(data, " Trying %s...\n", ipaddress);
965 if(data->set.tcp_nodelay)
966 tcpnodelay(conn, sockfd);
968 nosigpipe(conn, sockfd);
970 Curl_sndbufset(sockfd);
972 if(data->set.tcp_keepalive)
973 tcpkeepalive(data, sockfd);
975 if(data->set.fsockopt) {
976 /* activate callback for setting socket options */
977 error = data->set.fsockopt(data->set.sockopt_client,
981 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
984 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
985 return CURLE_ABORTED_BY_CALLBACK;
989 /* possibly bind the local end to an IP, interface or port */
990 res = bindlocal(conn, sockfd, addr.family);
992 Curl_closesocket(conn, sockfd); /* close socket and bail out */
993 if(res == CURLE_UNSUPPORTED_PROTOCOL) {
994 /* The address family is not supported on this interface.
995 We can continue trying addresses */
1001 /* set socket non-blocking */
1002 curlx_nonblock(sockfd, TRUE);
1004 conn->connecttime = Curl_tvnow();
1005 if(conn->num_addr > 1)
1006 Curl_expire(data, conn->timeoutms_per_addr);
1008 /* Connect TCP sockets, bind UDP */
1009 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
1010 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1020 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
1028 #if (EAGAIN) != (EWOULDBLOCK)
1029 /* On some platforms EAGAIN and EWOULDBLOCK are the
1030 * same value, and on others they are different, hence
1040 /* unknown error, fallthrough and try another address! */
1041 failf(data, "Failed to connect to %s: %s",
1042 conn->ip_addr_str, Curl_strerror(conn,error));
1043 data->state.os_errno = error;
1045 /* connect failed */
1046 Curl_closesocket(conn, sockfd);
1058 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1059 * There might be more than one IP address to try out. Fill in the passed
1060 * pointer with the connected socket.
1063 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1064 const struct Curl_dns_entry *remotehost,
1065 bool *connected) /* really connected? */
1067 struct SessionHandle *data = conn->data;
1068 struct timeval after;
1069 struct timeval before = Curl_tvnow();
1072 /*************************************************************
1073 * Figure out what maximum time we have left
1074 *************************************************************/
1077 *connected = FALSE; /* default to not connected */
1079 /* get the timeout left */
1080 timeout_ms = Curl_timeleft(data, &before, TRUE);
1082 if(timeout_ms < 0) {
1083 /* a precaution, no need to continue if time already is up */
1084 failf(data, "Connection time-out");
1085 return CURLE_OPERATION_TIMEDOUT;
1088 conn->num_addr = Curl_num_addresses(remotehost->addr);
1089 conn->tempaddr[0] = remotehost->addr;
1090 conn->tempaddr[1] = remotehost->addr;
1092 /* Below is the loop that attempts to connect to all IP-addresses we
1093 * know for the given host.
1094 * One by one, for each protocol, until one IP succeeds.
1097 for(i=0; i<2; i++) {
1098 curl_socket_t sockfd = CURL_SOCKET_BAD;
1099 Curl_addrinfo *ai = conn->tempaddr[i];
1100 int family = i ? AF_INET6 : AF_INET;
1102 /* find first address for this address family, if any */
1103 while(ai && ai->ai_family != family)
1107 * Connecting with a Curl_addrinfo chain
1112 /* Max time for the next connection attempt */
1113 conn->timeoutms_per_addr = ai->ai_next == NULL ?
1114 timeout_ms : timeout_ms / 2;
1116 /* start connecting to the IP curr_addr points to */
1117 res = singleipconnect(conn, ai, &sockfd, connected);
1121 if(sockfd != CURL_SOCKET_BAD)
1124 /* get a new timeout for next attempt */
1125 after = Curl_tvnow();
1126 timeout_ms -= Curl_tvdiff(after, before);
1127 if(timeout_ms < 0) {
1128 failf(data, "connect() timed out!");
1129 return CURLE_OPERATION_TIMEDOUT;
1133 /* next addresses */
1136 } while(ai && ai->ai_family != family);
1137 } /* end of connect-to-each-address loop */
1139 conn->tempsock[i] = sockfd;
1140 conn->tempaddr[i] = ai;
1143 if((conn->tempsock[0] == CURL_SOCKET_BAD) &&
1144 (conn->tempsock[1] == CURL_SOCKET_BAD)) {
1145 /* no good connect was made */
1146 failf(data, "couldn't connect to %s at %s:%ld",
1147 conn->bits.proxy?"proxy":"host",
1148 conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port);
1149 return CURLE_COULDNT_CONNECT;
1152 /* leave the socket in non-blocking mode */
1154 data->info.numconnects++; /* to track the number of connections made */
1160 struct connectdata *tofind;
1164 static int conn_is_conn(struct connectdata *conn, void *param)
1166 struct connfind *f = (struct connfind *)param;
1167 if(conn == f->tofind) {
1175 * Used to extract socket and connectdata struct for the most recent
1176 * transfer on the given SessionHandle.
1178 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1180 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1181 struct connectdata **connp)
1183 curl_socket_t sockfd;
1187 /* this only works for an easy handle that has been used for
1188 curl_easy_perform()! */
1189 if(data->state.lastconnect && data->multi_easy) {
1190 struct connectdata *c = data->state.lastconnect;
1191 struct connfind find;
1192 find.tofind = data->state.lastconnect;
1195 Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
1198 data->state.lastconnect = NULL;
1199 return CURL_SOCKET_BAD;
1203 /* only store this if the caller cares for it */
1205 sockfd = c->sock[FIRSTSOCKET];
1206 /* we have a socket connected, let's determine if the server shut down */
1207 /* determine if ssl */
1208 if(c->ssl[FIRSTSOCKET].use) {
1209 /* use the SSL context */
1210 if(!Curl_ssl_check_cxn(c))
1211 return CURL_SOCKET_BAD; /* FIN received */
1213 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1216 /* use the socket */
1218 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1219 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1220 return CURL_SOCKET_BAD; /* FIN received */
1226 return CURL_SOCKET_BAD;
1234 * 'conn' can be NULL, beware!
1236 int Curl_closesocket(struct connectdata *conn,
1239 if(conn && conn->fclosesocket) {
1240 if((sock == conn->sock[SECONDARYSOCKET]) &&
1241 conn->sock_accepted[SECONDARYSOCKET])
1242 /* if this socket matches the second socket, and that was created with
1243 accept, then we MUST NOT call the callback but clear the accepted
1245 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1247 return conn->fclosesocket(conn->closesocket_client, sock);
1252 /* tell the multi-socket code about this */
1253 Curl_multi_closed(conn, sock);
1259 * Create a socket based on info from 'conn' and 'ai'.
1261 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1262 * 'sockfd' must be a pointer to a socket descriptor.
1264 * If the open socket callback is set, used that!
1267 CURLcode Curl_socket(struct connectdata *conn,
1268 const Curl_addrinfo *ai,
1269 struct Curl_sockaddr_ex *addr,
1270 curl_socket_t *sockfd)
1272 struct SessionHandle *data = conn->data;
1273 struct Curl_sockaddr_ex dummy;
1276 /* if the caller doesn't want info back, use a local temp copy */
1280 * The Curl_sockaddr_ex structure is basically libcurl's external API
1281 * curl_sockaddr structure with enough space available to directly hold
1282 * any protocol-specific address structures. The variable declared here
1283 * will be used to pass / receive data to/from the fopensocket callback
1284 * if this has been set, before that, it is initialized from parameters.
1287 addr->family = ai->ai_family;
1288 addr->socktype = conn->socktype;
1289 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1290 addr->addrlen = ai->ai_addrlen;
1292 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1293 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1294 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1296 if(data->set.fopensocket)
1298 * If the opensocket callback is set, all the destination address
1299 * information is passed to the callback. Depending on this information the
1300 * callback may opt to abort the connection, this is indicated returning
1301 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1302 * the callback returns a valid socket the destination address information
1303 * might have been changed and this 'new' address will actually be used
1306 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1308 (struct curl_sockaddr *)addr);
1310 /* opensocket callback not set, so simply create the socket now */
1311 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1313 if(*sockfd == CURL_SOCKET_BAD)
1314 /* no socket, no connection */
1315 return CURLE_COULDNT_CONNECT;
1317 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1318 if(conn->scope && (addr->family == AF_INET6)) {
1319 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1320 sa6->sin6_scope_id = conn->scope;