1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2012, 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 conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
737 code = trynextip(conn, sockindex, connected);
741 data->state.os_errno = error;
742 failf(data, "Failed connect to %s:%ld; %s",
743 conn->host.name, conn->port, Curl_strerror(conn, error));
749 static void tcpnodelay(struct connectdata *conn,
750 curl_socket_t sockfd)
753 struct SessionHandle *data= conn->data;
754 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
755 int level = IPPROTO_TCP;
758 /* The use of getprotobyname() is disabled since it isn't thread-safe on
759 numerous systems. On these getprotobyname_r() should be used instead, but
760 that exists in at least one 4 arg version and one 5 arg version, and
761 since the proto number rarely changes anyway we now just use the hard
762 coded number. The "proper" fix would need a configure check for the
763 correct function much in the same style the gethostbyname_r versions are
765 struct protoent *pe = getprotobyname("tcp");
770 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
772 infof(data, "Could not set TCP_NODELAY: %s\n",
773 Curl_strerror(conn, SOCKERRNO));
775 infof(data,"TCP_NODELAY set\n");
783 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
784 sending data to a dead peer (instead of relying on the 4th argument to send
785 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
787 static void nosigpipe(struct connectdata *conn,
788 curl_socket_t sockfd)
790 struct SessionHandle *data= conn->data;
792 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
794 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
795 Curl_strerror(conn, SOCKERRNO));
798 #define nosigpipe(x,y) Curl_nop_stmt
802 /* When you run a program that uses the Windows Sockets API, you may
803 experience slow performance when you copy data to a TCP server.
805 http://support.microsoft.com/kb/823764
807 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
811 void Curl_sndbufset(curl_socket_t sockfd)
813 int val = CURL_MAX_WRITE_SIZE + 32;
815 int curlen = sizeof(curval);
817 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
821 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
829 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
830 * CURL_SOCKET_BAD. Other errors will however return proper errors.
832 * singleipconnect() connects to the given IP only, and it may return without
833 * having connected if used from the multi interface.
836 singleipconnect(struct connectdata *conn,
837 const Curl_addrinfo *ai,
839 curl_socket_t *sockp,
842 struct Curl_sockaddr_ex addr;
845 bool isconnected = FALSE;
846 struct SessionHandle *data = conn->data;
847 curl_socket_t sockfd;
848 CURLcode res = CURLE_OK;
850 *sockp = CURL_SOCKET_BAD;
851 *connected = FALSE; /* default is not connected */
853 res = Curl_socket(conn, ai, &addr, &sockfd);
857 /* store remote address and port used in this connection attempt */
858 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
859 conn->primary_ip, &conn->primary_port)) {
860 /* malformed address or bug in inet_ntop, try next address */
862 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
863 error, Curl_strerror(conn, error));
864 Curl_closesocket(conn, sockfd);
867 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
868 infof(data, " Trying %s...\n", conn->ip_addr_str);
870 Curl_persistconninfo(conn);
872 if(data->set.tcp_nodelay)
873 tcpnodelay(conn, sockfd);
875 nosigpipe(conn, sockfd);
877 Curl_sndbufset(sockfd);
879 if(data->set.fsockopt) {
880 /* activate callback for setting socket options */
881 error = data->set.fsockopt(data->set.sockopt_client,
885 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
888 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
889 return CURLE_ABORTED_BY_CALLBACK;
893 /* possibly bind the local end to an IP, interface or port */
894 res = bindlocal(conn, sockfd, addr.family);
896 Curl_closesocket(conn, sockfd); /* close socket and bail out */
900 /* set socket non-blocking */
901 curlx_nonblock(sockfd, TRUE);
903 /* Connect TCP sockets, bind UDP */
904 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
905 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
908 conn->connecttime = Curl_tvnow();
909 if(conn->num_addr > 1)
910 Curl_expire(data, conn->timeoutms_per_addr);
920 #if (EAGAIN) != (EWOULDBLOCK)
921 /* On some platforms EAGAIN and EWOULDBLOCK are the
922 * same value, and on others they are different, hence
928 rc = waitconnect(conn, sockfd, timeout_ms);
929 if(WAITCONN_ABORTED == rc) {
930 Curl_closesocket(conn, sockfd);
931 return CURLE_ABORTED_BY_CALLBACK;
935 /* unknown error, fallthrough and try another address! */
936 failf(data, "Failed to connect to %s: %s",
937 conn->ip_addr_str, Curl_strerror(conn,error));
938 data->state.os_errno = error;
943 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
944 connect(). We can be sure of this since connect() cannot return 1. */
945 if((WAITCONN_TIMEOUT == rc) &&
946 (data->state.used_interface == Curl_if_multi)) {
947 /* Timeout when running the multi interface */
953 isconnected = verifyconnect(sockfd, &error);
955 if(!rc && isconnected) {
956 /* we are connected, awesome! */
957 *connected = TRUE; /* this is a true connect */
958 infof(data, "connected\n");
960 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
963 Curl_updateconninfo(conn, sockfd);
967 else if(WAITCONN_TIMEOUT == rc)
968 infof(data, "Timeout\n");
970 data->state.os_errno = error;
971 infof(data, "%s\n", Curl_strerror(conn, error));
974 /* connect failed or timed out */
975 Curl_closesocket(conn, sockfd);
981 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
982 * There might be more than one IP address to try out. Fill in the passed
983 * pointer with the connected socket.
986 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
987 const struct Curl_dns_entry *remotehost,
988 curl_socket_t *sockconn, /* the connected socket */
989 Curl_addrinfo **addr, /* the one we used */
990 bool *connected) /* really connected? */
992 struct SessionHandle *data = conn->data;
993 curl_socket_t sockfd = CURL_SOCKET_BAD;
995 Curl_addrinfo *curr_addr;
997 struct timeval after;
998 struct timeval before = Curl_tvnow();
1000 /*************************************************************
1001 * Figure out what maximum time we have left
1002 *************************************************************/
1005 DEBUGASSERT(sockconn);
1006 *connected = FALSE; /* default to not connected */
1008 /* get the timeout left */
1009 timeout_ms = Curl_timeleft(data, &before, TRUE);
1011 if(timeout_ms < 0) {
1012 /* a precaution, no need to continue if time already is up */
1013 failf(data, "Connection time-out");
1014 return CURLE_OPERATION_TIMEDOUT;
1017 conn->num_addr = Curl_num_addresses(remotehost->addr);
1019 ai = remotehost->addr;
1021 /* Below is the loop that attempts to connect to all IP-addresses we
1022 * know for the given host. One by one until one IP succeeds.
1026 * Connecting with a Curl_addrinfo chain
1028 for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
1031 /* Max time for the next address */
1032 conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
1033 timeout_ms : timeout_ms / 2;
1035 /* start connecting to the IP curr_addr points to */
1036 res = singleipconnect(conn, curr_addr,
1037 /* don't hang when doing multi */
1038 (data->state.used_interface == Curl_if_multi)?0:
1039 conn->timeoutms_per_addr, &sockfd, connected);
1043 if(sockfd != CURL_SOCKET_BAD)
1046 /* get a new timeout for next attempt */
1047 after = Curl_tvnow();
1048 timeout_ms -= Curl_tvdiff(after, before);
1049 if(timeout_ms < 0) {
1050 failf(data, "connect() timed out!");
1051 return CURLE_OPERATION_TIMEDOUT;
1054 } /* end of connect-to-each-address loop */
1056 *sockconn = sockfd; /* the socket descriptor we've connected */
1058 if(sockfd == CURL_SOCKET_BAD) {
1059 /* no good connect was made */
1060 failf(data, "couldn't connect to host");
1061 return CURLE_COULDNT_CONNECT;
1064 /* leave the socket in non-blocking mode */
1066 /* store the address we use */
1070 data->info.numconnects++; /* to track the number of connections made */
1076 * Used to extract socket and connectdata struct for the most recent
1077 * transfer on the given SessionHandle.
1079 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1081 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1082 struct connectdata **connp)
1084 curl_socket_t sockfd;
1088 if((data->state.lastconnect != -1) &&
1089 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1090 struct connectdata *c =
1091 data->state.connc->connects[data->state.lastconnect];
1093 /* only store this if the caller cares for it */
1095 sockfd = c->sock[FIRSTSOCKET];
1096 /* we have a socket connected, let's determine if the server shut down */
1097 /* determine if ssl */
1098 if(c->ssl[FIRSTSOCKET].use) {
1099 /* use the SSL context */
1100 if(!Curl_ssl_check_cxn(c))
1101 return CURL_SOCKET_BAD; /* FIN received */
1103 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1106 /* use the socket */
1108 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1109 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1110 return CURL_SOCKET_BAD; /* FIN received */
1116 return CURL_SOCKET_BAD;
1124 * 'conn' can be NULL, beware!
1126 int Curl_closesocket(struct connectdata *conn,
1129 if(conn && conn->fclosesocket) {
1130 if((sock == conn->sock[SECONDARYSOCKET]) &&
1131 conn->sock_accepted[SECONDARYSOCKET])
1132 /* if this socket matches the second socket, and that was created with
1133 accept, then we MUST NOT call the callback but clear the accepted
1135 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1137 return conn->fclosesocket(conn->closesocket_client, sock);
1139 return sclose(sock);
1143 * Create a socket based on info from 'conn' and 'ai'.
1145 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1146 * 'sockfd' must be a pointer to a socket descriptor.
1148 * If the open socket callback is set, used that!
1151 CURLcode Curl_socket(struct connectdata *conn,
1152 const Curl_addrinfo *ai,
1153 struct Curl_sockaddr_ex *addr,
1154 curl_socket_t *sockfd)
1156 struct SessionHandle *data = conn->data;
1157 struct Curl_sockaddr_ex dummy;
1160 /* if the caller doesn't want info back, use a local temp copy */
1164 * The Curl_sockaddr_ex structure is basically libcurl's external API
1165 * curl_sockaddr structure with enough space available to directly hold
1166 * any protocol-specific address structures. The variable declared here
1167 * will be used to pass / receive data to/from the fopensocket callback
1168 * if this has been set, before that, it is initialized from parameters.
1171 addr->family = ai->ai_family;
1172 addr->socktype = conn->socktype;
1173 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1174 addr->addrlen = ai->ai_addrlen;
1176 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1177 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1178 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1180 if(data->set.fopensocket)
1182 * If the opensocket callback is set, all the destination address
1183 * information is passed to the callback. Depending on this information the
1184 * callback may opt to abort the connection, this is indicated returning
1185 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1186 * the callback returns a valid socket the destination address information
1187 * might have been changed and this 'new' address will actually be used
1190 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1192 (struct curl_sockaddr *)addr);
1194 /* opensocket callback not set, so simply create the socket now */
1195 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1197 if(*sockfd == CURL_SOCKET_BAD)
1198 /* no socket, no connection */
1199 return CURLE_FAILED_INIT;
1201 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1202 if(conn->scope && (addr->family == AF_INET6)) {
1203 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1204 sa6->sin6_scope_id = conn->scope;