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);
91 /* DragonFlyBSD uses millisecond as KEEPIDLE and KEEPINTVL units */
92 #define KEEPALIVE_FACTOR(x) (x *= 1000)
94 #define KEEPALIVE_FACTOR(x)
98 tcpkeepalive(struct SessionHandle *data,
101 int optval = data->set.tcp_keepalive?1:0;
103 /* only set IDLE and INTVL if setting KEEPALIVE is successful */
104 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
105 (void *)&optval, sizeof(optval)) < 0) {
106 infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
110 optval = curlx_sltosi(data->set.tcp_keepidle);
111 KEEPALIVE_FACTOR(optval);
112 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
113 (void *)&optval, sizeof(optval)) < 0) {
114 infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
118 optval = curlx_sltosi(data->set.tcp_keepintvl);
119 KEEPALIVE_FACTOR(optval);
120 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
121 (void *)&optval, sizeof(optval)) < 0) {
122 infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
129 singleipconnect(struct connectdata *conn,
130 const Curl_addrinfo *ai, /* start connecting to this */
135 * Curl_timeleft() returns the amount of milliseconds left allowed for the
136 * transfer/connection. If the value is negative, the timeout time has already
139 * The start time is stored in progress.t_startsingle - as set with
140 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
142 * If 'nowp' is non-NULL, it points to the current time.
143 * 'duringconnect' is FALSE if not during a connect, as then of course the
144 * connect timeout is not taken into account!
148 long Curl_timeleft(struct SessionHandle *data,
149 struct timeval *nowp,
153 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
156 /* if a timeout is set, use the most restrictive one */
158 if(data->set.timeout > 0)
160 if(duringconnect && (data->set.connecttimeout > 0))
163 switch (timeout_set) {
165 timeout_ms = data->set.timeout;
168 timeout_ms = data->set.connecttimeout;
171 if(data->set.timeout < data->set.connecttimeout)
172 timeout_ms = data->set.timeout;
174 timeout_ms = data->set.connecttimeout;
177 /* use the default */
179 /* if we're not during connect, there's no default timeout so if we're
180 at zero we better just return zero and not make it a negative number
191 /* subtract elapsed time */
192 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
194 /* avoid returning 0 as that means no timeout! */
201 * checkconnect() checks for a TCP connect on the given socket.
206 CHKCONN_SELECT_ERROR = -1,
207 CHKCONN_CONNECTED = 0,
209 CHKCONN_FDSET_ERROR = 2
212 static enum chkconn_t
213 checkconnect(curl_socket_t sockfd)
217 /* Call this function once now, and ignore the results. We do this to
218 "clear" the error state on the socket so that we can later read it
219 reliably. This is reported necessary on the MPE/iX operating system. */
220 (void)verifyconnect(sockfd, NULL);
223 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 0);
226 /* error, no connect here, try next */
227 return CHKCONN_SELECT_ERROR;
229 else if(rc & CURL_CSELECT_ERR)
230 /* error condition caught */
231 return CHKCONN_FDSET_ERROR;
234 return CHKCONN_CONNECTED;
239 static CURLcode bindlocal(struct connectdata *conn,
240 curl_socket_t sockfd, int af)
242 struct SessionHandle *data = conn->data;
244 struct Curl_sockaddr_storage sa;
245 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
246 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
247 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
249 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
252 struct Curl_dns_entry *h=NULL;
253 unsigned short port = data->set.localport; /* use this port number, 0 for
255 /* how many port numbers to try to bind to, increasing one at a time */
256 int portnum = data->set.localportrange;
257 const char *dev = data->set.str[STRING_DEVICE];
259 char myhost[256] = "";
260 int done = 0; /* -1 for error, 1 for address found */
261 bool is_interface = FALSE;
262 bool is_host = FALSE;
263 static const char *if_prefix = "if!";
264 static const char *host_prefix = "host!";
266 /*************************************************************
267 * Select device to bind socket to
268 *************************************************************/
270 /* no local kind of binding was requested */
273 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
275 if(dev && (strlen(dev)<255) ) {
276 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
277 dev += strlen(if_prefix);
280 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
281 dev += strlen(host_prefix);
286 if(!is_host && (is_interface || Curl_if_is_interface_name(dev))) {
287 if(Curl_if2ip(af, dev, myhost, sizeof(myhost)) == NULL)
288 return CURLE_INTERFACE_FAILED;
291 * We now have the numerical IP address in the 'myhost' buffer
293 infof(data, "Local Interface %s is ip %s using address family %i\n",
297 #ifdef SO_BINDTODEVICE
298 /* I am not sure any other OSs than Linux that provide this feature, and
299 * at the least I cannot test. --Ben
301 * This feature allows one to tightly bind the local socket to a
302 * particular interface. This will force even requests to other local
303 * interfaces to go out the external interface.
306 * Only bind to the interface when specified as interface, not just as a
307 * hostname or ip address.
309 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
310 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
312 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
313 " will do regular bind\n",
314 dev, error, Curl_strerror(conn, error));
315 /* This is typically "errno 1, error: Operation not permitted" if
316 you're not running as root or another suitable privileged user */
322 * This was not an interface, resolve the name as a host name
325 * Temporarily force name resolution to use only the address type
326 * of the connection. The resolve functions should really be changed
327 * to take a type parameter instead.
329 long ipver = conn->ip_version;
333 conn->ip_version = CURL_IPRESOLVE_V4;
335 else if(af == AF_INET6)
336 conn->ip_version = CURL_IPRESOLVE_V6;
339 rc = Curl_resolv(conn, dev, 0, &h);
340 if(rc == CURLRESOLV_PENDING)
341 (void)Curl_resolver_wait_resolv(conn, &h);
342 conn->ip_version = ipver;
345 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
346 Curl_printable_address(h->addr, myhost, sizeof(myhost));
347 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
348 dev, af, myhost, h->addr->ai_family);
349 Curl_resolv_unlock(data, h);
354 * provided dev was no interface (or interfaces are not supported
355 * e.g. solaris) no ip address and no domain we fail here
364 if((af == AF_INET6) &&
365 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
366 si6->sin6_family = AF_INET6;
367 si6->sin6_port = htons(port);
368 sizeof_sa = sizeof(struct sockaddr_in6);
373 if((af == AF_INET) &&
374 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
375 si4->sin_family = AF_INET;
376 si4->sin_port = htons(port);
377 sizeof_sa = sizeof(struct sockaddr_in);
382 failf(data, "Couldn't bind to '%s'", dev);
383 return CURLE_INTERFACE_FAILED;
387 /* no device was given, prepare sa to match af's needs */
390 si6->sin6_family = AF_INET6;
391 si6->sin6_port = htons(port);
392 sizeof_sa = sizeof(struct sockaddr_in6);
397 si4->sin_family = AF_INET;
398 si4->sin_port = htons(port);
399 sizeof_sa = sizeof(struct sockaddr_in);
404 if(bind(sockfd, sock, sizeof_sa) >= 0) {
405 /* we succeeded to bind */
406 struct Curl_sockaddr_storage add;
407 curl_socklen_t size = sizeof(add);
408 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
409 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
410 data->state.os_errno = error = SOCKERRNO;
411 failf(data, "getsockname() failed with errno %d: %s",
412 error, Curl_strerror(conn, error));
413 return CURLE_INTERFACE_FAILED;
415 infof(data, "Local port: %hu\n", port);
416 conn->bits.bound = TRUE;
421 infof(data, "Bind to local port %hu failed, trying next\n", port);
422 port++; /* try next port */
423 /* We re-use/clobber the port variable here below */
424 if(sock->sa_family == AF_INET)
425 si4->sin_port = ntohs(port);
428 si6->sin6_port = ntohs(port);
435 data->state.os_errno = error = SOCKERRNO;
436 failf(data, "bind failed with errno %d: %s",
437 error, Curl_strerror(conn, error));
439 return CURLE_INTERFACE_FAILED;
443 * verifyconnect() returns TRUE if the connect really has happened.
445 static bool verifyconnect(curl_socket_t sockfd, int *error)
450 curl_socklen_t errSize = sizeof(err);
454 * In October 2003 we effectively nullified this function on Windows due to
455 * problems with it using all CPU in multi-threaded cases.
457 * In May 2004, we bring it back to offer more info back on connect failures.
458 * Gisle Vanem could reproduce the former problems with this function, but
459 * could avoid them by adding this SleepEx() call below:
461 * "I don't have Rational Quantify, but the hint from his post was
462 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
463 * just Sleep(0) would be enough?) would release whatever
464 * mutex/critical-section the ntdll call is waiting on.
466 * Someone got to verify this on Win-NT 4.0, 2000."
477 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
480 /* Old WinCE versions don't support SO_ERROR */
481 if(WSAENOPROTOOPT == err) {
487 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
488 if(EBADIOCTL == err) {
493 if((0 == err) || (EISCONN == err))
494 /* we are connected, awesome! */
497 /* This wasn't a successful connect */
509 /* Used within the multi interface. Try next IP address, return TRUE if no
510 more address exists or error */
511 static CURLcode trynextip(struct connectdata *conn,
515 curl_socket_t sockfd;
518 /* First clean up after the failed socket.
519 Don't close it yet to ensure that the next IP's socket gets a different
520 file descriptor, which can prevent bugs when the curl_multi_socket_action
521 interface is used with certain select() replacements such as kqueue. */
522 curl_socket_t fd_to_close = conn->sock[sockindex];
523 conn->sock[sockindex] = CURL_SOCKET_BAD;
526 if(sockindex != FIRSTSOCKET) {
527 Curl_closesocket(conn, fd_to_close);
528 return CURLE_COULDNT_CONNECT; /* no next */
531 /* try the next address */
532 ai = conn->ip_addr->ai_next;
535 CURLcode res = singleipconnect(conn, ai, &sockfd, connected);
538 if(sockfd != CURL_SOCKET_BAD) {
539 /* store the new socket descriptor */
540 conn->sock[sockindex] = sockfd;
542 Curl_closesocket(conn, fd_to_close);
547 Curl_closesocket(conn, fd_to_close);
548 return CURLE_COULDNT_CONNECT;
551 /* Copies connection info into the session handle to make it available
552 when the session handle is no longer associated with a connection. */
553 void Curl_persistconninfo(struct connectdata *conn)
555 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
556 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
557 conn->data->info.conn_primary_port = conn->primary_port;
558 conn->data->info.conn_local_port = conn->local_port;
561 /* retrieves ip address and port from a sockaddr structure */
562 static bool getaddressinfo(struct sockaddr* sa, char* addr,
565 unsigned short us_port;
566 struct sockaddr_in* si = NULL;
568 struct sockaddr_in6* si6 = NULL;
570 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
571 struct sockaddr_un* su = NULL;
574 switch (sa->sa_family) {
576 si = (struct sockaddr_in*) sa;
577 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
578 addr, MAX_IPADR_LEN)) {
579 us_port = ntohs(si->sin_port);
586 si6 = (struct sockaddr_in6*)sa;
587 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
588 addr, MAX_IPADR_LEN)) {
589 us_port = ntohs(si6->sin6_port);
595 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
597 su = (struct sockaddr_un*)sa;
598 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
612 /* retrieves the start/end point information of a socket of an established
614 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
618 struct Curl_sockaddr_storage ssrem;
619 struct Curl_sockaddr_storage ssloc;
620 struct SessionHandle *data = conn->data;
622 if(!conn->bits.reuse) {
624 len = sizeof(struct Curl_sockaddr_storage);
625 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
627 failf(data, "getpeername() failed with errno %d: %s",
628 error, Curl_strerror(conn, error));
632 len = sizeof(struct Curl_sockaddr_storage);
633 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
635 failf(data, "getsockname() failed with errno %d: %s",
636 error, Curl_strerror(conn, error));
640 if(!getaddressinfo((struct sockaddr*)&ssrem,
641 conn->primary_ip, &conn->primary_port)) {
643 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
644 error, Curl_strerror(conn, error));
648 if(!getaddressinfo((struct sockaddr*)&ssloc,
649 conn->local_ip, &conn->local_port)) {
651 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
652 error, Curl_strerror(conn, error));
658 /* persist connection info in session handle */
659 Curl_persistconninfo(conn);
663 * Curl_is_connected() checks if the socket has connected.
666 CURLcode Curl_is_connected(struct connectdata *conn,
670 struct SessionHandle *data = conn->data;
671 CURLcode code = CURLE_OK;
672 curl_socket_t sockfd = conn->sock[sockindex];
673 long allow = DEFAULT_CONNECT_TIMEOUT;
678 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
680 *connected = FALSE; /* a very negative world view is best */
682 if(conn->bits.tcpconnect[sockindex]) {
683 /* we are connected already! */
690 /* figure out how long time we have left to connect */
691 allow = Curl_timeleft(data, &now, TRUE);
694 /* time-out, bail out, go home */
695 failf(data, "Connection time-out");
696 return CURLE_OPERATION_TIMEDOUT;
699 /* check socket for connect */
700 chk = checkconnect(sockfd);
701 if(CHKCONN_IDLE == chk) {
702 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
703 infof(data, "After %ldms connect time, move on!\n",
704 conn->timeoutms_per_addr);
708 /* not an error, but also no connection yet */
712 if(CHKCONN_CONNECTED == chk) {
713 if(verifyconnect(sockfd, &error)) {
714 /* we are connected with TCP, awesome! */
716 /* see if we need to do any proxy magic first once we connected */
717 code = Curl_connected_proxy(conn);
721 conn->bits.tcpconnect[sockindex] = TRUE;
724 if(sockindex == FIRSTSOCKET)
725 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
726 Curl_verboseconnect(conn);
727 Curl_updateconninfo(conn, sockfd);
731 /* nope, not connected for real */
734 /* nope, not connected */
735 if(CHKCONN_FDSET_ERROR == chk) {
736 (void)verifyconnect(sockfd, &error);
737 infof(data, "%s\n",Curl_strerror(conn, error));
740 infof(data, "Connection failed\n");
744 * The connection failed here, we should attempt to connect to the "next
745 * address" for the given host. But first remember the latest error.
748 data->state.os_errno = error;
749 SET_SOCKERRNO(error);
753 conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
755 code = trynextip(conn, sockindex, connected);
759 data->state.os_errno = error;
760 failf(data, "Failed connect to %s:%ld; %s",
761 conn->host.name, conn->port, Curl_strerror(conn, error));
767 static void tcpnodelay(struct connectdata *conn,
768 curl_socket_t sockfd)
771 struct SessionHandle *data= conn->data;
772 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
773 int level = IPPROTO_TCP;
776 /* The use of getprotobyname() is disabled since it isn't thread-safe on
777 numerous systems. On these getprotobyname_r() should be used instead, but
778 that exists in at least one 4 arg version and one 5 arg version, and
779 since the proto number rarely changes anyway we now just use the hard
780 coded number. The "proper" fix would need a configure check for the
781 correct function much in the same style the gethostbyname_r versions are
783 struct protoent *pe = getprotobyname("tcp");
788 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
790 infof(data, "Could not set TCP_NODELAY: %s\n",
791 Curl_strerror(conn, SOCKERRNO));
793 infof(data,"TCP_NODELAY set\n");
801 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
802 sending data to a dead peer (instead of relying on the 4th argument to send
803 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
805 static void nosigpipe(struct connectdata *conn,
806 curl_socket_t sockfd)
808 struct SessionHandle *data= conn->data;
810 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
812 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
813 Curl_strerror(conn, SOCKERRNO));
816 #define nosigpipe(x,y) Curl_nop_stmt
820 /* When you run a program that uses the Windows Sockets API, you may
821 experience slow performance when you copy data to a TCP server.
823 http://support.microsoft.com/kb/823764
825 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
829 void Curl_sndbufset(curl_socket_t sockfd)
831 int val = CURL_MAX_WRITE_SIZE + 32;
833 int curlen = sizeof(curval);
835 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
839 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
847 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
848 * CURL_SOCKET_BAD. Other errors will however return proper errors.
850 * singleipconnect() connects to the given IP only, and it may return without
854 singleipconnect(struct connectdata *conn,
855 const Curl_addrinfo *ai,
856 curl_socket_t *sockp,
859 struct Curl_sockaddr_ex addr;
862 bool isconnected = FALSE;
863 struct SessionHandle *data = conn->data;
864 curl_socket_t sockfd;
865 CURLcode res = CURLE_OK;
867 *sockp = CURL_SOCKET_BAD;
868 *connected = FALSE; /* default is not connected */
870 res = Curl_socket(conn, ai, &addr, &sockfd);
872 /* Failed to create the socket, but still return OK since we signal the
873 lack of socket as well. This allows the parent function to keep looping
874 over alternative addresses/socket families etc. */
877 /* store remote address and port used in this connection attempt */
878 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
879 conn->primary_ip, &conn->primary_port)) {
880 /* malformed address or bug in inet_ntop, try next address */
882 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
883 error, Curl_strerror(conn, error));
884 Curl_closesocket(conn, sockfd);
887 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
888 infof(data, " Trying %s...\n", conn->ip_addr_str);
890 Curl_persistconninfo(conn);
892 if(data->set.tcp_nodelay)
893 tcpnodelay(conn, sockfd);
895 nosigpipe(conn, sockfd);
897 Curl_sndbufset(sockfd);
899 if(data->set.tcp_keepalive)
900 tcpkeepalive(data, sockfd);
902 if(data->set.fsockopt) {
903 /* activate callback for setting socket options */
904 error = data->set.fsockopt(data->set.sockopt_client,
908 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
911 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
912 return CURLE_ABORTED_BY_CALLBACK;
916 /* possibly bind the local end to an IP, interface or port */
917 res = bindlocal(conn, sockfd, addr.family);
919 Curl_closesocket(conn, sockfd); /* close socket and bail out */
923 /* set socket non-blocking */
924 curlx_nonblock(sockfd, TRUE);
926 conn->connecttime = Curl_tvnow();
927 if(conn->num_addr > 1)
928 Curl_expire(data, conn->timeoutms_per_addr);
930 /* Connect TCP sockets, bind UDP */
931 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
932 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
943 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
951 #if (EAGAIN) != (EWOULDBLOCK)
952 /* On some platforms EAGAIN and EWOULDBLOCK are the
953 * same value, and on others they are different, hence
963 /* unknown error, fallthrough and try another address! */
964 failf(data, "Failed to connect to %s: %s",
965 conn->ip_addr_str, Curl_strerror(conn,error));
966 data->state.os_errno = error;
969 Curl_closesocket(conn, sockfd);
979 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
980 * There might be more than one IP address to try out. Fill in the passed
981 * pointer with the connected socket.
984 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
985 const struct Curl_dns_entry *remotehost,
986 curl_socket_t *sockconn, /* the connected socket */
987 Curl_addrinfo **addr, /* the one we used */
988 bool *connected) /* really connected? */
990 struct SessionHandle *data = conn->data;
991 curl_socket_t sockfd = CURL_SOCKET_BAD;
993 Curl_addrinfo *curr_addr;
995 struct timeval after;
996 struct timeval before = Curl_tvnow();
998 /*************************************************************
999 * Figure out what maximum time we have left
1000 *************************************************************/
1003 DEBUGASSERT(sockconn);
1004 *connected = FALSE; /* default to not connected */
1006 /* get the timeout left */
1007 timeout_ms = Curl_timeleft(data, &before, TRUE);
1009 if(timeout_ms < 0) {
1010 /* a precaution, no need to continue if time already is up */
1011 failf(data, "Connection time-out");
1012 return CURLE_OPERATION_TIMEDOUT;
1015 conn->num_addr = Curl_num_addresses(remotehost->addr);
1017 ai = remotehost->addr;
1019 /* Below is the loop that attempts to connect to all IP-addresses we
1020 * know for the given host. One by one until one IP succeeds.
1024 * Connecting with a Curl_addrinfo chain
1026 for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
1029 /* Max time for the next address */
1030 conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
1031 timeout_ms : timeout_ms / 2;
1033 /* start connecting to the IP curr_addr points to */
1034 res = singleipconnect(conn, curr_addr,
1035 &sockfd, connected);
1039 if(sockfd != CURL_SOCKET_BAD)
1042 /* get a new timeout for next attempt */
1043 after = Curl_tvnow();
1044 timeout_ms -= Curl_tvdiff(after, before);
1045 if(timeout_ms < 0) {
1046 failf(data, "connect() timed out!");
1047 return CURLE_OPERATION_TIMEDOUT;
1050 } /* end of connect-to-each-address loop */
1052 *sockconn = sockfd; /* the socket descriptor we've connected */
1054 if(sockfd == CURL_SOCKET_BAD) {
1055 /* no good connect was made */
1056 failf(data, "couldn't connect to %s at %s:%d",
1057 conn->bits.proxy?"proxy":"host",
1058 conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port);
1059 return CURLE_COULDNT_CONNECT;
1062 /* leave the socket in non-blocking mode */
1064 /* store the address we use */
1068 data->info.numconnects++; /* to track the number of connections made */
1074 struct connectdata *tofind;
1078 static int conn_is_conn(struct connectdata *conn, void *param)
1080 struct connfind *f = (struct connfind *)param;
1081 if(conn == f->tofind) {
1089 * Used to extract socket and connectdata struct for the most recent
1090 * transfer on the given SessionHandle.
1092 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1094 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1095 struct connectdata **connp)
1097 curl_socket_t sockfd;
1101 /* this only works for an easy handle that has been used for
1102 curl_easy_perform()! */
1103 if(data->state.lastconnect && data->multi_easy) {
1104 struct connectdata *c = data->state.lastconnect;
1105 struct connfind find;
1106 find.tofind = data->state.lastconnect;
1109 Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
1112 data->state.lastconnect = NULL;
1113 return CURL_SOCKET_BAD;
1117 /* only store this if the caller cares for it */
1119 sockfd = c->sock[FIRSTSOCKET];
1120 /* we have a socket connected, let's determine if the server shut down */
1121 /* determine if ssl */
1122 if(c->ssl[FIRSTSOCKET].use) {
1123 /* use the SSL context */
1124 if(!Curl_ssl_check_cxn(c))
1125 return CURL_SOCKET_BAD; /* FIN received */
1127 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1130 /* use the socket */
1132 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1133 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1134 return CURL_SOCKET_BAD; /* FIN received */
1140 return CURL_SOCKET_BAD;
1148 * 'conn' can be NULL, beware!
1150 int Curl_closesocket(struct connectdata *conn,
1153 if(conn && conn->fclosesocket) {
1154 if((sock == conn->sock[SECONDARYSOCKET]) &&
1155 conn->sock_accepted[SECONDARYSOCKET])
1156 /* if this socket matches the second socket, and that was created with
1157 accept, then we MUST NOT call the callback but clear the accepted
1159 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1161 return conn->fclosesocket(conn->closesocket_client, sock);
1163 return sclose(sock);
1167 * Create a socket based on info from 'conn' and 'ai'.
1169 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1170 * 'sockfd' must be a pointer to a socket descriptor.
1172 * If the open socket callback is set, used that!
1175 CURLcode Curl_socket(struct connectdata *conn,
1176 const Curl_addrinfo *ai,
1177 struct Curl_sockaddr_ex *addr,
1178 curl_socket_t *sockfd)
1180 struct SessionHandle *data = conn->data;
1181 struct Curl_sockaddr_ex dummy;
1184 /* if the caller doesn't want info back, use a local temp copy */
1188 * The Curl_sockaddr_ex structure is basically libcurl's external API
1189 * curl_sockaddr structure with enough space available to directly hold
1190 * any protocol-specific address structures. The variable declared here
1191 * will be used to pass / receive data to/from the fopensocket callback
1192 * if this has been set, before that, it is initialized from parameters.
1195 addr->family = ai->ai_family;
1196 addr->socktype = conn->socktype;
1197 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1198 addr->addrlen = ai->ai_addrlen;
1200 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1201 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1202 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1204 if(data->set.fopensocket)
1206 * If the opensocket callback is set, all the destination address
1207 * information is passed to the callback. Depending on this information the
1208 * callback may opt to abort the connection, this is indicated returning
1209 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1210 * the callback returns a valid socket the destination address information
1211 * might have been changed and this 'new' address will actually be used
1214 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1216 (struct curl_sockaddr *)addr);
1218 /* opensocket callback not set, so simply create the socket now */
1219 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1221 if(*sockfd == CURL_SOCKET_BAD)
1222 /* no socket, no connection */
1223 return CURLE_COULDNT_CONNECT;
1225 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1226 if(conn->scope && (addr->family == AF_INET6)) {
1227 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1228 sa6->sin6_scope_id = conn->scope;