Resync
[CMakeLuaTailorHgBridge.git] / CMakeLua / Utilities / cmcurl / connect.c
blob998eef52034ed9d62c4bcb2950123a13c246ae97
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2006, 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 * $Id: connect.c,v 1.2 2007/03/15 19:22:13 andy Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 #ifndef WIN32
27 /* headers for non-win32 */
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
33 #endif
34 #ifdef HAVE_SYS_SOCKET_H
35 #include <sys/socket.h>
36 #endif
37 #ifdef HAVE_NETINET_IN_H
38 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
39 #endif
40 #ifdef HAVE_NETINET_TCP_H
41 #include <netinet/tcp.h> /* for TCP_NODELAY */
42 #endif
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef HAVE_FCNTL_H
53 #include <fcntl.h>
54 #endif
55 #ifdef HAVE_NETINET_IN_H
56 #include <netinet/in.h>
57 #endif
58 #ifdef HAVE_ARPA_INET_H
59 #include <arpa/inet.h>
60 #endif
61 #ifdef HAVE_STDLIB_H
62 #include <stdlib.h> /* required for free() prototype, without it, this crashes
63 on macos 68K */
64 #endif
65 #if (defined(HAVE_FIONBIO) && defined(__NOVELL_LIBC__))
66 #include <sys/filio.h>
67 #endif
68 #if (defined(NETWARE) && defined(__NOVELL_LIBC__))
69 #undef in_addr_t
70 #define in_addr_t unsigned long
71 #endif
72 #ifdef VMS
73 #include <in.h>
74 #include <inet.h>
75 #endif
77 #endif
78 #include <stdio.h>
79 #include <errno.h>
80 #include <string.h>
82 #ifndef TRUE
83 #define TRUE 1
84 #define FALSE 0
85 #endif
87 #ifdef USE_WINSOCK
88 #define EINPROGRESS WSAEINPROGRESS
89 #define EWOULDBLOCK WSAEWOULDBLOCK
90 #define EISCONN WSAEISCONN
91 #define ENOTSOCK WSAENOTSOCK
92 #define ECONNREFUSED WSAECONNREFUSED
93 #endif
95 #include "urldata.h"
96 #include "sendf.h"
97 #include "if2ip.h"
98 #include "strerror.h"
99 #include "connect.h"
100 #include "memory.h"
101 #include "select.h"
102 #include "url.h" /* for Curl_safefree() */
103 #include "multiif.h"
104 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
105 #include "inet_ntop.h"
107 /* The last #include file should be: */
108 #include "memdebug.h"
110 static bool verifyconnect(curl_socket_t sockfd, int *error);
112 static curl_socket_t
113 singleipconnect(struct connectdata *conn,
114 const Curl_addrinfo *ai, /* start connecting to this */
115 long timeout_ms,
116 bool *connected);
119 * Curl_sockerrno() returns the *socket-related* errno (or equivalent) on this
120 * platform to hide platform specific for the function that calls this.
122 int Curl_sockerrno(void)
124 #ifdef USE_WINSOCK
125 return (int)WSAGetLastError();
126 #else
127 return errno;
128 #endif
132 * Curl_nonblock() set the given socket to either blocking or non-blocking
133 * mode based on the 'nonblock' boolean argument. This function is highly
134 * portable.
136 int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
137 int nonblock /* TRUE or FALSE */)
139 #undef SETBLOCK
140 #define SETBLOCK 0
141 #ifdef HAVE_O_NONBLOCK
142 /* most recent unix versions */
143 int flags;
145 flags = fcntl(sockfd, F_GETFL, 0);
146 if (TRUE == nonblock)
147 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
148 else
149 return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
150 #undef SETBLOCK
151 #define SETBLOCK 1
152 #endif
154 #if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
155 /* older unix versions */
156 int flags;
158 flags = nonblock;
159 return ioctl(sockfd, FIONBIO, &flags);
160 #undef SETBLOCK
161 #define SETBLOCK 2
162 #endif
164 #if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
165 /* Windows? */
166 unsigned long flags;
167 flags = nonblock;
169 return ioctlsocket(sockfd, FIONBIO, &flags);
170 #undef SETBLOCK
171 #define SETBLOCK 3
172 #endif
174 #if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
175 /* presumably for Amiga */
176 return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
177 #undef SETBLOCK
178 #define SETBLOCK 4
179 #endif
181 #if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
182 /* BeOS */
183 long b = nonblock ? 1 : 0;
184 return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
185 #undef SETBLOCK
186 #define SETBLOCK 5
187 #endif
189 #ifdef HAVE_DISABLED_NONBLOCKING
190 return 0; /* returns success */
191 #undef SETBLOCK
192 #define SETBLOCK 6
193 #endif
195 #if (SETBLOCK == 0)
196 #error "no non-blocking method was found/used/set"
197 #endif
201 * waitconnect() waits for a TCP connect on the given socket for the specified
202 * number if milliseconds. It returns:
203 * 0 fine connect
204 * -1 select() error
205 * 1 select() timeout
206 * 2 select() returned with an error condition fd_set
209 #define WAITCONN_CONNECTED 0
210 #define WAITCONN_SELECT_ERROR -1
211 #define WAITCONN_TIMEOUT 1
212 #define WAITCONN_FDSET_ERROR 2
214 static
215 int waitconnect(curl_socket_t sockfd, /* socket */
216 long timeout_msec)
218 int rc;
219 #ifdef mpeix
220 /* Call this function once now, and ignore the results. We do this to
221 "clear" the error state on the socket so that we can later read it
222 reliably. This is reported necessary on the MPE/iX operating system. */
223 (void)verifyconnect(sockfd, NULL);
224 #endif
226 /* now select() until we get connect or timeout */
227 rc = Curl_select(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
228 if(-1 == rc)
229 /* error, no connect here, try next */
230 return WAITCONN_SELECT_ERROR;
232 else if(0 == rc)
233 /* timeout, no connect today */
234 return WAITCONN_TIMEOUT;
236 if(rc & CSELECT_ERR)
237 /* error condition caught */
238 return WAITCONN_FDSET_ERROR;
240 /* we have a connect! */
241 return WAITCONN_CONNECTED;
244 static CURLcode bindlocal(struct connectdata *conn,
245 curl_socket_t sockfd)
247 struct SessionHandle *data = conn->data;
248 struct sockaddr_in me;
249 struct sockaddr *sock = NULL; /* bind to this address */
250 socklen_t socksize; /* size of the data sock points to */
251 unsigned short port = data->set.localport; /* use this port number, 0 for
252 "random" */
253 /* how many port numbers to try to bind to, increasing one at a time */
254 int portnum = data->set.localportrange;
256 /*************************************************************
257 * Select device to bind socket to
258 *************************************************************/
259 if (data->set.device && (strlen(data->set.device)<255) ) {
260 struct Curl_dns_entry *h=NULL;
261 char myhost[256] = "";
262 in_addr_t in;
263 int rc;
264 bool was_iface = FALSE;
266 /* First check if the given name is an IP address */
267 in=inet_addr(data->set.device);
269 if((in == CURL_INADDR_NONE) &&
270 Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
272 * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
274 rc = Curl_resolv(conn, myhost, 0, &h);
275 if(rc == CURLRESOLV_PENDING)
276 (void)Curl_wait_for_resolv(conn, &h);
278 if(h) {
279 was_iface = TRUE;
280 Curl_resolv_unlock(data, h);
284 if(!was_iface) {
286 * This was not an interface, resolve the name as a host name
287 * or IP number
289 rc = Curl_resolv(conn, data->set.device, 0, &h);
290 if(rc == CURLRESOLV_PENDING)
291 (void)Curl_wait_for_resolv(conn, &h);
293 if(h) {
294 if(in == CURL_INADDR_NONE)
295 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
296 Curl_inet_ntop(h->addr->ai_addr->sa_family,
297 &((struct sockaddr_in*)h->addr->ai_addr)->sin_addr,
298 myhost, sizeof myhost);
299 else
300 /* we know data->set.device is shorter than the myhost array */
301 strcpy(myhost, data->set.device);
302 Curl_resolv_unlock(data, h);
306 if(! *myhost) {
307 /* need to fix this
308 h=Curl_gethost(data,
309 getmyhost(*myhost,sizeof(myhost)),
310 hostent_buf,
311 sizeof(hostent_buf));
313 failf(data, "Couldn't bind to '%s'", data->set.device);
314 return CURLE_HTTP_PORT_FAILED;
317 infof(data, "Bind local address to %s\n", myhost);
319 #ifdef SO_BINDTODEVICE
320 /* I am not sure any other OSs than Linux that provide this feature, and
321 * at the least I cannot test. --Ben
323 * This feature allows one to tightly bind the local socket to a
324 * particular interface. This will force even requests to other local
325 * interfaces to go out the external interface.
328 if (was_iface) {
329 /* Only bind to the interface when specified as interface, not just as a
330 * hostname or ip address.
332 if (setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
333 data->set.device, strlen(data->set.device)+1) != 0) {
334 /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
335 sockfd, data->set.device, Curl_strerror(Curl_sockerrno())); */
336 infof(data, "SO_BINDTODEVICE %s failed\n",
337 data->set.device);
338 /* This is typically "errno 1, error: Operation not permitted" if
339 you're not running as root or another suitable privileged user */
342 #endif
344 in=inet_addr(myhost);
345 if (CURL_INADDR_NONE == in) {
346 failf(data,"couldn't find my own IP address (%s)", myhost);
347 return CURLE_HTTP_PORT_FAILED;
348 } /* end of inet_addr */
350 if ( h ) {
351 Curl_addrinfo *addr = h->addr;
352 sock = addr->ai_addr;
353 socksize = addr->ai_addrlen;
355 else
356 return CURLE_HTTP_PORT_FAILED;
359 else if(port) {
360 /* if a local port number is requested but no local IP, extract the
361 address from the socket */
362 memset(&me, 0, sizeof(struct sockaddr));
363 me.sin_family = AF_INET;
364 me.sin_addr.s_addr = INADDR_ANY;
366 sock = (struct sockaddr *)&me;
367 socksize = sizeof(struct sockaddr);
370 else
371 /* no local kind of binding was requested */
372 return CURLE_OK;
374 do {
376 /* Set port number to bind to, 0 makes the system pick one */
377 if(sock->sa_family == AF_INET)
378 ((struct sockaddr_in *)sock)->sin_port = htons(port);
379 #ifdef ENABLE_IPV6
380 else
381 ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
382 #endif
384 if( bind(sockfd, sock, socksize) >= 0) {
385 /* we succeeded to bind */
386 struct Curl_sockaddr_storage add;
387 socklen_t size;
389 size = sizeof(add);
390 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
391 failf(data, "getsockname() failed");
392 return CURLE_HTTP_PORT_FAILED;
394 /* We re-use/clobber the port variable here below */
395 if(((struct sockaddr *)&add)->sa_family == AF_INET)
396 port = ntohs(((struct sockaddr_in *)&add)->sin_port);
397 #ifdef ENABLE_IPV6
398 else
399 port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
400 #endif
401 infof(data, "Local port: %d\n", port);
402 return CURLE_OK;
404 if(--portnum > 0) {
405 infof(data, "Bind to local port %d failed, trying next\n", port);
406 port++; /* try next port */
408 else
409 break;
410 } while(1);
412 data->state.os_errno = Curl_sockerrno();
413 failf(data, "bind failure: %s",
414 Curl_strerror(conn, data->state.os_errno));
415 return CURLE_HTTP_PORT_FAILED;
420 * verifyconnect() returns TRUE if the connect really has happened.
422 static bool verifyconnect(curl_socket_t sockfd, int *error)
424 bool rc = TRUE;
425 #ifdef SO_ERROR
426 int err = 0;
427 socklen_t errSize = sizeof(err);
429 #ifdef WIN32
431 * In October 2003 we effectively nullified this function on Windows due to
432 * problems with it using all CPU in multi-threaded cases.
434 * In May 2004, we bring it back to offer more info back on connect failures.
435 * Gisle Vanem could reproduce the former problems with this function, but
436 * could avoid them by adding this SleepEx() call below:
438 * "I don't have Rational Quantify, but the hint from his post was
439 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
440 * just Sleep(0) would be enough?) would release whatever
441 * mutex/critical-section the ntdll call is waiting on.
443 * Someone got to verify this on Win-NT 4.0, 2000."
446 #ifdef _WIN32_WCE
447 Sleep(0);
448 #else
449 SleepEx(0, FALSE);
450 #endif
452 #endif
454 if( -1 == getsockopt(sockfd, SOL_SOCKET, SO_ERROR,
455 (void *)&err, &errSize))
456 err = Curl_sockerrno();
458 #ifdef _WIN32_WCE
459 /* Always returns this error, bug in CE? */
460 if(WSAENOPROTOOPT==err)
461 err=0;
462 #endif
464 if ((0 == err) || (EISCONN == err))
465 /* we are connected, awesome! */
466 rc = TRUE;
467 else
468 /* This wasn't a successful connect */
469 rc = FALSE;
470 if (error)
471 *error = err;
472 #else
473 (void)sockfd;
474 if (error)
475 *error = Curl_sockerrno();
476 #endif
477 return rc;
480 CURLcode Curl_store_ip_addr(struct connectdata *conn)
482 char addrbuf[256];
483 Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
485 /* save the string */
486 Curl_safefree(conn->ip_addr_str);
487 conn->ip_addr_str = strdup(addrbuf);
488 if(!conn->ip_addr_str)
489 return CURLE_OUT_OF_MEMORY; /* FAIL */
491 #ifdef PF_INET6
492 if(conn->ip_addr->ai_family == PF_INET6)
493 conn->bits.ipv6 = TRUE;
494 #endif
496 return CURLE_OK;
499 /* Used within the multi interface. Try next IP address, return TRUE if no
500 more address exists */
501 static bool trynextip(struct connectdata *conn,
502 int sockindex,
503 bool *connected)
505 curl_socket_t sockfd;
506 Curl_addrinfo *ai;
508 /* first close the failed socket */
509 sclose(conn->sock[sockindex]);
510 conn->sock[sockindex] = CURL_SOCKET_BAD;
511 *connected = FALSE;
513 if(sockindex != FIRSTSOCKET)
514 return TRUE; /* no next */
516 /* try the next address */
517 ai = conn->ip_addr->ai_next;
519 while (ai) {
520 sockfd = singleipconnect(conn, ai, 0L, connected);
521 if(sockfd != CURL_SOCKET_BAD) {
522 /* store the new socket descriptor */
523 conn->sock[sockindex] = sockfd;
524 conn->ip_addr = ai;
526 Curl_store_ip_addr(conn);
527 return FALSE;
529 ai = ai->ai_next;
531 return TRUE;
535 * Curl_is_connected() is used from the multi interface to check if the
536 * firstsocket has connected.
539 CURLcode Curl_is_connected(struct connectdata *conn,
540 int sockindex,
541 bool *connected)
543 int rc;
544 struct SessionHandle *data = conn->data;
545 CURLcode code = CURLE_OK;
546 curl_socket_t sockfd = conn->sock[sockindex];
547 long allow = DEFAULT_CONNECT_TIMEOUT;
548 long allow_total = 0;
549 long has_passed;
551 curlassert(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
553 *connected = FALSE; /* a very negative world view is best */
555 /* Evaluate in milliseconds how much time that has passed */
556 has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
558 /* subtract the most strict timeout of the ones */
559 if(data->set.timeout && data->set.connecttimeout) {
560 if (data->set.timeout < data->set.connecttimeout)
561 allow_total = allow = data->set.timeout*1000;
562 else
563 allow = data->set.connecttimeout*1000;
565 else if(data->set.timeout) {
566 allow_total = allow = data->set.timeout*1000;
568 else if(data->set.connecttimeout) {
569 allow = data->set.connecttimeout*1000;
572 if(has_passed > allow ) {
573 /* time-out, bail out, go home */
574 failf(data, "Connection time-out after %ld ms", has_passed);
575 return CURLE_OPERATION_TIMEOUTED;
577 if(conn->bits.tcpconnect) {
578 /* we are connected already! */
579 Curl_expire(data, allow_total);
580 *connected = TRUE;
581 return CURLE_OK;
584 Curl_expire(data, allow);
586 /* check for connect without timeout as we want to return immediately */
587 rc = waitconnect(sockfd, 0);
589 if(WAITCONN_CONNECTED == rc) {
590 int error;
591 if (verifyconnect(sockfd, &error)) {
592 /* we are connected, awesome! */
593 *connected = TRUE;
594 return CURLE_OK;
596 /* nope, not connected for real */
597 data->state.os_errno = error;
598 infof(data, "Connection failed\n");
599 if(trynextip(conn, sockindex, connected)) {
600 code = CURLE_COULDNT_CONNECT;
603 else if(WAITCONN_TIMEOUT != rc) {
604 int error = 0;
606 /* nope, not connected */
607 if (WAITCONN_FDSET_ERROR == rc) {
608 (void)verifyconnect(sockfd, &error);
609 data->state.os_errno = error;
610 infof(data, "%s\n",Curl_strerror(conn,error));
612 else
613 infof(data, "Connection failed\n");
615 if(trynextip(conn, sockindex, connected)) {
616 error = Curl_sockerrno();
617 data->state.os_errno = error;
618 failf(data, "Failed connect to %s:%d; %s",
619 conn->host.name, conn->port, Curl_strerror(conn,error));
620 code = CURLE_COULDNT_CONNECT;
624 * If the connection failed here, we should attempt to connect to the "next
625 * address" for the given host.
628 return code;
631 static void tcpnodelay(struct connectdata *conn,
632 curl_socket_t sockfd)
634 #ifdef TCP_NODELAY
635 struct SessionHandle *data= conn->data;
636 socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
637 int proto = IPPROTO_TCP;
639 #ifdef HAVE_GETPROTOBYNAME
640 struct protoent *pe = getprotobyname("tcp");
641 if (pe)
642 proto = pe->p_proto;
643 #endif
645 if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
646 sizeof(onoff)) < 0)
647 infof(data, "Could not set TCP_NODELAY: %s\n",
648 Curl_strerror(conn, Curl_sockerrno()));
649 else
650 infof(data,"TCP_NODELAY set\n");
651 #else
652 (void)conn;
653 (void)sockfd;
654 #endif
657 #ifdef SO_NOSIGPIPE
658 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
659 sending data to a dead peer (instead of relying on the 4th argument to send
660 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
661 systems? */
662 static void nosigpipe(struct connectdata *conn,
663 curl_socket_t sockfd)
665 struct SessionHandle *data= conn->data;
666 int onoff = 1;
667 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
668 sizeof(onoff)) < 0)
669 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
670 Curl_strerror(conn, Curl_sockerrno()));
672 #else
673 #define nosigpipe(x,y)
674 #endif
676 /* singleipconnect() connects to the given IP only, and it may return without
677 having connected if used from the multi interface. */
678 static curl_socket_t
679 singleipconnect(struct connectdata *conn,
680 const Curl_addrinfo *ai,
681 long timeout_ms,
682 bool *connected)
684 char addr_buf[128];
685 int rc;
686 int error;
687 bool isconnected;
688 struct SessionHandle *data = conn->data;
689 curl_socket_t sockfd;
690 CURLcode res;
692 sockfd = socket(ai->ai_family, conn->socktype, ai->ai_protocol);
693 if (sockfd == CURL_SOCKET_BAD)
694 return CURL_SOCKET_BAD;
696 *connected = FALSE; /* default is not connected */
698 Curl_printable_address(ai, addr_buf, sizeof(addr_buf));
699 infof(data, " Trying %s... ", addr_buf);
701 if(data->set.tcp_nodelay)
702 tcpnodelay(conn, sockfd);
704 nosigpipe(conn, sockfd);
706 if(data->set.fsockopt) {
707 /* activate callback for setting socket options */
708 error = data->set.fsockopt(data->set.sockopt_client,
709 sockfd,
710 CURLSOCKTYPE_IPCXN);
711 if (error) {
712 sclose(sockfd); /* close the socket and bail out */
713 return CURL_SOCKET_BAD;
717 /* possibly bind the local end to an IP, interface or port */
718 res = bindlocal(conn, sockfd);
719 if(res) {
720 sclose(sockfd); /* close socket and bail out */
721 return CURL_SOCKET_BAD;
724 /* set socket non-blocking */
725 Curl_nonblock(sockfd, TRUE);
727 /* Connect TCP sockets, bind UDP */
728 if(conn->socktype == SOCK_STREAM)
729 rc = connect(sockfd, ai->ai_addr, ai->ai_addrlen);
730 else
731 rc = 0;
733 if(-1 == rc) {
734 error = Curl_sockerrno();
736 switch (error) {
737 case EINPROGRESS:
738 case EWOULDBLOCK:
739 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
740 /* On some platforms EAGAIN and EWOULDBLOCK are the
741 * same value, and on others they are different, hence
742 * the odd #if
744 case EAGAIN:
745 #endif
746 rc = waitconnect(sockfd, timeout_ms);
747 break;
748 default:
749 /* unknown error, fallthrough and try another address! */
750 failf(data, "Failed to connect to %s: %s",
751 addr_buf, Curl_strerror(conn,error));
752 data->state.os_errno = error;
753 break;
757 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
758 connect(). We can be sure of this since connect() cannot return 1. */
759 if((WAITCONN_TIMEOUT == rc) &&
760 (data->state.used_interface == Curl_if_multi)) {
761 /* Timeout when running the multi interface */
762 return sockfd;
765 isconnected = verifyconnect(sockfd, &error);
767 if(!rc && isconnected) {
768 /* we are connected, awesome! */
769 *connected = TRUE; /* this is a true connect */
770 infof(data, "connected\n");
771 return sockfd;
773 else if(WAITCONN_TIMEOUT == rc)
774 infof(data, "Timeout\n");
775 else {
776 data->state.os_errno = error;
777 infof(data, "%s\n", Curl_strerror(conn, error));
780 /* connect failed or timed out */
781 sclose(sockfd);
783 return CURL_SOCKET_BAD;
787 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
788 * There might be more than one IP address to try out. Fill in the passed
789 * pointer with the connected socket.
792 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
793 const struct Curl_dns_entry *remotehost, /* use this one */
794 curl_socket_t *sockconn, /* the connected socket */
795 Curl_addrinfo **addr, /* the one we used */
796 bool *connected) /* really connected? */
798 struct SessionHandle *data = conn->data;
799 curl_socket_t sockfd = CURL_SOCKET_BAD;
800 int aliasindex;
801 int num_addr;
802 Curl_addrinfo *ai;
803 Curl_addrinfo *curr_addr;
805 struct timeval after;
806 struct timeval before = Curl_tvnow();
808 /*************************************************************
809 * Figure out what maximum time we have left
810 *************************************************************/
811 long timeout_ms= DEFAULT_CONNECT_TIMEOUT;
812 long timeout_per_addr;
814 *connected = FALSE; /* default to not connected */
816 if(data->set.timeout || data->set.connecttimeout) {
817 long has_passed;
819 /* Evaluate in milliseconds how much time that has passed */
820 has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
822 #ifndef min
823 #define min(a, b) ((a) < (b) ? (a) : (b))
824 #endif
826 /* get the most strict timeout of the ones converted to milliseconds */
827 if(data->set.timeout && data->set.connecttimeout) {
828 if (data->set.timeout < data->set.connecttimeout)
829 timeout_ms = data->set.timeout*1000;
830 else
831 timeout_ms = data->set.connecttimeout*1000;
833 else if(data->set.timeout)
834 timeout_ms = data->set.timeout*1000;
835 else
836 timeout_ms = data->set.connecttimeout*1000;
838 /* subtract the passed time */
839 timeout_ms -= has_passed;
841 if(timeout_ms < 0) {
842 /* a precaution, no need to continue if time already is up */
843 failf(data, "Connection time-out");
844 return CURLE_OPERATION_TIMEOUTED;
847 Curl_expire(data, timeout_ms);
849 /* Max time for each address */
850 num_addr = Curl_num_addresses(remotehost->addr);
851 timeout_per_addr = timeout_ms / num_addr;
853 ai = remotehost->addr;
855 /* Below is the loop that attempts to connect to all IP-addresses we
856 * know for the given host. One by one until one IP succeeds.
859 if(data->state.used_interface == Curl_if_multi)
860 /* don't hang when doing multi */
861 timeout_per_addr = 0;
864 * Connecting with a Curl_addrinfo chain
866 for (curr_addr = ai, aliasindex=0; curr_addr;
867 curr_addr = curr_addr->ai_next, aliasindex++) {
869 /* start connecting to the IP curr_addr points to */
870 sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
872 if(sockfd != CURL_SOCKET_BAD)
873 break;
875 /* get a new timeout for next attempt */
876 after = Curl_tvnow();
877 timeout_ms -= Curl_tvdiff(after, before);
878 if(timeout_ms < 0) {
879 failf(data, "connect() timed out!");
880 return CURLE_OPERATION_TIMEOUTED;
882 before = after;
883 } /* end of connect-to-each-address loop */
885 if (sockfd == CURL_SOCKET_BAD) {
886 /* no good connect was made */
887 *sockconn = CURL_SOCKET_BAD;
888 failf(data, "couldn't connect to host");
889 return CURLE_COULDNT_CONNECT;
892 /* leave the socket in non-blocking mode */
894 /* store the address we use */
895 if(addr)
896 *addr = curr_addr;
898 /* allow NULL-pointers to get passed in */
899 if(sockconn)
900 *sockconn = sockfd; /* the socket descriptor we've connected */
902 data->info.numconnects++; /* to track the number of connections made */
904 return CURLE_OK;