1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, 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.1.1.1 2008-09-23 16:32:05 hoffman Exp $
22 ***************************************************************************/
27 /* headers for non-win32 */
28 #ifdef HAVE_SYS_TIME_H
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
38 #include <sys/un.h> /* for sockaddr_un */
40 #ifdef HAVE_NETINET_TCP_H
41 #include <netinet/tcp.h> /* for TCP_NODELAY */
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
59 #include <stdlib.h> /* required for free() prototype, without it, this crashes */
60 #endif /* on macos 68K */
62 #if (defined(HAVE_FIONBIO) && defined(NETWARE))
63 #include <sys/filio.h>
67 #define in_addr_t unsigned long
80 #define _MPRINTF_REPLACE /* use our functions only */
81 #include <curl/mprintf.h>
90 #include "url.h" /* for Curl_safefree() */
92 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
93 #include "inet_ntop.h"
94 #include "inet_pton.h"
95 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
97 /* The last #include file should be: */
101 /* This isn't actually supported under Symbian OS */
105 static bool verifyconnect(curl_socket_t sockfd
, int *error
);
108 singleipconnect(struct connectdata
*conn
,
109 const Curl_addrinfo
*ai
, /* start connecting to this */
114 * Curl_timeleft() returns the amount of milliseconds left allowed for the
115 * transfer/connection. If the value is negative, the timeout time has already
118 * If 'nowp' is non-NULL, it points to the current time.
119 * 'duringconnect' is FALSE if not during a connect, as then of course the
120 * connect timeout is not taken into account!
122 long Curl_timeleft(struct connectdata
*conn
,
123 struct timeval
*nowp
,
126 struct SessionHandle
*data
= conn
->data
;
128 long timeout_ms
= duringconnect
?DEFAULT_CONNECT_TIMEOUT
:0;
131 /* if a timeout is set, use the most restrictive one */
133 if(data
->set
.timeout
> 0)
135 if(duringconnect
&& (data
->set
.connecttimeout
> 0))
138 switch (timeout_set
) {
140 timeout_ms
= data
->set
.timeout
;
143 timeout_ms
= data
->set
.connecttimeout
;
146 if(data
->set
.timeout
< data
->set
.connecttimeout
)
147 timeout_ms
= data
->set
.timeout
;
149 timeout_ms
= data
->set
.connecttimeout
;
152 /* use the default */
154 /* if we're not during connect, there's no default timeout so if we're
155 at zero we better just return zero and not make it a negative number
166 /* substract elapsed time */
167 timeout_ms
-= Curl_tvdiff(*nowp
, data
->progress
.t_startsingle
);
174 * Curl_nonblock() set the given socket to either blocking or non-blocking
175 * mode based on the 'nonblock' boolean argument. This function is highly
178 int Curl_nonblock(curl_socket_t sockfd
, /* operate on this */
179 int nonblock
/* TRUE or FALSE */)
183 #ifdef HAVE_O_NONBLOCK
184 /* most recent unix versions */
187 flags
= fcntl(sockfd
, F_GETFL
, 0);
188 if(FALSE
!= nonblock
)
189 return fcntl(sockfd
, F_SETFL
, flags
| O_NONBLOCK
);
191 return fcntl(sockfd
, F_SETFL
, flags
& (~O_NONBLOCK
));
196 #if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
197 /* older unix versions */
201 return ioctl(sockfd
, FIONBIO
, &flags
);
206 #if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
211 return ioctlsocket(sockfd
, FIONBIO
, &flags
);
216 #if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
217 /* presumably for Amiga */
218 return IoctlSocket(sockfd
, FIONBIO
, (long)nonblock
);
223 #if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
225 long b
= nonblock
? 1 : 0;
226 return setsockopt(sockfd
, SOL_SOCKET
, SO_NONBLOCK
, &b
, sizeof(b
));
231 #ifdef HAVE_DISABLED_NONBLOCKING
232 return 0; /* returns success */
238 #error "no non-blocking method was found/used/set"
243 * waitconnect() waits for a TCP connect on the given socket for the specified
244 * number if milliseconds. It returns:
248 * 2 select() returned with an error condition fd_set
251 #define WAITCONN_CONNECTED 0
252 #define WAITCONN_SELECT_ERROR -1
253 #define WAITCONN_TIMEOUT 1
254 #define WAITCONN_FDSET_ERROR 2
257 int waitconnect(curl_socket_t sockfd
, /* socket */
262 /* Call this function once now, and ignore the results. We do this to
263 "clear" the error state on the socket so that we can later read it
264 reliably. This is reported necessary on the MPE/iX operating system. */
265 (void)verifyconnect(sockfd
, NULL
);
268 /* now select() until we get connect or timeout */
269 rc
= Curl_socket_ready(CURL_SOCKET_BAD
, sockfd
, (int)timeout_msec
);
271 /* error, no connect here, try next */
272 return WAITCONN_SELECT_ERROR
;
275 /* timeout, no connect today */
276 return WAITCONN_TIMEOUT
;
278 if(rc
& CURL_CSELECT_ERR
)
279 /* error condition caught */
280 return WAITCONN_FDSET_ERROR
;
282 /* we have a connect! */
283 return WAITCONN_CONNECTED
;
286 static CURLcode
bindlocal(struct connectdata
*conn
,
287 curl_socket_t sockfd
)
292 struct SessionHandle
*data
= conn
->data
;
293 struct sockaddr_in me
;
294 struct sockaddr
*sock
= NULL
; /* bind to this address */
295 socklen_t socksize
; /* size of the data sock points to */
296 unsigned short port
= data
->set
.localport
; /* use this port number, 0 for
298 /* how many port numbers to try to bind to, increasing one at a time */
299 int portnum
= data
->set
.localportrange
;
300 const char *dev
= data
->set
.str
[STRING_DEVICE
];
302 /*************************************************************
303 * Select device to bind socket to
304 *************************************************************/
305 if(dev
&& (strlen(dev
)<255) ) {
306 struct Curl_dns_entry
*h
=NULL
;
307 char myhost
[256] = "";
310 bool was_iface
= FALSE
;
313 /* First check if the given name is an IP address */
314 in
=inet_addr((char *) dev
);
316 if((in
== CURL_INADDR_NONE
) &&
317 Curl_if2ip(dev
, myhost
, sizeof(myhost
))) {
319 * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
321 rc
= Curl_resolv(conn
, myhost
, 0, &h
);
322 if(rc
== CURLRESOLV_PENDING
)
323 (void)Curl_wait_for_resolv(conn
, &h
);
327 Curl_resolv_unlock(data
, h
);
333 * This was not an interface, resolve the name as a host name
336 rc
= Curl_resolv(conn
, dev
, 0, &h
);
337 if(rc
== CURLRESOLV_PENDING
)
338 (void)Curl_wait_for_resolv(conn
, &h
);
341 if(in
== CURL_INADDR_NONE
)
342 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
343 Curl_printable_address(h
->addr
, myhost
, sizeof myhost
);
345 /* we know data->set.device is shorter than the myhost array */
347 Curl_resolv_unlock(data
, h
);
354 getmyhost(*myhost,sizeof(myhost)),
356 sizeof(hostent_buf));
358 failf(data
, "Couldn't bind to '%s'", dev
);
359 return CURLE_INTERFACE_FAILED
;
362 infof(data
, "Bind local address to %s\n", myhost
);
364 #ifdef SO_BINDTODEVICE
365 /* I am not sure any other OSs than Linux that provide this feature, and
366 * at the least I cannot test. --Ben
368 * This feature allows one to tightly bind the local socket to a
369 * particular interface. This will force even requests to other local
370 * interfaces to go out the external interface.
374 /* Only bind to the interface when specified as interface, not just as a
375 * hostname or ip address.
377 if(setsockopt(sockfd
, SOL_SOCKET
, SO_BINDTODEVICE
,
378 dev
, strlen(dev
)+1) != 0) {
379 /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
380 sockfd, dev, Curl_strerror(SOCKERRNO)); */
381 infof(data
, "SO_BINDTODEVICE %s failed\n", dev
);
382 /* This is typically "errno 1, error: Operation not permitted" if
383 you're not running as root or another suitable privileged user */
388 in
=inet_addr(myhost
);
391 in6
= Curl_inet_pton (AF_INET6
, myhost
, (void *)&ipv6_addr
);
393 if(CURL_INADDR_NONE
== in
&& -1 == in6
) {
394 failf(data
,"couldn't find my own IP address (%s)", myhost
);
395 return CURLE_INTERFACE_FAILED
;
396 } /* end of inet_addr */
399 Curl_addrinfo
*addr
= h
->addr
;
400 sock
= addr
->ai_addr
;
401 socksize
= addr
->ai_addrlen
;
404 return CURLE_INTERFACE_FAILED
;
408 /* if a local port number is requested but no local IP, extract the
409 address from the socket */
410 memset(&me
, 0, sizeof(struct sockaddr
));
411 me
.sin_family
= AF_INET
;
412 me
.sin_addr
.s_addr
= INADDR_ANY
;
414 sock
= (struct sockaddr
*)&me
;
415 socksize
= sizeof(struct sockaddr
);
419 /* no local kind of binding was requested */
424 /* Set port number to bind to, 0 makes the system pick one */
425 if(sock
->sa_family
== AF_INET
)
426 ((struct sockaddr_in
*)sock
)->sin_port
= htons(port
);
429 ((struct sockaddr_in6
*)sock
)->sin6_port
= htons(port
);
432 if( bind(sockfd
, sock
, socksize
) >= 0) {
433 /* we succeeded to bind */
434 struct Curl_sockaddr_storage add
;
438 if(getsockname(sockfd
, (struct sockaddr
*) &add
, &size
) < 0) {
439 failf(data
, "getsockname() failed");
440 return CURLE_INTERFACE_FAILED
;
442 /* We re-use/clobber the port variable here below */
443 if(((struct sockaddr
*)&add
)->sa_family
== AF_INET
)
444 port
= ntohs(((struct sockaddr_in
*)&add
)->sin_port
);
447 port
= ntohs(((struct sockaddr_in6
*)&add
)->sin6_port
);
449 infof(data
, "Local port: %d\n", port
);
450 conn
->bits
.bound
= TRUE
;
454 infof(data
, "Bind to local port %d failed, trying next\n", port
);
455 port
++; /* try next port */
461 data
->state
.os_errno
= SOCKERRNO
;
462 failf(data
, "bind failure: %s",
463 Curl_strerror(conn
, data
->state
.os_errno
));
464 return CURLE_INTERFACE_FAILED
;
469 * verifyconnect() returns TRUE if the connect really has happened.
471 static bool verifyconnect(curl_socket_t sockfd
, int *error
)
476 socklen_t errSize
= sizeof(err
);
480 * In October 2003 we effectively nullified this function on Windows due to
481 * problems with it using all CPU in multi-threaded cases.
483 * In May 2004, we bring it back to offer more info back on connect failures.
484 * Gisle Vanem could reproduce the former problems with this function, but
485 * could avoid them by adding this SleepEx() call below:
487 * "I don't have Rational Quantify, but the hint from his post was
488 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
489 * just Sleep(0) would be enough?) would release whatever
490 * mutex/critical-section the ntdll call is waiting on.
492 * Someone got to verify this on Win-NT 4.0, 2000."
503 if(0 != getsockopt(sockfd
, SOL_SOCKET
, SO_ERROR
, (void *)&err
, &errSize
))
506 /* Old WinCE versions don't support SO_ERROR */
507 if(WSAENOPROTOOPT
== err
) {
513 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
514 if(EBADIOCTL
== err
) {
519 if((0 == err
) || (EISCONN
== err
))
520 /* we are connected, awesome! */
523 /* This wasn't a successful connect */
535 CURLcode
Curl_store_ip_addr(struct connectdata
*conn
)
538 Curl_printable_address(conn
->ip_addr
, addrbuf
, sizeof(addrbuf
));
540 /* save the string */
541 Curl_safefree(conn
->ip_addr_str
);
542 conn
->ip_addr_str
= strdup(addrbuf
);
543 if(!conn
->ip_addr_str
)
544 return CURLE_OUT_OF_MEMORY
; /* FAIL */
547 if(conn
->ip_addr
->ai_family
== PF_INET6
)
548 conn
->bits
.ipv6
= TRUE
;
554 /* Used within the multi interface. Try next IP address, return TRUE if no
555 more address exists or error */
556 static bool trynextip(struct connectdata
*conn
,
560 curl_socket_t sockfd
;
563 /* first close the failed socket */
564 sclose(conn
->sock
[sockindex
]);
565 conn
->sock
[sockindex
] = CURL_SOCKET_BAD
;
568 if(sockindex
!= FIRSTSOCKET
)
569 return TRUE
; /* no next */
571 /* try the next address */
572 ai
= conn
->ip_addr
->ai_next
;
575 sockfd
= singleipconnect(conn
, ai
, 0L, connected
);
576 if(sockfd
!= CURL_SOCKET_BAD
) {
577 /* store the new socket descriptor */
578 conn
->sock
[sockindex
] = sockfd
;
581 return Curl_store_ip_addr(conn
) != CURLE_OK
;
589 * Curl_is_connected() is used from the multi interface to check if the
590 * firstsocket has connected.
593 CURLcode
Curl_is_connected(struct connectdata
*conn
,
598 struct SessionHandle
*data
= conn
->data
;
599 CURLcode code
= CURLE_OK
;
600 curl_socket_t sockfd
= conn
->sock
[sockindex
];
601 long allow
= DEFAULT_CONNECT_TIMEOUT
;
603 DEBUGASSERT(sockindex
>= FIRSTSOCKET
&& sockindex
<= SECONDARYSOCKET
);
605 *connected
= FALSE
; /* a very negative world view is best */
607 if(conn
->bits
.tcpconnect
) {
608 /* we are connected already! */
609 long allow_total
= 0;
611 /* subtract the most strict timeout of the ones */
612 if(data
->set
.timeout
)
613 allow_total
= data
->set
.timeout
;
615 Curl_expire(data
, allow_total
);
620 /* figure out how long time we have left to connect */
621 allow
= Curl_timeleft(conn
, NULL
, TRUE
);
624 /* time-out, bail out, go home */
625 failf(data
, "Connection time-out");
626 return CURLE_OPERATION_TIMEDOUT
;
629 Curl_expire(data
, allow
);
631 /* check for connect without timeout as we want to return immediately */
632 rc
= waitconnect(sockfd
, 0);
634 if(WAITCONN_CONNECTED
== rc
) {
636 if(verifyconnect(sockfd
, &error
)) {
637 /* we are connected, awesome! */
641 /* nope, not connected for real */
642 data
->state
.os_errno
= error
;
643 infof(data
, "Connection failed\n");
644 if(trynextip(conn
, sockindex
, connected
)) {
645 failf(data
, "Failed connect to %s:%d; %s",
646 conn
->host
.name
, conn
->port
, Curl_strerror(conn
, error
));
647 code
= CURLE_COULDNT_CONNECT
;
650 else if(WAITCONN_TIMEOUT
!= rc
) {
653 /* nope, not connected */
654 if(WAITCONN_FDSET_ERROR
== rc
) {
655 (void)verifyconnect(sockfd
, &error
);
656 data
->state
.os_errno
= error
;
657 infof(data
, "%s\n",Curl_strerror(conn
,error
));
660 infof(data
, "Connection failed\n");
662 if(trynextip(conn
, sockindex
, connected
)) {
664 data
->state
.os_errno
= error
;
665 failf(data
, "Failed connect to %s:%d; %s",
666 conn
->host
.name
, conn
->port
, Curl_strerror(conn
, error
));
667 code
= CURLE_COULDNT_CONNECT
;
671 * If the connection failed here, we should attempt to connect to the "next
672 * address" for the given host.
678 static void tcpnodelay(struct connectdata
*conn
,
679 curl_socket_t sockfd
)
682 struct SessionHandle
*data
= conn
->data
;
683 socklen_t onoff
= (socklen_t
) data
->set
.tcp_nodelay
;
684 int proto
= IPPROTO_TCP
;
687 /* The use of getprotobyname() is disabled since it isn't thread-safe on
688 numerous systems. On these getprotobyname_r() should be used instead, but
689 that exists in at least one 4 arg version and one 5 arg version, and
690 since the proto number rarely changes anyway we now just use the hard
691 coded number. The "proper" fix would need a configure check for the
692 correct function much in the same style the gethostbyname_r versions are
694 struct protoent
*pe
= getprotobyname("tcp");
699 if(setsockopt(sockfd
, proto
, TCP_NODELAY
, (void *)&onoff
,
701 infof(data
, "Could not set TCP_NODELAY: %s\n",
702 Curl_strerror(conn
, SOCKERRNO
));
704 infof(data
,"TCP_NODELAY set\n");
712 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
713 sending data to a dead peer (instead of relying on the 4th argument to send
714 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
716 static void nosigpipe(struct connectdata
*conn
,
717 curl_socket_t sockfd
)
719 struct SessionHandle
*data
= conn
->data
;
721 if(setsockopt(sockfd
, SOL_SOCKET
, SO_NOSIGPIPE
, (void *)&onoff
,
723 infof(data
, "Could not set SO_NOSIGPIPE: %s\n",
724 Curl_strerror(conn
, SOCKERRNO
));
727 #define nosigpipe(x,y)
730 /* singleipconnect() connects to the given IP only, and it may return without
731 having connected if used from the multi interface. */
733 singleipconnect(struct connectdata
*conn
,
734 const Curl_addrinfo
*ai
,
742 struct SessionHandle
*data
= conn
->data
;
743 curl_socket_t sockfd
;
746 * Curl_sockaddr_storage, which is basically sockaddr_storage has a space
747 * for a largest possible struct sockaddr only. We should add some space for
748 * the other fields we are using. Hence the addr_storage size math.
750 char addr_storage
[sizeof(struct curl_sockaddr
)-
751 sizeof(struct sockaddr
)+
752 sizeof(struct Curl_sockaddr_storage
)];
753 struct curl_sockaddr
*addr
=(struct curl_sockaddr
*)&addr_storage
;
754 const void *iptoprint
;
756 addr
->family
=ai
->ai_family
;
757 addr
->socktype
=conn
->socktype
;
758 addr
->protocol
=ai
->ai_protocol
;
760 (ai
->ai_addrlen
< (socklen_t
)sizeof(struct Curl_sockaddr_storage
)) ?
761 (unsigned int)ai
->ai_addrlen
: sizeof(struct Curl_sockaddr_storage
);
762 memcpy(&addr
->addr
, ai
->ai_addr
, addr
->addrlen
);
764 /* If set, use opensocket callback to get the socket */
765 if(data
->set
.fopensocket
)
766 sockfd
= data
->set
.fopensocket(data
->set
.opensocket_client
,
767 CURLSOCKTYPE_IPCXN
, addr
);
769 sockfd
= socket(addr
->family
, addr
->socktype
, addr
->protocol
);
770 if(sockfd
== CURL_SOCKET_BAD
)
771 return CURL_SOCKET_BAD
;
773 *connected
= FALSE
; /* default is not connected */
776 if (conn
->scope
&& (addr
->family
== AF_INET6
)) {
777 struct sockaddr_in6
*in6
= (struct sockaddr_in6
*)&addr
->addr
;
778 in6
->sin6_scope_id
= conn
->scope
;
782 /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
784 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
785 if(addr
->family
==AF_UNIX
) {
786 infof(data
, " Trying %s... ",
787 ((const struct sockaddr_un
*)(&addr
->addr
))->sun_path
);
788 snprintf(data
->info
.ip
, MAX_IPADR_LEN
, "%s",
789 ((const struct sockaddr_un
*)(&addr
->addr
))->sun_path
);
795 if(addr
->family
==AF_INET6
)
796 iptoprint
= &((const struct sockaddr_in6
*)(&addr
->addr
))->sin6_addr
;
799 iptoprint
= &((const struct sockaddr_in
*)(&addr
->addr
))->sin_addr
;
801 if(Curl_inet_ntop(addr
->family
, iptoprint
, addr_buf
,
802 sizeof(addr_buf
)) != NULL
) {
803 infof(data
, " Trying %s... ", addr_buf
);
804 snprintf(data
->info
.ip
, MAX_IPADR_LEN
, "%s", addr_buf
);
808 if(data
->set
.tcp_nodelay
)
809 tcpnodelay(conn
, sockfd
);
811 nosigpipe(conn
, sockfd
);
813 if(data
->set
.fsockopt
) {
814 /* activate callback for setting socket options */
815 error
= data
->set
.fsockopt(data
->set
.sockopt_client
,
819 sclose(sockfd
); /* close the socket and bail out */
820 return CURL_SOCKET_BAD
;
824 /* possibly bind the local end to an IP, interface or port */
825 res
= bindlocal(conn
, sockfd
);
827 sclose(sockfd
); /* close socket and bail out */
828 return CURL_SOCKET_BAD
;
831 /* set socket non-blocking */
832 Curl_nonblock(sockfd
, TRUE
);
834 /* Connect TCP sockets, bind UDP */
835 if(conn
->socktype
== SOCK_STREAM
)
836 rc
= connect(sockfd
, &addr
->addr
, addr
->addrlen
);
846 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
847 /* On some platforms EAGAIN and EWOULDBLOCK are the
848 * same value, and on others they are different, hence
853 rc
= waitconnect(sockfd
, timeout_ms
);
856 /* unknown error, fallthrough and try another address! */
857 failf(data
, "Failed to connect to %s: %s",
858 addr_buf
, Curl_strerror(conn
,error
));
859 data
->state
.os_errno
= error
;
864 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
865 connect(). We can be sure of this since connect() cannot return 1. */
866 if((WAITCONN_TIMEOUT
== rc
) &&
867 (data
->state
.used_interface
== Curl_if_multi
)) {
868 /* Timeout when running the multi interface */
872 isconnected
= verifyconnect(sockfd
, &error
);
874 if(!rc
&& isconnected
) {
875 /* we are connected, awesome! */
876 *connected
= TRUE
; /* this is a true connect */
877 infof(data
, "connected\n");
880 else if(WAITCONN_TIMEOUT
== rc
)
881 infof(data
, "Timeout\n");
883 data
->state
.os_errno
= error
;
884 infof(data
, "%s\n", Curl_strerror(conn
, error
));
887 /* connect failed or timed out */
890 return CURL_SOCKET_BAD
;
894 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
895 * There might be more than one IP address to try out. Fill in the passed
896 * pointer with the connected socket.
899 CURLcode
Curl_connecthost(struct connectdata
*conn
, /* context */
900 const struct Curl_dns_entry
*remotehost
,
901 curl_socket_t
*sockconn
, /* the connected socket */
902 Curl_addrinfo
**addr
, /* the one we used */
903 bool *connected
) /* really connected? */
905 struct SessionHandle
*data
= conn
->data
;
906 curl_socket_t sockfd
= CURL_SOCKET_BAD
;
910 Curl_addrinfo
*curr_addr
;
912 struct timeval after
;
913 struct timeval before
= Curl_tvnow();
915 /*************************************************************
916 * Figure out what maximum time we have left
917 *************************************************************/
919 long timeout_per_addr
;
921 DEBUGASSERT(sockconn
);
922 *connected
= FALSE
; /* default to not connected */
924 /* get the timeout left */
925 timeout_ms
= Curl_timeleft(conn
, &before
, TRUE
);
928 /* a precaution, no need to continue if time already is up */
929 failf(data
, "Connection time-out");
930 return CURLE_OPERATION_TIMEDOUT
;
932 Curl_expire(data
, timeout_ms
);
934 /* Max time for each address */
935 num_addr
= Curl_num_addresses(remotehost
->addr
);
936 timeout_per_addr
= timeout_ms
/ num_addr
;
938 ai
= remotehost
->addr
;
940 /* Below is the loop that attempts to connect to all IP-addresses we
941 * know for the given host. One by one until one IP succeeds.
944 if(data
->state
.used_interface
== Curl_if_multi
)
945 /* don't hang when doing multi */
946 timeout_per_addr
= 0;
949 * Connecting with a Curl_addrinfo chain
951 for (curr_addr
= ai
, aliasindex
=0; curr_addr
;
952 curr_addr
= curr_addr
->ai_next
, aliasindex
++) {
954 /* start connecting to the IP curr_addr points to */
955 sockfd
= singleipconnect(conn
, curr_addr
, timeout_per_addr
, connected
);
957 if(sockfd
!= CURL_SOCKET_BAD
)
960 /* get a new timeout for next attempt */
961 after
= Curl_tvnow();
962 timeout_ms
-= Curl_tvdiff(after
, before
);
964 failf(data
, "connect() timed out!");
965 return CURLE_OPERATION_TIMEDOUT
;
968 } /* end of connect-to-each-address loop */
970 *sockconn
= sockfd
; /* the socket descriptor we've connected */
972 if(sockfd
== CURL_SOCKET_BAD
) {
973 /* no good connect was made */
974 failf(data
, "couldn't connect to host");
975 return CURLE_COULDNT_CONNECT
;
978 /* leave the socket in non-blocking mode */
980 /* store the address we use */
984 data
->info
.numconnects
++; /* to track the number of connections made */
990 * Used to extract socket and connectdata struct for the most recent
991 * transfer on the given SessionHandle.
993 * The socket 'long' will be -1 in case of failure!
995 CURLcode
Curl_getconnectinfo(struct SessionHandle
*data
,
997 struct connectdata
**connp
)
999 if((data
->state
.lastconnect
!= -1) &&
1000 (data
->state
.connc
->connects
[data
->state
.lastconnect
] != NULL
)) {
1001 struct connectdata
*c
=
1002 data
->state
.connc
->connects
[data
->state
.lastconnect
];
1004 /* only store this if the caller cares for it */
1006 *param_longp
= c
->sock
[FIRSTSOCKET
];
1007 /* we have a socket connected, let's determine if the server shut down */
1008 /* determine if ssl */
1009 if(c
->ssl
[FIRSTSOCKET
].use
) {
1010 /* use the SSL context */
1011 if(!Curl_ssl_check_cxn(c
))
1012 *param_longp
= -1; /* FIN received */
1014 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1017 /* use the socket */
1019 if(recv((RECV_TYPE_ARG1
)c
->sock
[FIRSTSOCKET
], (RECV_TYPE_ARG2
)&buf
,
1020 (RECV_TYPE_ARG3
)1, (RECV_TYPE_ARG4
)MSG_PEEK
) == 0) {
1021 *param_longp
= -1; /* FIN received */