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 static bool verifyconnect(curl_socket_t sockfd, int *error);
95 singleipconnect(struct connectdata *conn,
96 const Curl_addrinfo *ai, /* start connecting to this */
102 * Curl_timeleft() returns the amount of milliseconds left allowed for the
103 * transfer/connection. If the value is negative, the timeout time has already
106 * The start time is stored in progress.t_startsingle - as set with
107 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
109 * If 'nowp' is non-NULL, it points to the current time.
110 * 'duringconnect' is FALSE if not during a connect, as then of course the
111 * connect timeout is not taken into account!
115 long Curl_timeleft(struct SessionHandle *data,
116 struct timeval *nowp,
120 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
123 /* if a timeout is set, use the most restrictive one */
125 if(data->set.timeout > 0)
127 if(duringconnect && (data->set.connecttimeout > 0))
130 switch (timeout_set) {
132 timeout_ms = data->set.timeout;
135 timeout_ms = data->set.connecttimeout;
138 if(data->set.timeout < data->set.connecttimeout)
139 timeout_ms = data->set.timeout;
141 timeout_ms = data->set.connecttimeout;
144 /* use the default */
146 /* if we're not during connect, there's no default timeout so if we're
147 at zero we better just return zero and not make it a negative number
158 /* subtract elapsed time */
159 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
161 /* avoid returning 0 as that means no timeout! */
168 * waitconnect() waits for a TCP connect on the given socket for the specified
169 * number if milliseconds. It returns:
172 #define WAITCONN_CONNECTED 0
173 #define WAITCONN_SELECT_ERROR -1
174 #define WAITCONN_TIMEOUT 1
175 #define WAITCONN_FDSET_ERROR 2
176 #define WAITCONN_ABORTED 3
179 int waitconnect(struct connectdata *conn,
180 curl_socket_t sockfd, /* socket */
185 /* Call this function once now, and ignore the results. We do this to
186 "clear" the error state on the socket so that we can later read it
187 reliably. This is reported necessary on the MPE/iX operating system. */
188 (void)verifyconnect(sockfd, NULL);
193 /* now select() until we get connect or timeout */
194 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, timeout_msec>1000?
196 if(Curl_pgrsUpdate(conn))
197 return WAITCONN_ABORTED;
200 /* error, no connect here, try next */
201 return WAITCONN_SELECT_ERROR;
205 timeout_msec -= 1000;
206 if(timeout_msec <= 0)
207 return WAITCONN_TIMEOUT;
212 if(rc & CURL_CSELECT_ERR)
213 /* error condition caught */
214 return WAITCONN_FDSET_ERROR;
218 return WAITCONN_CONNECTED;
221 static CURLcode bindlocal(struct connectdata *conn,
222 curl_socket_t sockfd, int af)
224 struct SessionHandle *data = conn->data;
226 struct Curl_sockaddr_storage sa;
227 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
228 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
229 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
231 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
234 struct Curl_dns_entry *h=NULL;
235 unsigned short port = data->set.localport; /* use this port number, 0 for
237 /* how many port numbers to try to bind to, increasing one at a time */
238 int portnum = data->set.localportrange;
239 const char *dev = data->set.str[STRING_DEVICE];
241 char myhost[256] = "";
242 int done = 0; /* -1 for error, 1 for address found */
243 bool is_interface = FALSE;
244 bool is_host = FALSE;
245 static const char *if_prefix = "if!";
246 static const char *host_prefix = "host!";
248 /*************************************************************
249 * Select device to bind socket to
250 *************************************************************/
252 /* no local kind of binding was requested */
255 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
257 if(dev && (strlen(dev)<255) ) {
258 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
259 dev += strlen(if_prefix);
262 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
263 dev += strlen(host_prefix);
268 if(!is_host && (is_interface || Curl_if_is_interface_name(dev))) {
269 if(Curl_if2ip(af, dev, myhost, sizeof(myhost)) == NULL)
270 return CURLE_INTERFACE_FAILED;
273 * We now have the numerical IP address in the 'myhost' buffer
275 infof(data, "Local Interface %s is ip %s using address family %i\n",
279 #ifdef SO_BINDTODEVICE
280 /* I am not sure any other OSs than Linux that provide this feature, and
281 * at the least I cannot test. --Ben
283 * This feature allows one to tightly bind the local socket to a
284 * particular interface. This will force even requests to other local
285 * interfaces to go out the external interface.
288 * Only bind to the interface when specified as interface, not just as a
289 * hostname or ip address.
291 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
292 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
294 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
295 " will do regular bind\n",
296 dev, error, Curl_strerror(conn, error));
297 /* This is typically "errno 1, error: Operation not permitted" if
298 you're not running as root or another suitable privileged user */
304 * This was not an interface, resolve the name as a host name
307 * Temporarily force name resolution to use only the address type
308 * of the connection. The resolve functions should really be changed
309 * to take a type parameter instead.
311 long ipver = conn->ip_version;
315 conn->ip_version = CURL_IPRESOLVE_V4;
317 else if(af == AF_INET6)
318 conn->ip_version = CURL_IPRESOLVE_V6;
321 rc = Curl_resolv(conn, dev, 0, &h);
322 if(rc == CURLRESOLV_PENDING)
323 (void)Curl_resolver_wait_resolv(conn, &h);
324 conn->ip_version = ipver;
327 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
328 Curl_printable_address(h->addr, myhost, sizeof(myhost));
329 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
330 dev, af, myhost, h->addr->ai_family);
331 Curl_resolv_unlock(data, h);
336 * provided dev was no interface (or interfaces are not supported
337 * e.g. solaris) no ip address and no domain we fail here
346 if((af == AF_INET6) &&
347 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
348 si6->sin6_family = AF_INET6;
349 si6->sin6_port = htons(port);
350 sizeof_sa = sizeof(struct sockaddr_in6);
355 if((af == AF_INET) &&
356 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
357 si4->sin_family = AF_INET;
358 si4->sin_port = htons(port);
359 sizeof_sa = sizeof(struct sockaddr_in);
364 failf(data, "Couldn't bind to '%s'", dev);
365 return CURLE_INTERFACE_FAILED;
369 /* no device was given, prepare sa to match af's needs */
372 si6->sin6_family = AF_INET6;
373 si6->sin6_port = htons(port);
374 sizeof_sa = sizeof(struct sockaddr_in6);
379 si4->sin_family = AF_INET;
380 si4->sin_port = htons(port);
381 sizeof_sa = sizeof(struct sockaddr_in);
386 if(bind(sockfd, sock, sizeof_sa) >= 0) {
387 /* we succeeded to bind */
388 struct Curl_sockaddr_storage add;
389 curl_socklen_t size = sizeof(add);
390 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
391 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
392 data->state.os_errno = error = SOCKERRNO;
393 failf(data, "getsockname() failed with errno %d: %s",
394 error, Curl_strerror(conn, error));
395 return CURLE_INTERFACE_FAILED;
397 infof(data, "Local port: %hu\n", port);
398 conn->bits.bound = TRUE;
403 infof(data, "Bind to local port %hu failed, trying next\n", port);
404 port++; /* try next port */
405 /* We re-use/clobber the port variable here below */
406 if(sock->sa_family == AF_INET)
407 si4->sin_port = ntohs(port);
410 si6->sin6_port = ntohs(port);
417 data->state.os_errno = error = SOCKERRNO;
418 failf(data, "bind failed with errno %d: %s",
419 error, Curl_strerror(conn, error));
421 return CURLE_INTERFACE_FAILED;
425 * verifyconnect() returns TRUE if the connect really has happened.
427 static bool verifyconnect(curl_socket_t sockfd, int *error)
432 curl_socklen_t errSize = sizeof(err);
436 * In October 2003 we effectively nullified this function on Windows due to
437 * problems with it using all CPU in multi-threaded cases.
439 * In May 2004, we bring it back to offer more info back on connect failures.
440 * Gisle Vanem could reproduce the former problems with this function, but
441 * could avoid them by adding this SleepEx() call below:
443 * "I don't have Rational Quantify, but the hint from his post was
444 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
445 * just Sleep(0) would be enough?) would release whatever
446 * mutex/critical-section the ntdll call is waiting on.
448 * Someone got to verify this on Win-NT 4.0, 2000."
459 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
462 /* Old WinCE versions don't support SO_ERROR */
463 if(WSAENOPROTOOPT == err) {
469 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
470 if(EBADIOCTL == err) {
475 if((0 == err) || (EISCONN == err))
476 /* we are connected, awesome! */
479 /* This wasn't a successful connect */
491 /* Used within the multi interface. Try next IP address, return TRUE if no
492 more address exists or error */
493 static CURLcode trynextip(struct connectdata *conn,
497 curl_socket_t sockfd;
500 /* First clean up after the failed socket.
501 Don't close it yet to ensure that the next IP's socket gets a different
502 file descriptor, which can prevent bugs when the curl_multi_socket_action
503 interface is used with certain select() replacements such as kqueue. */
504 curl_socket_t fd_to_close = conn->sock[sockindex];
505 conn->sock[sockindex] = CURL_SOCKET_BAD;
508 if(sockindex != FIRSTSOCKET) {
509 Curl_closesocket(conn, fd_to_close);
510 return CURLE_COULDNT_CONNECT; /* no next */
513 /* try the next address */
514 ai = conn->ip_addr->ai_next;
517 CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected);
520 if(sockfd != CURL_SOCKET_BAD) {
521 /* store the new socket descriptor */
522 conn->sock[sockindex] = sockfd;
524 Curl_closesocket(conn, fd_to_close);
529 Curl_closesocket(conn, fd_to_close);
530 return CURLE_COULDNT_CONNECT;
533 /* Copies connection info into the session handle to make it available
534 when the session handle is no longer associated with a connection. */
535 void Curl_persistconninfo(struct connectdata *conn)
537 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
538 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
539 conn->data->info.conn_primary_port = conn->primary_port;
540 conn->data->info.conn_local_port = conn->local_port;
543 /* retrieves ip address and port from a sockaddr structure */
544 static bool getaddressinfo(struct sockaddr* sa, char* addr,
547 unsigned short us_port;
548 struct sockaddr_in* si = NULL;
550 struct sockaddr_in6* si6 = NULL;
552 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
553 struct sockaddr_un* su = NULL;
556 switch (sa->sa_family) {
558 si = (struct sockaddr_in*) sa;
559 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
560 addr, MAX_IPADR_LEN)) {
561 us_port = ntohs(si->sin_port);
568 si6 = (struct sockaddr_in6*)sa;
569 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
570 addr, MAX_IPADR_LEN)) {
571 us_port = ntohs(si6->sin6_port);
577 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
579 su = (struct sockaddr_un*)sa;
580 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
594 /* retrieves the start/end point information of a socket of an established
596 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
600 struct Curl_sockaddr_storage ssrem;
601 struct Curl_sockaddr_storage ssloc;
602 struct SessionHandle *data = conn->data;
604 if(!conn->bits.reuse) {
606 len = sizeof(struct Curl_sockaddr_storage);
607 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
609 failf(data, "getpeername() failed with errno %d: %s",
610 error, Curl_strerror(conn, error));
614 len = sizeof(struct Curl_sockaddr_storage);
615 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
617 failf(data, "getsockname() failed with errno %d: %s",
618 error, Curl_strerror(conn, error));
622 if(!getaddressinfo((struct sockaddr*)&ssrem,
623 conn->primary_ip, &conn->primary_port)) {
625 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
626 error, Curl_strerror(conn, error));
630 if(!getaddressinfo((struct sockaddr*)&ssloc,
631 conn->local_ip, &conn->local_port)) {
633 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
634 error, Curl_strerror(conn, error));
640 /* persist connection info in session handle */
641 Curl_persistconninfo(conn);
645 * Curl_is_connected() is used from the multi interface to check if the
646 * firstsocket has connected.
649 CURLcode Curl_is_connected(struct connectdata *conn,
654 struct SessionHandle *data = conn->data;
655 CURLcode code = CURLE_OK;
656 curl_socket_t sockfd = conn->sock[sockindex];
657 long allow = DEFAULT_CONNECT_TIMEOUT;
661 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
663 *connected = FALSE; /* a very negative world view is best */
665 if(conn->bits.tcpconnect[sockindex]) {
666 /* we are connected already! */
673 /* figure out how long time we have left to connect */
674 allow = Curl_timeleft(data, &now, TRUE);
677 /* time-out, bail out, go home */
678 failf(data, "Connection time-out");
679 return CURLE_OPERATION_TIMEDOUT;
682 /* check for connect without timeout as we want to return immediately */
683 rc = waitconnect(conn, sockfd, 0);
684 if(WAITCONN_TIMEOUT == rc) {
685 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
686 infof(data, "After %ldms connect time, move on!\n",
687 conn->timeoutms_per_addr);
691 /* not an error, but also no connection yet */
695 if(WAITCONN_CONNECTED == rc) {
696 if(verifyconnect(sockfd, &error)) {
697 /* we are connected with TCP, awesome! */
699 /* see if we need to do any proxy magic first once we connected */
700 code = Curl_connected_proxy(conn);
704 conn->bits.tcpconnect[sockindex] = TRUE;
706 if(sockindex == FIRSTSOCKET)
707 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
708 Curl_verboseconnect(conn);
709 Curl_updateconninfo(conn, sockfd);
713 /* nope, not connected for real */
716 /* nope, not connected */
717 if(WAITCONN_FDSET_ERROR == rc) {
718 (void)verifyconnect(sockfd, &error);
719 infof(data, "%s\n",Curl_strerror(conn, error));
722 infof(data, "Connection failed\n");
726 * The connection failed here, we should attempt to connect to the "next
727 * address" for the given host. But first remember the latest error.
730 data->state.os_errno = error;
731 SET_SOCKERRNO(error);
735 code = trynextip(conn, sockindex, connected);
739 data->state.os_errno = error;
740 failf(data, "Failed connect to %s:%ld; %s",
741 conn->host.name, conn->port, Curl_strerror(conn, error));
747 static void tcpnodelay(struct connectdata *conn,
748 curl_socket_t sockfd)
751 struct SessionHandle *data= conn->data;
752 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
753 int level = IPPROTO_TCP;
756 /* The use of getprotobyname() is disabled since it isn't thread-safe on
757 numerous systems. On these getprotobyname_r() should be used instead, but
758 that exists in at least one 4 arg version and one 5 arg version, and
759 since the proto number rarely changes anyway we now just use the hard
760 coded number. The "proper" fix would need a configure check for the
761 correct function much in the same style the gethostbyname_r versions are
763 struct protoent *pe = getprotobyname("tcp");
768 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
770 infof(data, "Could not set TCP_NODELAY: %s\n",
771 Curl_strerror(conn, SOCKERRNO));
773 infof(data,"TCP_NODELAY set\n");
781 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
782 sending data to a dead peer (instead of relying on the 4th argument to send
783 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
785 static void nosigpipe(struct connectdata *conn,
786 curl_socket_t sockfd)
788 struct SessionHandle *data= conn->data;
790 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
792 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
793 Curl_strerror(conn, SOCKERRNO));
796 #define nosigpipe(x,y) Curl_nop_stmt
800 /* When you run a program that uses the Windows Sockets API, you may
801 experience slow performance when you copy data to a TCP server.
803 http://support.microsoft.com/kb/823764
805 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
809 void Curl_sndbufset(curl_socket_t sockfd)
811 int val = CURL_MAX_WRITE_SIZE + 32;
813 int curlen = sizeof(curval);
815 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
819 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
827 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
828 * CURL_SOCKET_BAD. Other errors will however return proper errors.
830 * singleipconnect() connects to the given IP only, and it may return without
831 * having connected if used from the multi interface.
834 singleipconnect(struct connectdata *conn,
835 const Curl_addrinfo *ai,
837 curl_socket_t *sockp,
840 struct Curl_sockaddr_ex addr;
843 bool isconnected = FALSE;
844 struct SessionHandle *data = conn->data;
845 curl_socket_t sockfd;
846 CURLcode res = CURLE_OK;
848 *sockp = CURL_SOCKET_BAD;
849 *connected = FALSE; /* default is not connected */
851 res = Curl_socket(conn, ai, &addr, &sockfd);
855 /* store remote address and port used in this connection attempt */
856 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
857 conn->primary_ip, &conn->primary_port)) {
858 /* malformed address or bug in inet_ntop, try next address */
860 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
861 error, Curl_strerror(conn, error));
862 Curl_closesocket(conn, sockfd);
865 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
866 infof(data, " Trying %s... ", conn->ip_addr_str);
868 Curl_persistconninfo(conn);
870 if(data->set.tcp_nodelay)
871 tcpnodelay(conn, sockfd);
873 nosigpipe(conn, sockfd);
875 Curl_sndbufset(sockfd);
877 if(data->set.fsockopt) {
878 /* activate callback for setting socket options */
879 error = data->set.fsockopt(data->set.sockopt_client,
883 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
886 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
887 return CURLE_ABORTED_BY_CALLBACK;
891 /* possibly bind the local end to an IP, interface or port */
892 res = bindlocal(conn, sockfd, addr.family);
894 Curl_closesocket(conn, sockfd); /* close socket and bail out */
898 /* set socket non-blocking */
899 curlx_nonblock(sockfd, TRUE);
901 /* Connect TCP sockets, bind UDP */
902 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
903 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
906 conn->connecttime = Curl_tvnow();
907 if(conn->num_addr > 1)
908 Curl_expire(data, conn->timeoutms_per_addr);
918 #if (EAGAIN) != (EWOULDBLOCK)
919 /* On some platforms EAGAIN and EWOULDBLOCK are the
920 * same value, and on others they are different, hence
926 rc = waitconnect(conn, sockfd, timeout_ms);
927 if(WAITCONN_ABORTED == rc) {
928 Curl_closesocket(conn, sockfd);
929 return CURLE_ABORTED_BY_CALLBACK;
933 /* unknown error, fallthrough and try another address! */
934 failf(data, "Failed to connect to %s: %s",
935 conn->ip_addr_str, Curl_strerror(conn,error));
936 data->state.os_errno = error;
941 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
942 connect(). We can be sure of this since connect() cannot return 1. */
943 if((WAITCONN_TIMEOUT == rc) &&
944 (data->state.used_interface == Curl_if_multi)) {
945 /* Timeout when running the multi interface */
951 isconnected = verifyconnect(sockfd, &error);
953 if(!rc && isconnected) {
954 /* we are connected, awesome! */
955 *connected = TRUE; /* this is a true connect */
956 infof(data, "connected\n");
958 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
961 Curl_updateconninfo(conn, sockfd);
965 else if(WAITCONN_TIMEOUT == rc)
966 infof(data, "Timeout\n");
968 data->state.os_errno = error;
969 infof(data, "%s\n", Curl_strerror(conn, error));
972 /* connect failed or timed out */
973 Curl_closesocket(conn, sockfd);
979 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
980 * There might be more than one IP address to try out. Fill in the passed
981 * pointer with the connected socket.
984 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
985 const struct Curl_dns_entry *remotehost,
986 curl_socket_t *sockconn, /* the connected socket */
987 Curl_addrinfo **addr, /* the one we used */
988 bool *connected) /* really connected? */
990 struct SessionHandle *data = conn->data;
991 curl_socket_t sockfd = CURL_SOCKET_BAD;
994 Curl_addrinfo *curr_addr;
996 struct timeval after;
997 struct timeval before = Curl_tvnow();
999 /*************************************************************
1000 * Figure out what maximum time we have left
1001 *************************************************************/
1004 DEBUGASSERT(sockconn);
1005 *connected = FALSE; /* default to not connected */
1007 /* get the timeout left */
1008 timeout_ms = Curl_timeleft(data, &before, TRUE);
1010 if(timeout_ms < 0) {
1011 /* a precaution, no need to continue if time already is up */
1012 failf(data, "Connection time-out");
1013 return CURLE_OPERATION_TIMEDOUT;
1016 /* Max time for each address */
1017 conn->num_addr = Curl_num_addresses(remotehost->addr);
1018 conn->timeoutms_per_addr = timeout_ms / conn->num_addr;
1020 ai = remotehost->addr;
1022 /* Below is the loop that attempts to connect to all IP-addresses we
1023 * know for the given host. One by one until one IP succeeds.
1027 * Connecting with a Curl_addrinfo chain
1029 for(curr_addr = ai, aliasindex=0; curr_addr;
1030 curr_addr = curr_addr->ai_next, aliasindex++) {
1032 /* start connecting to the IP curr_addr points to */
1034 singleipconnect(conn, curr_addr,
1035 /* don't hang when doing multi */
1036 (data->state.used_interface == Curl_if_multi)?0:
1037 conn->timeoutms_per_addr, &sockfd, connected);
1042 if(sockfd != CURL_SOCKET_BAD)
1045 /* get a new timeout for next attempt */
1046 after = Curl_tvnow();
1047 timeout_ms -= Curl_tvdiff(after, before);
1048 if(timeout_ms < 0) {
1049 failf(data, "connect() timed out!");
1050 return CURLE_OPERATION_TIMEDOUT;
1053 } /* end of connect-to-each-address loop */
1055 *sockconn = sockfd; /* the socket descriptor we've connected */
1057 if(sockfd == CURL_SOCKET_BAD) {
1058 /* no good connect was made */
1059 failf(data, "couldn't connect to host");
1060 return CURLE_COULDNT_CONNECT;
1063 /* leave the socket in non-blocking mode */
1065 /* store the address we use */
1069 data->info.numconnects++; /* to track the number of connections made */
1075 * Used to extract socket and connectdata struct for the most recent
1076 * transfer on the given SessionHandle.
1078 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1080 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1081 struct connectdata **connp)
1083 curl_socket_t sockfd;
1087 if((data->state.lastconnect != -1) &&
1088 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1089 struct connectdata *c =
1090 data->state.connc->connects[data->state.lastconnect];
1092 /* only store this if the caller cares for it */
1094 sockfd = c->sock[FIRSTSOCKET];
1095 /* we have a socket connected, let's determine if the server shut down */
1096 /* determine if ssl */
1097 if(c->ssl[FIRSTSOCKET].use) {
1098 /* use the SSL context */
1099 if(!Curl_ssl_check_cxn(c))
1100 return CURL_SOCKET_BAD; /* FIN received */
1102 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1105 /* use the socket */
1107 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1108 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1109 return CURL_SOCKET_BAD; /* FIN received */
1115 return CURL_SOCKET_BAD;
1123 * 'conn' can be NULL, beware!
1125 int Curl_closesocket(struct connectdata *conn,
1128 if(conn && conn->fclosesocket) {
1129 if((sock == conn->sock[SECONDARYSOCKET]) &&
1130 conn->sock_accepted[SECONDARYSOCKET])
1131 /* if this socket matches the second socket, and that was created with
1132 accept, then we MUST NOT call the callback but clear the accepted
1134 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1136 return conn->fclosesocket(conn->closesocket_client, sock);
1138 return sclose(sock);
1142 * Create a socket based on info from 'conn' and 'ai'.
1144 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1145 * 'sockfd' must be a pointer to a socket descriptor.
1147 * If the open socket callback is set, used that!
1150 CURLcode Curl_socket(struct connectdata *conn,
1151 const Curl_addrinfo *ai,
1152 struct Curl_sockaddr_ex *addr,
1153 curl_socket_t *sockfd)
1155 struct SessionHandle *data = conn->data;
1156 struct Curl_sockaddr_ex dummy;
1159 /* if the caller doesn't want info back, use a local temp copy */
1163 * The Curl_sockaddr_ex structure is basically libcurl's external API
1164 * curl_sockaddr structure with enough space available to directly hold
1165 * any protocol-specific address structures. The variable declared here
1166 * will be used to pass / receive data to/from the fopensocket callback
1167 * if this has been set, before that, it is initialized from parameters.
1170 addr->family = ai->ai_family;
1171 addr->socktype = conn->socktype;
1172 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1173 addr->addrlen = ai->ai_addrlen;
1175 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1176 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1177 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1179 if(data->set.fopensocket)
1181 * If the opensocket callback is set, all the destination address
1182 * information is passed to the callback. Depending on this information the
1183 * callback may opt to abort the connection, this is indicated returning
1184 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1185 * the callback returns a valid socket the destination address information
1186 * might have been changed and this 'new' address will actually be used
1189 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1191 (struct curl_sockaddr *)addr);
1193 /* opensocket callback not set, so simply create the socket now */
1194 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1196 if(*sockfd == CURL_SOCKET_BAD)
1197 /* no socket, no connection */
1198 return CURLE_FAILED_INIT;
1200 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1201 if(conn->scope && (addr->family == AF_INET6)) {
1202 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1203 sa6->sin6_scope_id = conn->scope;