1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2011, 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_SOCKET_H
26 #include <sys/socket.h>
28 #ifdef HAVE_NETINET_IN_H
29 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
32 #include <sys/un.h> /* for sockaddr_un */
34 #ifdef HAVE_NETINET_TCP_H
35 #include <netinet/tcp.h> /* for TCP_NODELAY */
37 #ifdef HAVE_SYS_IOCTL_H
38 #include <sys/ioctl.h>
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
53 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
54 #include <sys/filio.h>
58 #define in_addr_t unsigned long
65 #define _MPRINTF_REPLACE /* use our functions only */
66 #include <curl/mprintf.h>
73 #include "curl_memory.h"
75 #include "url.h" /* for Curl_safefree() */
77 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
78 #include "inet_ntop.h"
79 #include "inet_pton.h"
80 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
84 /* The last #include file should be: */
88 /* This isn't actually supported under Symbian OS */
92 struct Curl_sockaddr_ex {
99 struct Curl_sockaddr_storage buff;
102 #define sa_addr _sa_ex_u.addr
104 static bool verifyconnect(curl_socket_t sockfd, int *error);
107 singleipconnect(struct connectdata *conn,
108 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 * The start time is stored in progress.t_startsingle - as set with
119 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
121 * If 'nowp' is non-NULL, it points to the current time.
122 * 'duringconnect' is FALSE if not during a connect, as then of course the
123 * connect timeout is not taken into account!
127 long Curl_timeleft(struct SessionHandle *data,
128 struct timeval *nowp,
132 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
135 /* if a timeout is set, use the most restrictive one */
137 if(data->set.timeout > 0)
139 if(duringconnect && (data->set.connecttimeout > 0))
142 switch (timeout_set) {
144 timeout_ms = data->set.timeout;
147 timeout_ms = data->set.connecttimeout;
150 if(data->set.timeout < data->set.connecttimeout)
151 timeout_ms = data->set.timeout;
153 timeout_ms = data->set.connecttimeout;
156 /* use the default */
158 /* if we're not during connect, there's no default timeout so if we're
159 at zero we better just return zero and not make it a negative number
170 /* subtract elapsed time */
171 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
173 /* avoid returning 0 as that means no timeout! */
180 * waitconnect() waits for a TCP connect on the given socket for the specified
181 * number if milliseconds. It returns:
184 #define WAITCONN_CONNECTED 0
185 #define WAITCONN_SELECT_ERROR -1
186 #define WAITCONN_TIMEOUT 1
187 #define WAITCONN_FDSET_ERROR 2
188 #define WAITCONN_ABORTED 3
191 int waitconnect(struct connectdata *conn,
192 curl_socket_t sockfd, /* socket */
197 /* Call this function once now, and ignore the results. We do this to
198 "clear" the error state on the socket so that we can later read it
199 reliably. This is reported necessary on the MPE/iX operating system. */
200 (void)verifyconnect(sockfd, NULL);
205 /* now select() until we get connect or timeout */
206 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, timeout_msec>1000?
208 if(Curl_pgrsUpdate(conn))
209 return WAITCONN_ABORTED;
212 /* error, no connect here, try next */
213 return WAITCONN_SELECT_ERROR;
217 timeout_msec -= 1000;
218 if(timeout_msec <= 0)
219 return WAITCONN_TIMEOUT;
224 if(rc & CURL_CSELECT_ERR)
225 /* error condition caught */
226 return WAITCONN_FDSET_ERROR;
230 return WAITCONN_CONNECTED;
233 static CURLcode bindlocal(struct connectdata *conn,
234 curl_socket_t sockfd, int af)
236 struct SessionHandle *data = conn->data;
238 struct Curl_sockaddr_storage sa;
239 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
240 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
241 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
243 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
246 struct Curl_dns_entry *h=NULL;
247 unsigned short port = data->set.localport; /* use this port number, 0 for
249 /* how many port numbers to try to bind to, increasing one at a time */
250 int portnum = data->set.localportrange;
251 const char *dev = data->set.str[STRING_DEVICE];
253 char myhost[256] = "";
254 int done = 0; /* -1 for error, 1 for address found */
256 /*************************************************************
257 * Select device to bind socket to
258 *************************************************************/
260 /* no local kind of binding was requested */
263 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
265 if(dev && (strlen(dev)<255) ) {
268 if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
270 * We now have the numerical IP address in the 'myhost' buffer
272 infof(data, "Local Interface %s is ip %s using address family %i\n",
276 #ifdef SO_BINDTODEVICE
277 /* I am not sure any other OSs than Linux that provide this feature, and
278 * at the least I cannot test. --Ben
280 * This feature allows one to tightly bind the local socket to a
281 * particular interface. This will force even requests to other local
282 * interfaces to go out the external interface.
285 * Only bind to the interface when specified as interface, not just as a
286 * hostname or ip address.
288 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
289 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
291 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
292 " will do regular bind\n",
293 dev, error, Curl_strerror(conn, error));
294 /* This is typically "errno 1, error: Operation not permitted" if
295 you're not running as root or another suitable privileged user */
301 * This was not an interface, resolve the name as a host name
304 * Temporarily force name resolution to use only the address type
305 * of the connection. The resolve functions should really be changed
306 * to take a type parameter instead.
308 long ipver = conn->ip_version;
312 conn->ip_version = CURL_IPRESOLVE_V4;
314 else if(af == AF_INET6)
315 conn->ip_version = CURL_IPRESOLVE_V6;
318 rc = Curl_resolv(conn, dev, 0, &h);
319 if(rc == CURLRESOLV_PENDING)
320 (void)Curl_resolver_wait_resolv(conn, &h);
321 conn->ip_version = ipver;
324 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
325 Curl_printable_address(h->addr, myhost, sizeof(myhost));
326 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
327 dev, af, myhost, h->addr->ai_family);
328 Curl_resolv_unlock(data, h);
333 * provided dev was no interface (or interfaces are not supported
334 * e.g. solaris) no ip address and no domain we fail here
343 if((af == AF_INET6) &&
344 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
345 si6->sin6_family = AF_INET6;
346 si6->sin6_port = htons(port);
347 sizeof_sa = sizeof(struct sockaddr_in6);
352 if((af == AF_INET) &&
353 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
354 si4->sin_family = AF_INET;
355 si4->sin_port = htons(port);
356 sizeof_sa = sizeof(struct sockaddr_in);
361 failf(data, "Couldn't bind to '%s'", dev);
362 return CURLE_INTERFACE_FAILED;
366 /* no device was given, prepare sa to match af's needs */
369 si6->sin6_family = AF_INET6;
370 si6->sin6_port = htons(port);
371 sizeof_sa = sizeof(struct sockaddr_in6);
376 si4->sin_family = AF_INET;
377 si4->sin_port = htons(port);
378 sizeof_sa = sizeof(struct sockaddr_in);
383 if(bind(sockfd, sock, sizeof_sa) >= 0) {
384 /* we succeeded to bind */
385 struct Curl_sockaddr_storage add;
386 curl_socklen_t size = sizeof(add);
387 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
388 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
389 data->state.os_errno = error = SOCKERRNO;
390 failf(data, "getsockname() failed with errno %d: %s",
391 error, Curl_strerror(conn, error));
392 return CURLE_INTERFACE_FAILED;
394 infof(data, "Local port: %hu\n", port);
395 conn->bits.bound = TRUE;
400 infof(data, "Bind to local port %hu failed, trying next\n", port);
401 port++; /* try next port */
402 /* We re-use/clobber the port variable here below */
403 if(sock->sa_family == AF_INET)
404 si4->sin_port = ntohs(port);
407 si6->sin6_port = ntohs(port);
414 data->state.os_errno = error = SOCKERRNO;
415 failf(data, "bind failed with errno %d: %s",
416 error, Curl_strerror(conn, error));
418 return CURLE_INTERFACE_FAILED;
422 * verifyconnect() returns TRUE if the connect really has happened.
424 static bool verifyconnect(curl_socket_t sockfd, int *error)
429 curl_socklen_t errSize = sizeof(err);
433 * In October 2003 we effectively nullified this function on Windows due to
434 * problems with it using all CPU in multi-threaded cases.
436 * In May 2004, we bring it back to offer more info back on connect failures.
437 * Gisle Vanem could reproduce the former problems with this function, but
438 * could avoid them by adding this SleepEx() call below:
440 * "I don't have Rational Quantify, but the hint from his post was
441 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
442 * just Sleep(0) would be enough?) would release whatever
443 * mutex/critical-section the ntdll call is waiting on.
445 * Someone got to verify this on Win-NT 4.0, 2000."
456 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
459 /* Old WinCE versions don't support SO_ERROR */
460 if(WSAENOPROTOOPT == err) {
466 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
467 if(EBADIOCTL == err) {
472 if((0 == err) || (EISCONN == err))
473 /* we are connected, awesome! */
476 /* This wasn't a successful connect */
488 /* Used within the multi interface. Try next IP address, return TRUE if no
489 more address exists or error */
490 static CURLcode trynextip(struct connectdata *conn,
494 curl_socket_t sockfd;
497 /* First clean up after the failed socket.
498 Don't close it yet to ensure that the next IP's socket gets a different
499 file descriptor, which can prevent bugs when the curl_multi_socket_action
500 interface is used with certain select() replacements such as kqueue. */
501 curl_socket_t fd_to_close = conn->sock[sockindex];
502 conn->sock[sockindex] = CURL_SOCKET_BAD;
505 if(sockindex != FIRSTSOCKET) {
506 Curl_closesocket(conn, fd_to_close);
507 return CURLE_COULDNT_CONNECT; /* no next */
510 /* try the next address */
511 ai = conn->ip_addr->ai_next;
514 CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected);
517 if(sockfd != CURL_SOCKET_BAD) {
518 /* store the new socket descriptor */
519 conn->sock[sockindex] = sockfd;
521 Curl_closesocket(conn, fd_to_close);
526 Curl_closesocket(conn, fd_to_close);
527 return CURLE_COULDNT_CONNECT;
530 /* Copies connection info into the session handle to make it available
531 when the session handle is no longer associated with a connection. */
532 void Curl_persistconninfo(struct connectdata *conn)
534 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
535 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
536 conn->data->info.conn_primary_port = conn->primary_port;
537 conn->data->info.conn_local_port = conn->local_port;
540 /* retrieves ip address and port from a sockaddr structure */
541 static bool getaddressinfo(struct sockaddr* sa, char* addr,
544 unsigned short us_port;
545 struct sockaddr_in* si = NULL;
547 struct sockaddr_in6* si6 = NULL;
549 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
550 struct sockaddr_un* su = NULL;
553 switch (sa->sa_family) {
555 si = (struct sockaddr_in*) sa;
556 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
557 addr, MAX_IPADR_LEN)) {
558 us_port = ntohs(si->sin_port);
565 si6 = (struct sockaddr_in6*)sa;
566 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
567 addr, MAX_IPADR_LEN)) {
568 us_port = ntohs(si6->sin6_port);
574 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
576 su = (struct sockaddr_un*)sa;
577 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
591 /* retrieves the start/end point information of a socket of an established
593 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
597 struct Curl_sockaddr_storage ssrem;
598 struct Curl_sockaddr_storage ssloc;
599 struct SessionHandle *data = conn->data;
601 if(!conn->bits.reuse) {
603 len = sizeof(struct Curl_sockaddr_storage);
604 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
606 failf(data, "getpeername() failed with errno %d: %s",
607 error, Curl_strerror(conn, error));
611 len = sizeof(struct Curl_sockaddr_storage);
612 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
614 failf(data, "getsockname() failed with errno %d: %s",
615 error, Curl_strerror(conn, error));
619 if(!getaddressinfo((struct sockaddr*)&ssrem,
620 conn->primary_ip, &conn->primary_port)) {
622 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
623 error, Curl_strerror(conn, error));
627 if(!getaddressinfo((struct sockaddr*)&ssloc,
628 conn->local_ip, &conn->local_port)) {
630 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
631 error, Curl_strerror(conn, error));
637 /* persist connection info in session handle */
638 Curl_persistconninfo(conn);
642 * Curl_is_connected() is used from the multi interface to check if the
643 * firstsocket has connected.
646 CURLcode Curl_is_connected(struct connectdata *conn,
651 struct SessionHandle *data = conn->data;
652 CURLcode code = CURLE_OK;
653 curl_socket_t sockfd = conn->sock[sockindex];
654 long allow = DEFAULT_CONNECT_TIMEOUT;
658 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
660 *connected = FALSE; /* a very negative world view is best */
662 if(conn->bits.tcpconnect[sockindex]) {
663 /* we are connected already! */
670 /* figure out how long time we have left to connect */
671 allow = Curl_timeleft(data, &now, TRUE);
674 /* time-out, bail out, go home */
675 failf(data, "Connection time-out");
676 return CURLE_OPERATION_TIMEDOUT;
679 /* check for connect without timeout as we want to return immediately */
680 rc = waitconnect(conn, sockfd, 0);
681 if(WAITCONN_TIMEOUT == rc) {
682 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
683 infof(data, "After %ldms connect time, move on!\n",
684 conn->timeoutms_per_addr);
688 /* not an error, but also no connection yet */
692 if(WAITCONN_CONNECTED == rc) {
693 if(verifyconnect(sockfd, &error)) {
694 /* we are connected with TCP, awesome! */
696 /* see if we need to do any proxy magic first once we connected */
697 code = Curl_connected_proxy(conn);
701 conn->bits.tcpconnect[sockindex] = TRUE;
703 if(sockindex == FIRSTSOCKET)
704 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
705 Curl_verboseconnect(conn);
706 Curl_updateconninfo(conn, sockfd);
710 /* nope, not connected for real */
713 /* nope, not connected */
714 if(WAITCONN_FDSET_ERROR == rc) {
715 (void)verifyconnect(sockfd, &error);
716 infof(data, "%s\n",Curl_strerror(conn, error));
719 infof(data, "Connection failed\n");
723 * The connection failed here, we should attempt to connect to the "next
724 * address" for the given host. But first remember the latest error.
727 data->state.os_errno = error;
728 SET_SOCKERRNO(error);
732 code = trynextip(conn, sockindex, connected);
736 data->state.os_errno = error;
737 failf(data, "Failed connect to %s:%ld; %s",
738 conn->host.name, conn->port, Curl_strerror(conn, error));
744 static void tcpnodelay(struct connectdata *conn,
745 curl_socket_t sockfd)
748 struct SessionHandle *data= conn->data;
749 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
750 int level = IPPROTO_TCP;
753 /* The use of getprotobyname() is disabled since it isn't thread-safe on
754 numerous systems. On these getprotobyname_r() should be used instead, but
755 that exists in at least one 4 arg version and one 5 arg version, and
756 since the proto number rarely changes anyway we now just use the hard
757 coded number. The "proper" fix would need a configure check for the
758 correct function much in the same style the gethostbyname_r versions are
760 struct protoent *pe = getprotobyname("tcp");
765 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
767 infof(data, "Could not set TCP_NODELAY: %s\n",
768 Curl_strerror(conn, SOCKERRNO));
770 infof(data,"TCP_NODELAY set\n");
778 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
779 sending data to a dead peer (instead of relying on the 4th argument to send
780 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
782 static void nosigpipe(struct connectdata *conn,
783 curl_socket_t sockfd)
785 struct SessionHandle *data= conn->data;
787 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
789 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
790 Curl_strerror(conn, SOCKERRNO));
793 #define nosigpipe(x,y) Curl_nop_stmt
797 /* When you run a program that uses the Windows Sockets API, you may
798 experience slow performance when you copy data to a TCP server.
800 http://support.microsoft.com/kb/823764
802 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
806 void Curl_sndbufset(curl_socket_t sockfd)
808 int val = CURL_MAX_WRITE_SIZE + 32;
810 int curlen = sizeof(curval);
812 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
816 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
824 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
825 * CURL_SOCKET_BAD. Other errors will however return proper errors.
827 * singleipconnect() connects to the given IP only, and it may return without
828 * having connected if used from the multi interface.
831 singleipconnect(struct connectdata *conn,
832 const Curl_addrinfo *ai,
834 curl_socket_t *sockp,
837 struct Curl_sockaddr_ex addr;
840 bool isconnected = FALSE;
841 struct SessionHandle *data = conn->data;
842 curl_socket_t sockfd;
843 CURLcode res = CURLE_OK;
844 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
845 struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
848 *sockp = CURL_SOCKET_BAD;
851 * The Curl_sockaddr_ex structure is basically libcurl's external API
852 * curl_sockaddr structure with enough space available to directly hold
853 * any protocol-specific address structures. The variable declared here
854 * will be used to pass / receive data to/from the fopensocket callback
855 * if this has been set, before that, it is initialized from parameters.
858 addr.family = ai->ai_family;
859 addr.socktype = conn->socktype;
860 addr.protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
861 addr.addrlen = ai->ai_addrlen;
863 if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
864 addr.addrlen = sizeof(struct Curl_sockaddr_storage);
865 memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
867 *connected = FALSE; /* default is not connected */
869 if(data->set.fopensocket)
871 * If the opensocket callback is set, all the destination address
872 * information is passed to the callback. Depending on this information the
873 * callback may opt to abort the connection, this is indicated returning
874 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
875 * the callback returns a valid socket the destination address information
876 * might have been changed and this 'new' address will actually be used
879 sockfd = data->set.fopensocket(data->set.opensocket_client,
881 (struct curl_sockaddr *)&addr);
883 /* opensocket callback not set, so simply create the socket now */
884 sockfd = socket(addr.family, addr.socktype, addr.protocol);
886 if(sockfd == CURL_SOCKET_BAD)
887 /* no socket, no connection */
890 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
891 if(conn->scope && (addr.family == AF_INET6))
892 sa6->sin6_scope_id = conn->scope;
895 /* store remote address and port used in this connection attempt */
896 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
897 conn->primary_ip, &conn->primary_port)) {
898 /* malformed address or bug in inet_ntop, try next address */
900 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
901 error, Curl_strerror(conn, error));
902 Curl_closesocket(conn, sockfd);
905 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
906 infof(data, " Trying %s... ", conn->ip_addr_str);
908 Curl_persistconninfo(conn);
910 if(data->set.tcp_nodelay)
911 tcpnodelay(conn, sockfd);
913 nosigpipe(conn, sockfd);
915 Curl_sndbufset(sockfd);
917 if(data->set.fsockopt) {
918 /* activate callback for setting socket options */
919 error = data->set.fsockopt(data->set.sockopt_client,
923 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
926 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
927 return CURLE_ABORTED_BY_CALLBACK;
931 /* possibly bind the local end to an IP, interface or port */
932 res = bindlocal(conn, sockfd, addr.family);
934 Curl_closesocket(conn, sockfd); /* close socket and bail out */
938 /* set socket non-blocking */
939 curlx_nonblock(sockfd, TRUE);
941 /* Connect TCP sockets, bind UDP */
942 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
943 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
946 conn->connecttime = Curl_tvnow();
947 if(conn->num_addr > 1)
948 Curl_expire(data, conn->timeoutms_per_addr);
958 #if (EAGAIN) != (EWOULDBLOCK)
959 /* On some platforms EAGAIN and EWOULDBLOCK are the
960 * same value, and on others they are different, hence
966 rc = waitconnect(conn, sockfd, timeout_ms);
967 if(WAITCONN_ABORTED == rc) {
968 Curl_closesocket(conn, sockfd);
969 return CURLE_ABORTED_BY_CALLBACK;
973 /* unknown error, fallthrough and try another address! */
974 failf(data, "Failed to connect to %s: %s",
975 conn->ip_addr_str, Curl_strerror(conn,error));
976 data->state.os_errno = error;
981 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
982 connect(). We can be sure of this since connect() cannot return 1. */
983 if((WAITCONN_TIMEOUT == rc) &&
984 (data->state.used_interface == Curl_if_multi)) {
985 /* Timeout when running the multi interface */
991 isconnected = verifyconnect(sockfd, &error);
993 if(!rc && isconnected) {
994 /* we are connected, awesome! */
995 *connected = TRUE; /* this is a true connect */
996 infof(data, "connected\n");
998 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
1001 Curl_updateconninfo(conn, sockfd);
1005 else if(WAITCONN_TIMEOUT == rc)
1006 infof(data, "Timeout\n");
1008 data->state.os_errno = error;
1009 infof(data, "%s\n", Curl_strerror(conn, error));
1012 /* connect failed or timed out */
1013 Curl_closesocket(conn, sockfd);
1019 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1020 * There might be more than one IP address to try out. Fill in the passed
1021 * pointer with the connected socket.
1024 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1025 const struct Curl_dns_entry *remotehost,
1026 curl_socket_t *sockconn, /* the connected socket */
1027 Curl_addrinfo **addr, /* the one we used */
1028 bool *connected) /* really connected? */
1030 struct SessionHandle *data = conn->data;
1031 curl_socket_t sockfd = CURL_SOCKET_BAD;
1034 Curl_addrinfo *curr_addr;
1036 struct timeval after;
1037 struct timeval before = Curl_tvnow();
1039 /*************************************************************
1040 * Figure out what maximum time we have left
1041 *************************************************************/
1044 DEBUGASSERT(sockconn);
1045 *connected = FALSE; /* default to not connected */
1047 /* get the timeout left */
1048 timeout_ms = Curl_timeleft(data, &before, TRUE);
1050 if(timeout_ms < 0) {
1051 /* a precaution, no need to continue if time already is up */
1052 failf(data, "Connection time-out");
1053 return CURLE_OPERATION_TIMEDOUT;
1056 /* Max time for each address */
1057 conn->num_addr = Curl_num_addresses(remotehost->addr);
1058 conn->timeoutms_per_addr = timeout_ms / conn->num_addr;
1060 ai = remotehost->addr;
1062 /* Below is the loop that attempts to connect to all IP-addresses we
1063 * know for the given host. One by one until one IP succeeds.
1067 * Connecting with a Curl_addrinfo chain
1069 for(curr_addr = ai, aliasindex=0; curr_addr;
1070 curr_addr = curr_addr->ai_next, aliasindex++) {
1072 /* start connecting to the IP curr_addr points to */
1074 singleipconnect(conn, curr_addr,
1075 /* don't hang when doing multi */
1076 (data->state.used_interface == Curl_if_multi)?0:
1077 conn->timeoutms_per_addr, &sockfd, connected);
1082 if(sockfd != CURL_SOCKET_BAD)
1085 /* get a new timeout for next attempt */
1086 after = Curl_tvnow();
1087 timeout_ms -= Curl_tvdiff(after, before);
1088 if(timeout_ms < 0) {
1089 failf(data, "connect() timed out!");
1090 return CURLE_OPERATION_TIMEDOUT;
1093 } /* end of connect-to-each-address loop */
1095 *sockconn = sockfd; /* the socket descriptor we've connected */
1097 if(sockfd == CURL_SOCKET_BAD) {
1098 /* no good connect was made */
1099 failf(data, "couldn't connect to host");
1100 return CURLE_COULDNT_CONNECT;
1103 /* leave the socket in non-blocking mode */
1105 /* store the address we use */
1109 data->info.numconnects++; /* to track the number of connections made */
1115 * Used to extract socket and connectdata struct for the most recent
1116 * transfer on the given SessionHandle.
1118 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1120 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1121 struct connectdata **connp)
1123 curl_socket_t sockfd;
1127 if((data->state.lastconnect != -1) &&
1128 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1129 struct connectdata *c =
1130 data->state.connc->connects[data->state.lastconnect];
1132 /* only store this if the caller cares for it */
1134 sockfd = c->sock[FIRSTSOCKET];
1135 /* we have a socket connected, let's determine if the server shut down */
1136 /* determine if ssl */
1137 if(c->ssl[FIRSTSOCKET].use) {
1138 /* use the SSL context */
1139 if(!Curl_ssl_check_cxn(c))
1140 return CURL_SOCKET_BAD; /* FIN received */
1142 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1145 /* use the socket */
1147 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1148 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1149 return CURL_SOCKET_BAD; /* FIN received */
1155 return CURL_SOCKET_BAD;
1163 * 'conn' can be NULL, beware!
1165 int Curl_closesocket(struct connectdata *conn,
1168 if(conn && conn->fclosesocket)
1169 return conn->fclosesocket(conn->closesocket_client, sock);
1171 return sclose(sock);