1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2013, 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 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #include <sys/un.h> /* for sockaddr_un */
31 #ifdef HAVE_NETINET_TCP_H
32 #include <netinet/tcp.h> /* for TCP_NODELAY */
34 #ifdef HAVE_SYS_IOCTL_H
35 #include <sys/ioctl.h>
43 #ifdef HAVE_ARPA_INET_H
44 #include <arpa/inet.h>
47 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
48 #include <sys/filio.h>
52 #define in_addr_t unsigned long
59 #define _MPRINTF_REPLACE /* use our functions only */
60 #include <curl/mprintf.h>
67 #include "curl_memory.h"
69 #include "url.h" /* for Curl_safefree() */
71 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
72 #include "inet_ntop.h"
73 #include "inet_pton.h"
74 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
77 #include "conncache.h"
78 #include "multihandle.h"
80 /* The last #include file should be: */
84 /* This isn't actually supported under Symbian OS */
88 static bool verifyconnect(curl_socket_t sockfd, int *error);
91 /* DragonFlyBSD uses millisecond as KEEPIDLE and KEEPINTVL units */
92 #define KEEPALIVE_FACTOR(x) (x *= 1000)
94 #define KEEPALIVE_FACTOR(x)
98 tcpkeepalive(struct SessionHandle *data,
101 int optval = data->set.tcp_keepalive?1:0;
103 /* only set IDLE and INTVL if setting KEEPALIVE is successful */
104 if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
105 (void *)&optval, sizeof(optval)) < 0) {
106 infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
110 optval = curlx_sltosi(data->set.tcp_keepidle);
111 KEEPALIVE_FACTOR(optval);
112 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
113 (void *)&optval, sizeof(optval)) < 0) {
114 infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
118 optval = curlx_sltosi(data->set.tcp_keepintvl);
119 KEEPALIVE_FACTOR(optval);
120 if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
121 (void *)&optval, sizeof(optval)) < 0) {
122 infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
129 singleipconnect(struct connectdata *conn,
130 const Curl_addrinfo *ai, /* start connecting to this */
136 * Curl_timeleft() returns the amount of milliseconds left allowed for the
137 * transfer/connection. If the value is negative, the timeout time has already
140 * The start time is stored in progress.t_startsingle - as set with
141 * Curl_pgrsTime(..., TIMER_STARTSINGLE);
143 * If 'nowp' is non-NULL, it points to the current time.
144 * 'duringconnect' is FALSE if not during a connect, as then of course the
145 * connect timeout is not taken into account!
149 long Curl_timeleft(struct SessionHandle *data,
150 struct timeval *nowp,
154 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
157 /* if a timeout is set, use the most restrictive one */
159 if(data->set.timeout > 0)
161 if(duringconnect && (data->set.connecttimeout > 0))
164 switch (timeout_set) {
166 timeout_ms = data->set.timeout;
169 timeout_ms = data->set.connecttimeout;
172 if(data->set.timeout < data->set.connecttimeout)
173 timeout_ms = data->set.timeout;
175 timeout_ms = data->set.connecttimeout;
178 /* use the default */
180 /* if we're not during connect, there's no default timeout so if we're
181 at zero we better just return zero and not make it a negative number
192 /* subtract elapsed time */
193 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
195 /* avoid returning 0 as that means no timeout! */
202 * waitconnect() waits for a TCP connect on the given socket for the specified
203 * number if milliseconds. It returns:
206 #define WAITCONN_CONNECTED 0
207 #define WAITCONN_SELECT_ERROR -1
208 #define WAITCONN_TIMEOUT 1
209 #define WAITCONN_FDSET_ERROR 2
210 #define WAITCONN_ABORTED 3
213 int waitconnect(struct connectdata *conn,
214 curl_socket_t sockfd, /* socket */
219 /* Call this function once now, and ignore the results. We do this to
220 "clear" the error state on the socket so that we can later read it
221 reliably. This is reported necessary on the MPE/iX operating system. */
222 (void)verifyconnect(sockfd, NULL);
227 /* now select() until we get connect or timeout */
228 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, timeout_msec>1000?
230 if(Curl_pgrsUpdate(conn))
231 return WAITCONN_ABORTED;
234 /* error, no connect here, try next */
235 return WAITCONN_SELECT_ERROR;
239 timeout_msec -= 1000;
240 if(timeout_msec <= 0)
241 return WAITCONN_TIMEOUT;
246 if(rc & CURL_CSELECT_ERR)
247 /* error condition caught */
248 return WAITCONN_FDSET_ERROR;
252 return WAITCONN_CONNECTED;
255 static CURLcode bindlocal(struct connectdata *conn,
256 curl_socket_t sockfd, int af)
258 struct SessionHandle *data = conn->data;
260 struct Curl_sockaddr_storage sa;
261 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
262 curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
263 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
265 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
268 struct Curl_dns_entry *h=NULL;
269 unsigned short port = data->set.localport; /* use this port number, 0 for
271 /* how many port numbers to try to bind to, increasing one at a time */
272 int portnum = data->set.localportrange;
273 const char *dev = data->set.str[STRING_DEVICE];
275 char myhost[256] = "";
276 int done = 0; /* -1 for error, 1 for address found */
277 bool is_interface = FALSE;
278 bool is_host = FALSE;
279 static const char *if_prefix = "if!";
280 static const char *host_prefix = "host!";
282 /*************************************************************
283 * Select device to bind socket to
284 *************************************************************/
286 /* no local kind of binding was requested */
289 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
291 if(dev && (strlen(dev)<255) ) {
292 if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
293 dev += strlen(if_prefix);
296 else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
297 dev += strlen(host_prefix);
302 if(!is_host && (is_interface || Curl_if_is_interface_name(dev))) {
303 if(Curl_if2ip(af, dev, myhost, sizeof(myhost)) == NULL)
304 return CURLE_INTERFACE_FAILED;
307 * We now have the numerical IP address in the 'myhost' buffer
309 infof(data, "Local Interface %s is ip %s using address family %i\n",
313 #ifdef SO_BINDTODEVICE
314 /* I am not sure any other OSs than Linux that provide this feature, and
315 * at the least I cannot test. --Ben
317 * This feature allows one to tightly bind the local socket to a
318 * particular interface. This will force even requests to other local
319 * interfaces to go out the external interface.
322 * Only bind to the interface when specified as interface, not just as a
323 * hostname or ip address.
325 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
326 dev, (curl_socklen_t)strlen(dev)+1) != 0) {
328 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
329 " will do regular bind\n",
330 dev, error, Curl_strerror(conn, error));
331 /* This is typically "errno 1, error: Operation not permitted" if
332 you're not running as root or another suitable privileged user */
338 * This was not an interface, resolve the name as a host name
341 * Temporarily force name resolution to use only the address type
342 * of the connection. The resolve functions should really be changed
343 * to take a type parameter instead.
345 long ipver = conn->ip_version;
349 conn->ip_version = CURL_IPRESOLVE_V4;
351 else if(af == AF_INET6)
352 conn->ip_version = CURL_IPRESOLVE_V6;
355 rc = Curl_resolv(conn, dev, 0, &h);
356 if(rc == CURLRESOLV_PENDING)
357 (void)Curl_resolver_wait_resolv(conn, &h);
358 conn->ip_version = ipver;
361 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
362 Curl_printable_address(h->addr, myhost, sizeof(myhost));
363 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
364 dev, af, myhost, h->addr->ai_family);
365 Curl_resolv_unlock(data, h);
370 * provided dev was no interface (or interfaces are not supported
371 * e.g. solaris) no ip address and no domain we fail here
380 if((af == AF_INET6) &&
381 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
382 si6->sin6_family = AF_INET6;
383 si6->sin6_port = htons(port);
384 sizeof_sa = sizeof(struct sockaddr_in6);
389 if((af == AF_INET) &&
390 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
391 si4->sin_family = AF_INET;
392 si4->sin_port = htons(port);
393 sizeof_sa = sizeof(struct sockaddr_in);
398 failf(data, "Couldn't bind to '%s'", dev);
399 return CURLE_INTERFACE_FAILED;
403 /* no device was given, prepare sa to match af's needs */
406 si6->sin6_family = AF_INET6;
407 si6->sin6_port = htons(port);
408 sizeof_sa = sizeof(struct sockaddr_in6);
413 si4->sin_family = AF_INET;
414 si4->sin_port = htons(port);
415 sizeof_sa = sizeof(struct sockaddr_in);
420 if(bind(sockfd, sock, sizeof_sa) >= 0) {
421 /* we succeeded to bind */
422 struct Curl_sockaddr_storage add;
423 curl_socklen_t size = sizeof(add);
424 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
425 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
426 data->state.os_errno = error = SOCKERRNO;
427 failf(data, "getsockname() failed with errno %d: %s",
428 error, Curl_strerror(conn, error));
429 return CURLE_INTERFACE_FAILED;
431 infof(data, "Local port: %hu\n", port);
432 conn->bits.bound = TRUE;
437 infof(data, "Bind to local port %hu failed, trying next\n", port);
438 port++; /* try next port */
439 /* We re-use/clobber the port variable here below */
440 if(sock->sa_family == AF_INET)
441 si4->sin_port = ntohs(port);
444 si6->sin6_port = ntohs(port);
451 data->state.os_errno = error = SOCKERRNO;
452 failf(data, "bind failed with errno %d: %s",
453 error, Curl_strerror(conn, error));
455 return CURLE_INTERFACE_FAILED;
459 * verifyconnect() returns TRUE if the connect really has happened.
461 static bool verifyconnect(curl_socket_t sockfd, int *error)
466 curl_socklen_t errSize = sizeof(err);
470 * In October 2003 we effectively nullified this function on Windows due to
471 * problems with it using all CPU in multi-threaded cases.
473 * In May 2004, we bring it back to offer more info back on connect failures.
474 * Gisle Vanem could reproduce the former problems with this function, but
475 * could avoid them by adding this SleepEx() call below:
477 * "I don't have Rational Quantify, but the hint from his post was
478 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
479 * just Sleep(0) would be enough?) would release whatever
480 * mutex/critical-section the ntdll call is waiting on.
482 * Someone got to verify this on Win-NT 4.0, 2000."
493 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
496 /* Old WinCE versions don't support SO_ERROR */
497 if(WSAENOPROTOOPT == err) {
503 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
504 if(EBADIOCTL == err) {
509 if((0 == err) || (EISCONN == err))
510 /* we are connected, awesome! */
513 /* This wasn't a successful connect */
525 /* Used within the multi interface. Try next IP address, return TRUE if no
526 more address exists or error */
527 static CURLcode trynextip(struct connectdata *conn,
531 curl_socket_t sockfd;
534 /* First clean up after the failed socket.
535 Don't close it yet to ensure that the next IP's socket gets a different
536 file descriptor, which can prevent bugs when the curl_multi_socket_action
537 interface is used with certain select() replacements such as kqueue. */
538 curl_socket_t fd_to_close = conn->sock[sockindex];
539 conn->sock[sockindex] = CURL_SOCKET_BAD;
542 if(sockindex != FIRSTSOCKET) {
543 Curl_closesocket(conn, fd_to_close);
544 return CURLE_COULDNT_CONNECT; /* no next */
547 /* try the next address */
548 ai = conn->ip_addr->ai_next;
551 CURLcode res = singleipconnect(conn, ai, 0L, &sockfd, connected);
554 if(sockfd != CURL_SOCKET_BAD) {
555 /* store the new socket descriptor */
556 conn->sock[sockindex] = sockfd;
558 Curl_closesocket(conn, fd_to_close);
563 Curl_closesocket(conn, fd_to_close);
564 return CURLE_COULDNT_CONNECT;
567 /* Copies connection info into the session handle to make it available
568 when the session handle is no longer associated with a connection. */
569 void Curl_persistconninfo(struct connectdata *conn)
571 memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
572 memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
573 conn->data->info.conn_primary_port = conn->primary_port;
574 conn->data->info.conn_local_port = conn->local_port;
577 /* retrieves ip address and port from a sockaddr structure */
578 static bool getaddressinfo(struct sockaddr* sa, char* addr,
581 unsigned short us_port;
582 struct sockaddr_in* si = NULL;
584 struct sockaddr_in6* si6 = NULL;
586 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
587 struct sockaddr_un* su = NULL;
590 switch (sa->sa_family) {
592 si = (struct sockaddr_in*) sa;
593 if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
594 addr, MAX_IPADR_LEN)) {
595 us_port = ntohs(si->sin_port);
602 si6 = (struct sockaddr_in6*)sa;
603 if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
604 addr, MAX_IPADR_LEN)) {
605 us_port = ntohs(si6->sin6_port);
611 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
613 su = (struct sockaddr_un*)sa;
614 snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
628 /* retrieves the start/end point information of a socket of an established
630 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
634 struct Curl_sockaddr_storage ssrem;
635 struct Curl_sockaddr_storage ssloc;
636 struct SessionHandle *data = conn->data;
638 if(!conn->bits.reuse) {
640 len = sizeof(struct Curl_sockaddr_storage);
641 if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
643 failf(data, "getpeername() failed with errno %d: %s",
644 error, Curl_strerror(conn, error));
648 len = sizeof(struct Curl_sockaddr_storage);
649 if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
651 failf(data, "getsockname() failed with errno %d: %s",
652 error, Curl_strerror(conn, error));
656 if(!getaddressinfo((struct sockaddr*)&ssrem,
657 conn->primary_ip, &conn->primary_port)) {
659 failf(data, "ssrem inet_ntop() failed with errno %d: %s",
660 error, Curl_strerror(conn, error));
664 if(!getaddressinfo((struct sockaddr*)&ssloc,
665 conn->local_ip, &conn->local_port)) {
667 failf(data, "ssloc inet_ntop() failed with errno %d: %s",
668 error, Curl_strerror(conn, error));
674 /* persist connection info in session handle */
675 Curl_persistconninfo(conn);
679 * Curl_is_connected() is used from the multi interface to check if the
680 * firstsocket has connected.
683 CURLcode Curl_is_connected(struct connectdata *conn,
688 struct SessionHandle *data = conn->data;
689 CURLcode code = CURLE_OK;
690 curl_socket_t sockfd = conn->sock[sockindex];
691 long allow = DEFAULT_CONNECT_TIMEOUT;
695 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
697 *connected = FALSE; /* a very negative world view is best */
699 if(conn->bits.tcpconnect[sockindex]) {
700 /* we are connected already! */
707 /* figure out how long time we have left to connect */
708 allow = Curl_timeleft(data, &now, TRUE);
711 /* time-out, bail out, go home */
712 failf(data, "Connection time-out");
713 return CURLE_OPERATION_TIMEDOUT;
716 /* check for connect without timeout as we want to return immediately */
717 rc = waitconnect(conn, sockfd, 0);
718 if(WAITCONN_TIMEOUT == rc) {
719 if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
720 infof(data, "After %ldms connect time, move on!\n",
721 conn->timeoutms_per_addr);
725 /* not an error, but also no connection yet */
729 if(WAITCONN_CONNECTED == rc) {
730 if(verifyconnect(sockfd, &error)) {
731 /* we are connected with TCP, awesome! */
733 /* see if we need to do any proxy magic first once we connected */
734 code = Curl_connected_proxy(conn);
738 conn->bits.tcpconnect[sockindex] = TRUE;
740 if(sockindex == FIRSTSOCKET)
741 Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
742 Curl_verboseconnect(conn);
743 Curl_updateconninfo(conn, sockfd);
747 /* nope, not connected for real */
750 /* nope, not connected */
751 if(WAITCONN_FDSET_ERROR == rc) {
752 (void)verifyconnect(sockfd, &error);
753 infof(data, "%s\n",Curl_strerror(conn, error));
756 infof(data, "Connection failed\n");
760 * The connection failed here, we should attempt to connect to the "next
761 * address" for the given host. But first remember the latest error.
764 data->state.os_errno = error;
765 SET_SOCKERRNO(error);
769 conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
771 code = trynextip(conn, sockindex, connected);
775 data->state.os_errno = error;
776 failf(data, "Failed connect to %s:%ld; %s",
777 conn->host.name, conn->port, Curl_strerror(conn, error));
783 static void tcpnodelay(struct connectdata *conn,
784 curl_socket_t sockfd)
787 struct SessionHandle *data= conn->data;
788 curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
789 int level = IPPROTO_TCP;
792 /* The use of getprotobyname() is disabled since it isn't thread-safe on
793 numerous systems. On these getprotobyname_r() should be used instead, but
794 that exists in at least one 4 arg version and one 5 arg version, and
795 since the proto number rarely changes anyway we now just use the hard
796 coded number. The "proper" fix would need a configure check for the
797 correct function much in the same style the gethostbyname_r versions are
799 struct protoent *pe = getprotobyname("tcp");
804 if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
806 infof(data, "Could not set TCP_NODELAY: %s\n",
807 Curl_strerror(conn, SOCKERRNO));
809 infof(data,"TCP_NODELAY set\n");
817 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
818 sending data to a dead peer (instead of relying on the 4th argument to send
819 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
821 static void nosigpipe(struct connectdata *conn,
822 curl_socket_t sockfd)
824 struct SessionHandle *data= conn->data;
826 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
828 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
829 Curl_strerror(conn, SOCKERRNO));
832 #define nosigpipe(x,y) Curl_nop_stmt
836 /* When you run a program that uses the Windows Sockets API, you may
837 experience slow performance when you copy data to a TCP server.
839 http://support.microsoft.com/kb/823764
841 Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
845 void Curl_sndbufset(curl_socket_t sockfd)
847 int val = CURL_MAX_WRITE_SIZE + 32;
849 int curlen = sizeof(curval);
851 if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
855 setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
863 * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
864 * CURL_SOCKET_BAD. Other errors will however return proper errors.
866 * singleipconnect() connects to the given IP only, and it may return without
867 * having connected if used from the multi interface.
870 singleipconnect(struct connectdata *conn,
871 const Curl_addrinfo *ai,
873 curl_socket_t *sockp,
876 struct Curl_sockaddr_ex addr;
879 bool isconnected = FALSE;
880 struct SessionHandle *data = conn->data;
881 curl_socket_t sockfd;
882 CURLcode res = CURLE_OK;
884 *sockp = CURL_SOCKET_BAD;
885 *connected = FALSE; /* default is not connected */
887 res = Curl_socket(conn, ai, &addr, &sockfd);
889 /* Failed to create the socket, but still return OK since we signal the
890 lack of socket as well. This allows the parent function to keep looping
891 over alternative addresses/socket families etc. */
894 /* store remote address and port used in this connection attempt */
895 if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
896 conn->primary_ip, &conn->primary_port)) {
897 /* malformed address or bug in inet_ntop, try next address */
899 failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
900 error, Curl_strerror(conn, error));
901 Curl_closesocket(conn, sockfd);
904 memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
905 infof(data, " Trying %s...\n", conn->ip_addr_str);
907 Curl_persistconninfo(conn);
909 if(data->set.tcp_nodelay)
910 tcpnodelay(conn, sockfd);
912 nosigpipe(conn, sockfd);
914 Curl_sndbufset(sockfd);
916 if(data->set.tcp_keepalive)
917 tcpkeepalive(data, sockfd);
919 if(data->set.fsockopt) {
920 /* activate callback for setting socket options */
921 error = data->set.fsockopt(data->set.sockopt_client,
925 if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
928 Curl_closesocket(conn, sockfd); /* close the socket and bail out */
929 return CURLE_ABORTED_BY_CALLBACK;
933 /* possibly bind the local end to an IP, interface or port */
934 res = bindlocal(conn, sockfd, addr.family);
936 Curl_closesocket(conn, sockfd); /* close socket and bail out */
940 /* set socket non-blocking */
941 curlx_nonblock(sockfd, TRUE);
943 /* Connect TCP sockets, bind UDP */
944 if(!isconnected && (conn->socktype == SOCK_STREAM)) {
945 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
948 conn->connecttime = Curl_tvnow();
949 if(conn->num_addr > 1)
950 Curl_expire(data, conn->timeoutms_per_addr);
960 #if (EAGAIN) != (EWOULDBLOCK)
961 /* On some platforms EAGAIN and EWOULDBLOCK are the
962 * same value, and on others they are different, hence
968 rc = waitconnect(conn, sockfd, timeout_ms);
969 if(WAITCONN_ABORTED == rc) {
970 Curl_closesocket(conn, sockfd);
971 return CURLE_ABORTED_BY_CALLBACK;
975 /* unknown error, fallthrough and try another address! */
976 failf(data, "Failed to connect to %s: %s",
977 conn->ip_addr_str, Curl_strerror(conn,error));
978 data->state.os_errno = error;
983 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
984 connect(). We can be sure of this since connect() cannot return 1. */
985 if(WAITCONN_TIMEOUT == rc) {
986 /* Timeout when running the multi interface */
992 isconnected = verifyconnect(sockfd, &error);
994 if(!rc && isconnected) {
995 /* we are connected, awesome! */
996 *connected = TRUE; /* this is a true connect */
997 infof(data, "connected\n");
999 conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
1002 Curl_updateconninfo(conn, sockfd);
1006 else if(WAITCONN_TIMEOUT == rc)
1007 infof(data, "Timeout\n");
1009 data->state.os_errno = error;
1010 infof(data, "%s\n", Curl_strerror(conn, error));
1013 /* connect failed or timed out */
1014 Curl_closesocket(conn, sockfd);
1020 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1021 * There might be more than one IP address to try out. Fill in the passed
1022 * pointer with the connected socket.
1025 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
1026 const struct Curl_dns_entry *remotehost,
1027 curl_socket_t *sockconn, /* the connected socket */
1028 Curl_addrinfo **addr, /* the one we used */
1029 bool *connected) /* really connected? */
1031 struct SessionHandle *data = conn->data;
1032 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 conn->num_addr = Curl_num_addresses(remotehost->addr);
1058 ai = remotehost->addr;
1060 /* Below is the loop that attempts to connect to all IP-addresses we
1061 * know for the given host. One by one until one IP succeeds.
1065 * Connecting with a Curl_addrinfo chain
1067 for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
1070 /* Max time for the next address */
1071 conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
1072 timeout_ms : timeout_ms / 2;
1074 /* start connecting to the IP curr_addr points to */
1075 res = singleipconnect(conn, curr_addr,
1076 0, /* don't hang when doing multi */
1077 &sockfd, connected);
1081 if(sockfd != CURL_SOCKET_BAD)
1084 /* get a new timeout for next attempt */
1085 after = Curl_tvnow();
1086 timeout_ms -= Curl_tvdiff(after, before);
1087 if(timeout_ms < 0) {
1088 failf(data, "connect() timed out!");
1089 return CURLE_OPERATION_TIMEDOUT;
1092 } /* end of connect-to-each-address loop */
1094 *sockconn = sockfd; /* the socket descriptor we've connected */
1096 if(sockfd == CURL_SOCKET_BAD) {
1097 /* no good connect was made */
1098 failf(data, "couldn't connect to %s at %s:%d",
1099 conn->bits.proxy?"proxy":"host",
1100 conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port);
1101 return CURLE_COULDNT_CONNECT;
1104 /* leave the socket in non-blocking mode */
1106 /* store the address we use */
1110 data->info.numconnects++; /* to track the number of connections made */
1116 struct connectdata *tofind;
1120 static int conn_is_conn(struct connectdata *conn, void *param)
1122 struct connfind *f = (struct connfind *)param;
1123 if(conn == f->tofind) {
1131 * Used to extract socket and connectdata struct for the most recent
1132 * transfer on the given SessionHandle.
1134 * The returned socket will be CURL_SOCKET_BAD in case of failure!
1136 curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
1137 struct connectdata **connp)
1139 curl_socket_t sockfd;
1143 /* this only works for an easy handle that has been used for
1144 curl_easy_perform()! */
1145 if(data->state.lastconnect && data->multi_easy) {
1146 struct connectdata *c = data->state.lastconnect;
1147 struct connfind find;
1148 find.tofind = data->state.lastconnect;
1151 Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
1154 data->state.lastconnect = NULL;
1155 return CURL_SOCKET_BAD;
1159 /* only store this if the caller cares for it */
1161 sockfd = c->sock[FIRSTSOCKET];
1162 /* we have a socket connected, let's determine if the server shut down */
1163 /* determine if ssl */
1164 if(c->ssl[FIRSTSOCKET].use) {
1165 /* use the SSL context */
1166 if(!Curl_ssl_check_cxn(c))
1167 return CURL_SOCKET_BAD; /* FIN received */
1169 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1172 /* use the socket */
1174 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1175 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1176 return CURL_SOCKET_BAD; /* FIN received */
1182 return CURL_SOCKET_BAD;
1190 * 'conn' can be NULL, beware!
1192 int Curl_closesocket(struct connectdata *conn,
1195 if(conn && conn->fclosesocket) {
1196 if((sock == conn->sock[SECONDARYSOCKET]) &&
1197 conn->sock_accepted[SECONDARYSOCKET])
1198 /* if this socket matches the second socket, and that was created with
1199 accept, then we MUST NOT call the callback but clear the accepted
1201 conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1203 return conn->fclosesocket(conn->closesocket_client, sock);
1205 return sclose(sock);
1209 * Create a socket based on info from 'conn' and 'ai'.
1211 * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1212 * 'sockfd' must be a pointer to a socket descriptor.
1214 * If the open socket callback is set, used that!
1217 CURLcode Curl_socket(struct connectdata *conn,
1218 const Curl_addrinfo *ai,
1219 struct Curl_sockaddr_ex *addr,
1220 curl_socket_t *sockfd)
1222 struct SessionHandle *data = conn->data;
1223 struct Curl_sockaddr_ex dummy;
1226 /* if the caller doesn't want info back, use a local temp copy */
1230 * The Curl_sockaddr_ex structure is basically libcurl's external API
1231 * curl_sockaddr structure with enough space available to directly hold
1232 * any protocol-specific address structures. The variable declared here
1233 * will be used to pass / receive data to/from the fopensocket callback
1234 * if this has been set, before that, it is initialized from parameters.
1237 addr->family = ai->ai_family;
1238 addr->socktype = conn->socktype;
1239 addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
1240 addr->addrlen = ai->ai_addrlen;
1242 if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1243 addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1244 memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1246 if(data->set.fopensocket)
1248 * If the opensocket callback is set, all the destination address
1249 * information is passed to the callback. Depending on this information the
1250 * callback may opt to abort the connection, this is indicated returning
1251 * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1252 * the callback returns a valid socket the destination address information
1253 * might have been changed and this 'new' address will actually be used
1256 *sockfd = data->set.fopensocket(data->set.opensocket_client,
1258 (struct curl_sockaddr *)addr);
1260 /* opensocket callback not set, so simply create the socket now */
1261 *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1263 if(*sockfd == CURL_SOCKET_BAD)
1264 /* no socket, no connection */
1265 return CURLE_COULDNT_CONNECT;
1267 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1268 if(conn->scope && (addr->family == AF_INET6)) {
1269 struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1270 sa6->sin6_scope_id = conn->scope;