1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, 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 ***************************************************************************/
25 #ifdef HAVE_SYS_TIME_H
28 #ifdef HAVE_SYS_SOCKET_H
29 #include <sys/socket.h>
31 #ifdef HAVE_NETINET_IN_H
32 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
35 #include <sys/un.h> /* for sockaddr_un */
37 #ifdef HAVE_NETINET_TCP_H
38 #include <netinet/tcp.h> /* for TCP_NODELAY */
40 #ifdef HAVE_SYS_IOCTL_H
41 #include <sys/ioctl.h>
52 #ifdef HAVE_ARPA_INET_H
53 #include <arpa/inet.h>
59 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
60 #include <sys/filio.h>
64 #define in_addr_t unsigned long
75 #define _MPRINTF_REPLACE /* use our functions only */
76 #include <curl/mprintf.h>
83 #include "curl_memory.h"
85 #include "url.h" /* for Curl_safefree() */
87 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
88 #include "inet_ntop.h"
89 #include "inet_pton.h"
90 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
93 /* The last #include file should be: */
97 /* This isn't actually supported under Symbian OS */
101 struct Curl_sockaddr_ex {
105 unsigned int addrlen;
107 struct sockaddr addr;
108 struct Curl_sockaddr_storage buff;
111 #define sa_addr _sa_ex_u.addr
113 static bool verifyconnect(curl_socket_t sockfd, int *error);
116 singleipconnect(struct connectdata *conn,
117 const Curl_addrinfo *ai, /* start connecting to this */
123 * Curl_timeleft() returns the amount of milliseconds left allowed for the
124 * transfer/connection. If the value is negative, the timeout time has already
127 * If 'nowp' is non-NULL, it points to the current time.
128 * 'duringconnect' is FALSE if not during a connect, as then of course the
129 * connect timeout is not taken into account!
131 long Curl_timeleft(struct connectdata *conn,
132 struct timeval *nowp,
135 struct SessionHandle *data = conn->data;
137 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
140 /* if a timeout is set, use the most restrictive one */
142 if(data->set.timeout > 0)
144 if(duringconnect && (data->set.connecttimeout > 0))
147 switch (timeout_set) {
149 timeout_ms = data->set.timeout;
152 timeout_ms = data->set.connecttimeout;
155 if(data->set.timeout < data->set.connecttimeout)
156 timeout_ms = data->set.timeout;
158 timeout_ms = data->set.connecttimeout;
161 /* use the default */
163 /* if we're not during connect, there's no default timeout so if we're
164 at zero we better just return zero and not make it a negative number
175 /* substract elapsed time */
176 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
178 /* avoid returning 0 as that means no timeout! */
185 * waitconnect() waits for a TCP connect on the given socket for the specified
186 * number if milliseconds. It returns:
189 #define WAITCONN_CONNECTED 0
190 #define WAITCONN_SELECT_ERROR -1
191 #define WAITCONN_TIMEOUT 1
192 #define WAITCONN_FDSET_ERROR 2
193 #define WAITCONN_ABORTED 3
196 int waitconnect(struct connectdata *conn,
197 curl_socket_t sockfd, /* socket */
202 /* Call this function once now, and ignore the results. We do this to
203 "clear" the error state on the socket so that we can later read it
204 reliably. This is reported necessary on the MPE/iX operating system. */
205 (void)verifyconnect(sockfd, NULL);
210 /* now select() until we get connect or timeout */
211 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)(timeout_msec>1000?
213 if(Curl_pgrsUpdate(conn))
214 return WAITCONN_ABORTED;
217 /* error, no connect here, try next */
218 return WAITCONN_SELECT_ERROR;
222 timeout_msec -= 1000;
223 if(timeout_msec <= 0)
224 return WAITCONN_TIMEOUT;
229 if(rc & CURL_CSELECT_ERR)
230 /* error condition caught */
231 return WAITCONN_FDSET_ERROR;
235 return WAITCONN_CONNECTED;
238 static CURLcode bindlocal(struct connectdata *conn,
239 curl_socket_t sockfd, int af)
241 struct SessionHandle *data = conn->data;
243 struct Curl_sockaddr_storage sa;
244 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
245 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
246 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
248 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
251 struct Curl_dns_entry *h=NULL;
252 unsigned short port = data->set.localport; /* use this port number, 0 for
254 /* how many port numbers to try to bind to, increasing one at a time */
255 int portnum = data->set.localportrange;
256 const char *dev = data->set.str[STRING_DEVICE];
258 char myhost[256] = "";
259 int done = 0; /* -1 for error, 1 for address found */
261 /*************************************************************
262 * Select device to bind socket to
263 *************************************************************/
265 /* no local kind of binding was requested */
268 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
270 if(dev && (strlen(dev)<255) ) {
273 if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
275 * We now have the numerical IP address in the 'myhost' buffer
277 infof(data, "Local Interface %s is ip %s using address family %i\n",
281 #ifdef SO_BINDTODEVICE
282 /* I am not sure any other OSs than Linux that provide this feature, and
283 * at the least I cannot test. --Ben
285 * This feature allows one to tightly bind the local socket to a
286 * particular interface. This will force even requests to other local
287 * interfaces to go out the external interface.
290 * Only bind to the interface when specified as interface, not just as a
291 * hostname or ip address.
293 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
294 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
296 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
297 " will do regular bind\n",
298 dev, error, Curl_strerror(conn, error));
299 /* This is typically "errno 1, error: Operation not permitted" if
300 you're not running as root or another suitable privileged user */
306 * This was not an interface, resolve the name as a host name
309 * Temporarily force name resolution to use only the address type
310 * of the connection. The resolve functions should really be changed
311 * to take a type parameter instead.
313 long ipver = conn->ip_version;
317 conn->ip_version = CURL_IPRESOLVE_V4;
319 else if (af == AF_INET6)
320 conn->ip_version = CURL_IPRESOLVE_V6;
323 rc = Curl_resolv(conn, dev, 0, &h);
324 if(rc == CURLRESOLV_PENDING)
325 (void)Curl_wait_for_resolv(conn, &h);
326 conn->ip_version = ipver;
329 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
330 Curl_printable_address(h->addr, myhost, sizeof(myhost));
331 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
332 dev, af, myhost, h->addr->ai_family);
333 Curl_resolv_unlock(data, h);
338 * provided dev was no interface (or interfaces are not supported
339 * e.g. solaris) no ip address and no domain we fail here
348 if((af == AF_INET6) &&
349 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
350 si6->sin6_family = AF_INET6;
351 si6->sin6_port = htons(port);
352 sizeof_sa = sizeof(struct sockaddr_in6);
357 if((af == AF_INET) &&
358 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
359 si4->sin_family = AF_INET;
360 si4->sin_port = htons(port);
361 sizeof_sa = sizeof(struct sockaddr_in);
366 failf(data, "Couldn't bind to '%s'", dev);
367 return CURLE_INTERFACE_FAILED;
371 /* no device was given, prepare sa to match af's needs */
373 if ( af == AF_INET6 ) {
374 si6->sin6_family = AF_INET6;
375 si6->sin6_port = htons(port);
376 sizeof_sa = sizeof(struct sockaddr_in6);
380 if ( af == AF_INET ) {
381 si4->sin_family = AF_INET;
382 si4->sin_port = htons(port);
383 sizeof_sa = sizeof(struct sockaddr_in);
388 if( bind(sockfd, sock, sizeof_sa) >= 0) {
389 /* we succeeded to bind */
390 struct Curl_sockaddr_storage add;
391 curl_socklen_t size = sizeof(add);
392 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
393 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
394 data->state.os_errno = error = SOCKERRNO;
395 failf(data, "getsockname() failed with errno %d: %s",
396 error, Curl_strerror(conn, error));
397 return CURLE_INTERFACE_FAILED;
399 infof(data, "Local port: %hu\n", port);
400 conn->bits.bound = TRUE;
405 infof(data, "Bind to local port %hu failed, trying next\n", port);
406 port++; /* try next port */
407 /* We re-use/clobber the port variable here below */
408 if(sock->sa_family == AF_INET)
409 si4->sin_port = ntohs(port);
412 si6->sin6_port = ntohs(port);
419 data->state.os_errno = error = SOCKERRNO;
420 failf(data, "bind failed with errno %d: %s",
421 error, Curl_strerror(conn, error));
423 return CURLE_INTERFACE_FAILED;
427 * verifyconnect() returns TRUE if the connect really has happened.
429 static bool verifyconnect(curl_socket_t sockfd, int *error)
434 curl_socklen_t errSize = sizeof(err);
438 * In October 2003 we effectively nullified this function on Windows due to
439 * problems with it using all CPU in multi-threaded cases.
441 * In May 2004, we bring it back to offer more info back on connect failures.
442 * Gisle Vanem could reproduce the former problems with this function, but
443 * could avoid them by adding this SleepEx() call below:
445 * "I don't have Rational Quantify, but the hint from his post was
446 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
447 * just Sleep(0) would be enough?) would release whatever
448 * mutex/critical-section the ntdll call is waiting on.
450 * Someone got to verify this on Win-NT 4.0, 2000."
461 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
464 /* Old WinCE versions don't support SO_ERROR */
465 if(WSAENOPROTOOPT == err) {
471 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
472 if(EBADIOCTL == err) {
477 if((0 == err) || (EISCONN == err))
478 /* we are connected, awesome! */
481 /* This wasn't a successful connect */
493 /* Used within the multi interface. Try next IP address, return TRUE if no
494 more address exists or error */
495 static CURLcode trynextip(struct connectdata *conn,
499 curl_socket_t sockfd;
502 /* First clean up after the failed socket.
503 Don't close it yet to ensure that the next IP's socket gets a different
504 file descriptor, which can prevent bugs when the curl_multi_socket_action
505 interface is used with certain select() replacements such as kqueue. */
506 curl_socket_t fd_to_close = conn->sock[sockindex];
507 conn->sock[sockindex] = CURL_SOCKET_BAD;
510 if(sockindex != FIRSTSOCKET) {
512 return CURLE_COULDNT_CONNECT; /* no next */
515 /* try the next address */
516 ai = conn->ip_addr->ai_next;
519 CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected);
522 if(sockfd != CURL_SOCKET_BAD) {
523 /* store the new socket descriptor */
524 conn->sock[sockindex] = sockfd;
532 return CURLE_COULDNT_CONNECT;
535 /* Copies connection info into the session handle to make it available
536 when the session handle is no longer associated with a connection. */
537 void Curl_persistconninfo(struct connectdata *conn)
539 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
540 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
541 conn->data->info.conn_primary_port = conn->primary_port;
542 conn->data->info.conn_local_port = conn->local_port;
545 /* retrieves ip address and port from a sockaddr structure */
546 static bool getaddressinfo(struct sockaddr* sa, char* addr,
549 unsigned short us_port;
550 struct sockaddr_in* si = NULL;
552 struct sockaddr_in6* si6 = NULL;
554 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
555 struct sockaddr_un* su = NULL;
558 switch (sa->sa_family) {
560 si = (struct sockaddr_in*) sa;
561 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
562 addr, MAX_IPADR_LEN)) {
563 us_port = ntohs(si->sin_port);
570 si6 = (struct sockaddr_in6*)sa;
571 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
572 addr, MAX_IPADR_LEN)) {
573 us_port = ntohs(si6->sin6_port);
579 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
581 su = (struct sockaddr_un*)sa;
582 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
596 /* retrieves the start/end point information of a socket of an established
598 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
602 struct Curl_sockaddr_storage ssrem;
603 struct Curl_sockaddr_storage ssloc;
604 struct SessionHandle *data = conn->data;
606 if(!conn->bits.reuse) {
608 len = sizeof(struct Curl_sockaddr_storage);
609 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
611 failf(data, "getpeername() failed with errno %d: %s",
612 error, Curl_strerror(conn, error));
616 len = sizeof(struct Curl_sockaddr_storage);
617 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
619 failf(data, "getsockname() failed with errno %d: %s",
620 error, Curl_strerror(conn, error));
624 if(!getaddressinfo((struct sockaddr*)&ssrem,
625 conn->primary_ip, &conn->primary_port)) {
627 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
628 error, Curl_strerror(conn, error));
632 if(!getaddressinfo((struct sockaddr*)&ssloc,
633 conn->local_ip, &conn->local_port)) {
635 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
636 error, Curl_strerror(conn, error));
642 /* persist connection info in session handle */
643 Curl_persistconninfo(conn);
647 * Curl_is_connected() is used from the multi interface to check if the
648 * firstsocket has connected.
651 CURLcode Curl_is_connected(struct connectdata *conn,
656 struct SessionHandle *data = conn->data;
657 CURLcode code = CURLE_OK;
658 curl_socket_t sockfd = conn->sock[sockindex];
659 long allow = DEFAULT_CONNECT_TIMEOUT;
662 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
664 *connected = FALSE; /* a very negative world view is best */
666 if(conn->bits.tcpconnect) {
667 /* we are connected already! */
672 /* figure out how long time we have left to connect */
673 allow = Curl_timeleft(conn, NULL, TRUE);
676 /* time-out, bail out, go home */
677 failf(data, "Connection time-out");
678 return CURLE_OPERATION_TIMEDOUT;
681 /* check for connect without timeout as we want to return immediately */
682 rc = waitconnect(conn, sockfd, 0);
683 if(WAITCONN_TIMEOUT == rc)
684 /* not an error, but also no connection yet */
687 if(WAITCONN_CONNECTED == rc) {
688 if(verifyconnect(sockfd, &error)) {
689 /* we are connected, awesome! */
690 conn->bits.tcpconnect = TRUE;
692 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
693 Curl_verboseconnect(conn);
694 Curl_updateconninfo(conn, sockfd);
698 /* nope, not connected for real */
701 /* nope, not connected */
702 if(WAITCONN_FDSET_ERROR == rc) {
703 (void)verifyconnect(sockfd, &error);
704 infof(data, "%s\n",Curl_strerror(conn, error));
707 infof(data, "Connection failed\n");
711 * The connection failed here, we should attempt to connect to the "next
712 * address" for the given host. But first remember the latest error.
715 data->state.os_errno = error;
716 SET_SOCKERRNO(error);
719 code = trynextip(conn, sockindex, connected);
723 data->state.os_errno = error;
724 failf(data, "Failed connect to %s:%ld; %s",
725 conn->host.name, conn->port, Curl_strerror(conn, error));
731 static void tcpnodelay(struct connectdata *conn,
732 curl_socket_t sockfd)
735 struct SessionHandle *data= conn->data;
736 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
737 int proto = IPPROTO_TCP;
740 /* The use of getprotobyname() is disabled since it isn't thread-safe on
741 numerous systems. On these getprotobyname_r() should be used instead, but
742 that exists in at least one 4 arg version and one 5 arg version, and
743 since the proto number rarely changes anyway we now just use the hard
744 coded number. The "proper" fix would need a configure check for the
745 correct function much in the same style the gethostbyname_r versions are
747 struct protoent *pe = getprotobyname("tcp");
752 if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
754 infof(data, "Could not set TCP_NODELAY: %s\n",
755 Curl_strerror(conn, SOCKERRNO));
757 infof(data,"TCP_NODELAY set\n");
765 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
766 sending data to a dead peer (instead of relying on the 4th argument to send
767 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
769 static void nosigpipe(struct connectdata *conn,
770 curl_socket_t sockfd)
772 struct SessionHandle *data= conn->data;
774 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
776 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
777 Curl_strerror(conn, SOCKERRNO));
780 #define nosigpipe(x,y)
784 /* When you run a program that uses the Windows Sockets API, you may
785 experience slow performance when you copy data to a TCP server.
787 http://support.microsoft.com/kb/823764
789 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
793 void Curl_sndbufset(curl_socket_t sockfd)
795 int val = CURL_MAX_WRITE_SIZE + 32;
797 int curlen = sizeof(curval);
799 if (getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
803 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
811 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
812 * CURL_SOCKET_BAD. Other errors will however return proper errors.
814 * singleipconnect() connects to the given IP only, and it may return without
815 * having connected if used from the multi interface.
818 singleipconnect(struct connectdata *conn,
819 const Curl_addrinfo *ai,
821 curl_socket_t *sockp,
824 struct Curl_sockaddr_ex addr;
828 struct SessionHandle *data = conn->data;
829 curl_socket_t sockfd;
830 CURLcode res = CURLE_OK;
831 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
832 struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
835 *sockp = CURL_SOCKET_BAD;
838 * The Curl_sockaddr_ex structure is basically libcurl's external API
839 * curl_sockaddr structure with enough space available to directly hold
840 * any protocol-specific address structures. The variable declared here
841 * will be used to pass / receive data to/from the fopensocket callback
842 * if this has been set, before that, it is initialized from parameters.
845 addr.family = ai->ai_family;
846 addr.socktype = conn->socktype;
847 addr.protocol = ai->ai_protocol;
848 addr.addrlen = ai->ai_addrlen;
850 if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
851 addr.addrlen = sizeof(struct Curl_sockaddr_storage);
852 memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
854 *connected = FALSE; /* default is not connected */
856 if(data->set.fopensocket)
858 * If the opensocket callback is set, all the destination address
859 * information is passed to the callback. Depending on this information the
860 * callback may opt to abort the connection, this is indicated returning
861 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
862 * the callback returns a valid socket the destination address information
863 * might have been changed and this 'new' address will actually be used
866 sockfd = data->set.fopensocket(data->set.opensocket_client,
868 (struct curl_sockaddr *)&addr);
870 /* opensocket callback not set, so simply create the socket now */
871 sockfd = socket(addr.family, addr.socktype, addr.protocol);
873 if(sockfd == CURL_SOCKET_BAD)
874 /* no socket, no connection */
877 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
878 if (conn->scope && (addr.family == AF_INET6))
879 sa6->sin6_scope_id = conn->scope;
882 /* store remote address and port used in this connection attempt */
883 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
884 conn->primary_ip, &conn->primary_port)) {
885 /* malformed address or bug in inet_ntop, try next address */
887 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
888 error, Curl_strerror(conn, error));
892 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
893 infof(data, " Trying %s... ", conn->ip_addr_str);
895 Curl_persistconninfo(conn);
898 if(addr.family == AF_INET6)
899 conn->bits.ipv6 = TRUE;
902 if(data->set.tcp_nodelay)
903 tcpnodelay(conn, sockfd);
905 nosigpipe(conn, sockfd);
907 Curl_sndbufset(sockfd);
909 if(data->set.fsockopt) {
910 /* activate callback for setting socket options */
911 error = data->set.fsockopt(data->set.sockopt_client,
915 sclose(sockfd); /* close the socket and bail out */
920 /* possibly bind the local end to an IP, interface or port */
921 res = bindlocal(conn, sockfd, addr.family);
923 sclose(sockfd); /* close socket and bail out */
927 /* set socket non-blocking */
928 curlx_nonblock(sockfd, TRUE);
930 /* Connect TCP sockets, bind UDP */
931 if(conn->socktype == SOCK_STREAM)
932 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
943 #if (EAGAIN) != (EWOULDBLOCK)
944 /* On some platforms EAGAIN and EWOULDBLOCK are the
945 * same value, and on others they are different, hence
951 rc = waitconnect(conn, sockfd, timeout_ms);
952 if(WAITCONN_ABORTED == rc) {
954 return CURLE_ABORTED_BY_CALLBACK;
958 /* unknown error, fallthrough and try another address! */
959 failf(data, "Failed to connect to %s: %s",
960 conn->ip_addr_str, Curl_strerror(conn,error));
961 data->state.os_errno = error;
966 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
967 connect(). We can be sure of this since connect() cannot return 1. */
968 if((WAITCONN_TIMEOUT == rc) &&
969 (data->state.used_interface == Curl_if_multi)) {
970 /* Timeout when running the multi interface */
975 isconnected = verifyconnect(sockfd, &error);
977 if(!rc && isconnected) {
978 /* we are connected, awesome! */
979 *connected = TRUE; /* this is a true connect */
980 infof(data, "connected\n");
981 Curl_updateconninfo(conn, sockfd);
985 else if(WAITCONN_TIMEOUT == rc)
986 infof(data, "Timeout\n");
988 data->state.os_errno = error;
989 infof(data, "%s\n", Curl_strerror(conn, error));
992 /* connect failed or timed out */
999 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1000 * There might be more than one IP address to try out. Fill in the passed
1001 * pointer with the connected socket.
1004 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1005 const struct Curl_dns_entry *remotehost,
1006 curl_socket_t *sockconn, /* the connected socket */
1007 Curl_addrinfo **addr, /* the one we used */
1008 bool *connected) /* really connected? */
1010 struct SessionHandle *data = conn->data;
1011 curl_socket_t sockfd = CURL_SOCKET_BAD;
1015 Curl_addrinfo *curr_addr;
1017 struct timeval after;
1018 struct timeval before = Curl_tvnow();
1020 /*************************************************************
1021 * Figure out what maximum time we have left
1022 *************************************************************/
1024 long timeout_per_addr;
1026 DEBUGASSERT(sockconn);
1027 *connected = FALSE; /* default to not connected */
1029 /* get the timeout left */
1030 timeout_ms = Curl_timeleft(conn, &before, TRUE);
1032 if(timeout_ms < 0) {
1033 /* a precaution, no need to continue if time already is up */
1034 failf(data, "Connection time-out");
1035 return CURLE_OPERATION_TIMEDOUT;
1038 /* Max time for each address */
1039 num_addr = Curl_num_addresses(remotehost->addr);
1040 timeout_per_addr = timeout_ms / num_addr;
1042 ai = remotehost->addr;
1044 /* Below is the loop that attempts to connect to all IP-addresses we
1045 * know for the given host. One by one until one IP succeeds.
1048 if(data->state.used_interface == Curl_if_multi)
1049 /* don't hang when doing multi */
1050 timeout_per_addr = 0;
1053 * Connecting with a Curl_addrinfo chain
1055 for (curr_addr = ai, aliasindex=0; curr_addr;
1056 curr_addr = curr_addr->ai_next, aliasindex++) {
1058 /* start connecting to the IP curr_addr points to */
1060 singleipconnect(conn, curr_addr, timeout_per_addr, &sockfd, connected);
1065 if(sockfd != CURL_SOCKET_BAD)
1068 /* get a new timeout for next attempt */
1069 after = Curl_tvnow();
1070 timeout_ms -= Curl_tvdiff(after, before);
1071 if(timeout_ms < 0) {
1072 failf(data, "connect() timed out!");
1073 return CURLE_OPERATION_TIMEDOUT;
1076 } /* end of connect-to-each-address loop */
1078 *sockconn = sockfd; /* the socket descriptor we've connected */
1080 if(sockfd == CURL_SOCKET_BAD) {
1081 /* no good connect was made */
1082 failf(data, "couldn't connect to host");
1083 return CURLE_COULDNT_CONNECT;
1086 /* leave the socket in non-blocking mode */
1088 /* store the address we use */
1092 data->info.numconnects++; /* to track the number of connections made */
1098 * Used to extract socket and connectdata struct for the most recent
1099 * transfer on the given SessionHandle.
1101 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1103 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1104 struct connectdata **connp)
1106 curl_socket_t sockfd;
1107 if((data->state.lastconnect != -1) &&
1108 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1109 struct connectdata *c =
1110 data->state.connc->connects[data->state.lastconnect];
1112 /* only store this if the caller cares for it */
1114 sockfd = c->sock[FIRSTSOCKET];
1115 /* we have a socket connected, let's determine if the server shut down */
1116 /* determine if ssl */
1117 if(c->ssl[FIRSTSOCKET].use) {
1118 /* use the SSL context */
1119 if(!Curl_ssl_check_cxn(c))
1120 return CURL_SOCKET_BAD; /* FIN received */
1122 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1125 /* use the socket */
1127 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1128 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1129 return CURL_SOCKET_BAD; /* FIN received */
1135 return CURL_SOCKET_BAD;