Initial commit of visual studio 9 git build superproject.
[git-build-vc9.git] / curl / lib / connect.c
blob52d70715ecf6f8cf0b36772c38b7f3418ea00b50
1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at http://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 * $Id: connect.c,v 1.197 2008-08-26 21:28:57 danf Exp $
22 ***************************************************************************/
24 #include "setup.h"
26 #ifndef WIN32
27 /* headers for non-win32 */
28 #ifdef HAVE_SYS_TIME_H
29 #include <sys/time.h>
30 #endif
31 #ifdef HAVE_SYS_SOCKET_H
32 #include <sys/socket.h>
33 #endif
34 #ifdef HAVE_NETINET_IN_H
35 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
36 #endif
37 #ifdef HAVE_SYS_UN_H
38 #include <sys/un.h> /* for sockaddr_un */
39 #endif
40 #ifdef HAVE_NETINET_TCP_H
41 #include <netinet/tcp.h> /* for TCP_NODELAY */
42 #endif
43 #ifdef HAVE_SYS_IOCTL_H
44 #include <sys/ioctl.h>
45 #endif
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #ifdef HAVE_NETDB_H
50 #include <netdb.h>
51 #endif
52 #ifdef HAVE_FCNTL_H
53 #include <fcntl.h>
54 #endif
55 #ifdef HAVE_ARPA_INET_H
56 #include <arpa/inet.h>
57 #endif
58 #ifdef HAVE_STDLIB_H
59 #include <stdlib.h> /* required for free() prototype, without it, this crashes */
60 #endif /* on macos 68K */
62 #if (defined(HAVE_FIONBIO) && defined(NETWARE))
63 #include <sys/filio.h>
64 #endif
65 #ifdef NETWARE
66 #undef in_addr_t
67 #define in_addr_t unsigned long
68 #endif
69 #ifdef VMS
70 #include <in.h>
71 #include <inet.h>
72 #endif
74 #endif /* !WIN32 */
76 #include <stdio.h>
77 #include <errno.h>
78 #include <string.h>
80 #define _MPRINTF_REPLACE /* use our functions only */
81 #include <curl/mprintf.h>
83 #include "urldata.h"
84 #include "sendf.h"
85 #include "if2ip.h"
86 #include "strerror.h"
87 #include "connect.h"
88 #include "memory.h"
89 #include "select.h"
90 #include "url.h" /* for Curl_safefree() */
91 #include "multiif.h"
92 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
93 #include "inet_ntop.h"
94 #include "inet_pton.h"
95 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
97 /* The last #include file should be: */
98 #include "memdebug.h"
100 #ifdef __SYMBIAN32__
101 /* This isn't actually supported under Symbian OS */
102 #undef SO_NOSIGPIPE
103 #endif
105 static bool verifyconnect(curl_socket_t sockfd, int *error);
107 static curl_socket_t
108 singleipconnect(struct connectdata *conn,
109 const Curl_addrinfo *ai, /* start connecting to this */
110 long timeout_ms,
111 bool *connected);
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
116 * elapsed.
118 * If 'nowp' is non-NULL, it points to the current time.
119 * 'duringconnect' is FALSE if not during a connect, as then of course the
120 * connect timeout is not taken into account!
122 long Curl_timeleft(struct connectdata *conn,
123 struct timeval *nowp,
124 bool duringconnect)
126 struct SessionHandle *data = conn->data;
127 int timeout_set = 0;
128 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
129 struct timeval now;
131 /* if a timeout is set, use the most restrictive one */
133 if(data->set.timeout > 0)
134 timeout_set |= 1;
135 if(duringconnect && (data->set.connecttimeout > 0))
136 timeout_set |= 2;
138 switch (timeout_set) {
139 case 1:
140 timeout_ms = data->set.timeout;
141 break;
142 case 2:
143 timeout_ms = data->set.connecttimeout;
144 break;
145 case 3:
146 if(data->set.timeout < data->set.connecttimeout)
147 timeout_ms = data->set.timeout;
148 else
149 timeout_ms = data->set.connecttimeout;
150 break;
151 default:
152 /* use the default */
153 if(!duringconnect)
154 /* if we're not during connect, there's no default timeout so if we're
155 at zero we better just return zero and not make it a negative number
156 by the math below */
157 return 0;
158 break;
161 if(!nowp) {
162 now = Curl_tvnow();
163 nowp = &now;
166 /* substract elapsed time */
167 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
169 return timeout_ms;
174 * Curl_nonblock() set the given socket to either blocking or non-blocking
175 * mode based on the 'nonblock' boolean argument. This function is highly
176 * portable.
178 int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
179 int nonblock /* TRUE or FALSE */)
181 #undef SETBLOCK
182 #define SETBLOCK 0
183 #ifdef HAVE_O_NONBLOCK
184 /* most recent unix versions */
185 int flags;
187 flags = fcntl(sockfd, F_GETFL, 0);
188 if(FALSE != nonblock)
189 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
190 else
191 return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
192 #undef SETBLOCK
193 #define SETBLOCK 1
194 #endif
196 #if defined(HAVE_FIONBIO) && (SETBLOCK == 0)
197 /* older unix versions */
198 int flags;
200 flags = nonblock;
201 return ioctl(sockfd, FIONBIO, &flags);
202 #undef SETBLOCK
203 #define SETBLOCK 2
204 #endif
206 #if defined(HAVE_IOCTLSOCKET) && (SETBLOCK == 0)
207 /* Windows? */
208 unsigned long flags;
209 flags = nonblock;
211 return ioctlsocket(sockfd, FIONBIO, &flags);
212 #undef SETBLOCK
213 #define SETBLOCK 3
214 #endif
216 #if defined(HAVE_IOCTLSOCKET_CASE) && (SETBLOCK == 0)
217 /* presumably for Amiga */
218 return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
219 #undef SETBLOCK
220 #define SETBLOCK 4
221 #endif
223 #if defined(HAVE_SO_NONBLOCK) && (SETBLOCK == 0)
224 /* BeOS */
225 long b = nonblock ? 1 : 0;
226 return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
227 #undef SETBLOCK
228 #define SETBLOCK 5
229 #endif
231 #ifdef HAVE_DISABLED_NONBLOCKING
232 return 0; /* returns success */
233 #undef SETBLOCK
234 #define SETBLOCK 6
235 #endif
237 #if(SETBLOCK == 0)
238 #error "no non-blocking method was found/used/set"
239 #endif
243 * waitconnect() waits for a TCP connect on the given socket for the specified
244 * number if milliseconds. It returns:
245 * 0 fine connect
246 * -1 select() error
247 * 1 select() timeout
248 * 2 select() returned with an error condition fd_set
251 #define WAITCONN_CONNECTED 0
252 #define WAITCONN_SELECT_ERROR -1
253 #define WAITCONN_TIMEOUT 1
254 #define WAITCONN_FDSET_ERROR 2
256 static
257 int waitconnect(curl_socket_t sockfd, /* socket */
258 long timeout_msec)
260 int rc;
261 #ifdef mpeix
262 /* Call this function once now, and ignore the results. We do this to
263 "clear" the error state on the socket so that we can later read it
264 reliably. This is reported necessary on the MPE/iX operating system. */
265 (void)verifyconnect(sockfd, NULL);
266 #endif
268 /* now select() until we get connect or timeout */
269 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
270 if(-1 == rc)
271 /* error, no connect here, try next */
272 return WAITCONN_SELECT_ERROR;
274 else if(0 == rc)
275 /* timeout, no connect today */
276 return WAITCONN_TIMEOUT;
278 if(rc & CURL_CSELECT_ERR)
279 /* error condition caught */
280 return WAITCONN_FDSET_ERROR;
282 /* we have a connect! */
283 return WAITCONN_CONNECTED;
286 static CURLcode bindlocal(struct connectdata *conn,
287 curl_socket_t sockfd)
289 #ifdef ENABLE_IPV6
290 char ipv6_addr[16];
291 #endif
292 struct SessionHandle *data = conn->data;
293 struct sockaddr_in me;
294 struct sockaddr *sock = NULL; /* bind to this address */
295 socklen_t socksize; /* size of the data sock points to */
296 unsigned short port = data->set.localport; /* use this port number, 0 for
297 "random" */
298 /* how many port numbers to try to bind to, increasing one at a time */
299 int portnum = data->set.localportrange;
300 const char *dev = data->set.str[STRING_DEVICE];
302 /*************************************************************
303 * Select device to bind socket to
304 *************************************************************/
305 if(dev && (strlen(dev)<255) ) {
306 struct Curl_dns_entry *h=NULL;
307 char myhost[256] = "";
308 in_addr_t in;
309 int rc;
310 bool was_iface = FALSE;
311 int in6 = -1;
313 /* First check if the given name is an IP address */
314 in=inet_addr((char *) dev);
316 if((in == CURL_INADDR_NONE) &&
317 Curl_if2ip(dev, myhost, sizeof(myhost))) {
319 * We now have the numerical IPv4-style x.y.z.w in the 'myhost' buffer
321 rc = Curl_resolv(conn, myhost, 0, &h);
322 if(rc == CURLRESOLV_PENDING)
323 (void)Curl_wait_for_resolv(conn, &h);
325 if(h) {
326 was_iface = TRUE;
327 Curl_resolv_unlock(data, h);
331 if(!was_iface) {
333 * This was not an interface, resolve the name as a host name
334 * or IP number
336 rc = Curl_resolv(conn, dev, 0, &h);
337 if(rc == CURLRESOLV_PENDING)
338 (void)Curl_wait_for_resolv(conn, &h);
340 if(h) {
341 if(in == CURL_INADDR_NONE)
342 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
343 Curl_printable_address(h->addr, myhost, sizeof myhost);
344 else
345 /* we know data->set.device is shorter than the myhost array */
346 strcpy(myhost, dev);
347 Curl_resolv_unlock(data, h);
351 if(! *myhost) {
352 /* need to fix this
353 h=Curl_gethost(data,
354 getmyhost(*myhost,sizeof(myhost)),
355 hostent_buf,
356 sizeof(hostent_buf));
358 failf(data, "Couldn't bind to '%s'", dev);
359 return CURLE_INTERFACE_FAILED;
362 infof(data, "Bind local address to %s\n", myhost);
364 #ifdef SO_BINDTODEVICE
365 /* I am not sure any other OSs than Linux that provide this feature, and
366 * at the least I cannot test. --Ben
368 * This feature allows one to tightly bind the local socket to a
369 * particular interface. This will force even requests to other local
370 * interfaces to go out the external interface.
373 if(was_iface) {
374 /* Only bind to the interface when specified as interface, not just as a
375 * hostname or ip address.
377 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
378 dev, strlen(dev)+1) != 0) {
379 /* printf("Failed to BINDTODEVICE, socket: %d device: %s error: %s\n",
380 sockfd, dev, Curl_strerror(SOCKERRNO)); */
381 infof(data, "SO_BINDTODEVICE %s failed\n", dev);
382 /* This is typically "errno 1, error: Operation not permitted" if
383 you're not running as root or another suitable privileged user */
386 #endif
388 in=inet_addr(myhost);
390 #ifdef ENABLE_IPV6
391 in6 = Curl_inet_pton (AF_INET6, myhost, (void *)&ipv6_addr);
392 #endif
393 if(CURL_INADDR_NONE == in && -1 == in6) {
394 failf(data,"couldn't find my own IP address (%s)", myhost);
395 return CURLE_INTERFACE_FAILED;
396 } /* end of inet_addr */
398 if( h ) {
399 Curl_addrinfo *addr = h->addr;
400 sock = addr->ai_addr;
401 socksize = addr->ai_addrlen;
403 else
404 return CURLE_INTERFACE_FAILED;
407 else if(port) {
408 /* if a local port number is requested but no local IP, extract the
409 address from the socket */
410 memset(&me, 0, sizeof(struct sockaddr));
411 me.sin_family = AF_INET;
412 me.sin_addr.s_addr = INADDR_ANY;
414 sock = (struct sockaddr *)&me;
415 socksize = sizeof(struct sockaddr);
418 else
419 /* no local kind of binding was requested */
420 return CURLE_OK;
422 do {
424 /* Set port number to bind to, 0 makes the system pick one */
425 if(sock->sa_family == AF_INET)
426 ((struct sockaddr_in *)sock)->sin_port = htons(port);
427 #ifdef ENABLE_IPV6
428 else
429 ((struct sockaddr_in6 *)sock)->sin6_port = htons(port);
430 #endif
432 if( bind(sockfd, sock, socksize) >= 0) {
433 /* we succeeded to bind */
434 struct Curl_sockaddr_storage add;
435 socklen_t size;
437 size = sizeof(add);
438 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
439 failf(data, "getsockname() failed");
440 return CURLE_INTERFACE_FAILED;
442 /* We re-use/clobber the port variable here below */
443 if(((struct sockaddr *)&add)->sa_family == AF_INET)
444 port = ntohs(((struct sockaddr_in *)&add)->sin_port);
445 #ifdef ENABLE_IPV6
446 else
447 port = ntohs(((struct sockaddr_in6 *)&add)->sin6_port);
448 #endif
449 infof(data, "Local port: %d\n", port);
450 conn->bits.bound = TRUE;
451 return CURLE_OK;
453 if(--portnum > 0) {
454 infof(data, "Bind to local port %d failed, trying next\n", port);
455 port++; /* try next port */
457 else
458 break;
459 } while(1);
461 data->state.os_errno = SOCKERRNO;
462 failf(data, "bind failure: %s",
463 Curl_strerror(conn, data->state.os_errno));
464 return CURLE_INTERFACE_FAILED;
469 * verifyconnect() returns TRUE if the connect really has happened.
471 static bool verifyconnect(curl_socket_t sockfd, int *error)
473 bool rc = TRUE;
474 #ifdef SO_ERROR
475 int err = 0;
476 socklen_t errSize = sizeof(err);
478 #ifdef WIN32
480 * In October 2003 we effectively nullified this function on Windows due to
481 * problems with it using all CPU in multi-threaded cases.
483 * In May 2004, we bring it back to offer more info back on connect failures.
484 * Gisle Vanem could reproduce the former problems with this function, but
485 * could avoid them by adding this SleepEx() call below:
487 * "I don't have Rational Quantify, but the hint from his post was
488 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
489 * just Sleep(0) would be enough?) would release whatever
490 * mutex/critical-section the ntdll call is waiting on.
492 * Someone got to verify this on Win-NT 4.0, 2000."
495 #ifdef _WIN32_WCE
496 Sleep(0);
497 #else
498 SleepEx(0, FALSE);
499 #endif
501 #endif
503 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
504 err = SOCKERRNO;
505 #ifdef _WIN32_WCE
506 /* Old WinCE versions don't support SO_ERROR */
507 if(WSAENOPROTOOPT == err) {
508 SET_SOCKERRNO(0);
509 err = 0;
511 #endif
512 #ifdef __minix
513 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
514 if(EBADIOCTL == err) {
515 SET_SOCKERRNO(0);
516 err = 0;
518 #endif
519 if((0 == err) || (EISCONN == err))
520 /* we are connected, awesome! */
521 rc = TRUE;
522 else
523 /* This wasn't a successful connect */
524 rc = FALSE;
525 if(error)
526 *error = err;
527 #else
528 (void)sockfd;
529 if(error)
530 *error = SOCKERRNO;
531 #endif
532 return rc;
535 CURLcode Curl_store_ip_addr(struct connectdata *conn)
537 char addrbuf[256];
538 Curl_printable_address(conn->ip_addr, addrbuf, sizeof(addrbuf));
540 /* save the string */
541 Curl_safefree(conn->ip_addr_str);
542 conn->ip_addr_str = strdup(addrbuf);
543 if(!conn->ip_addr_str)
544 return CURLE_OUT_OF_MEMORY; /* FAIL */
546 #ifdef PF_INET6
547 if(conn->ip_addr->ai_family == PF_INET6)
548 conn->bits.ipv6 = TRUE;
549 #endif
551 return CURLE_OK;
554 /* Used within the multi interface. Try next IP address, return TRUE if no
555 more address exists or error */
556 static bool trynextip(struct connectdata *conn,
557 int sockindex,
558 bool *connected)
560 curl_socket_t sockfd;
561 Curl_addrinfo *ai;
563 /* first close the failed socket */
564 sclose(conn->sock[sockindex]);
565 conn->sock[sockindex] = CURL_SOCKET_BAD;
566 *connected = FALSE;
568 if(sockindex != FIRSTSOCKET)
569 return TRUE; /* no next */
571 /* try the next address */
572 ai = conn->ip_addr->ai_next;
574 while(ai) {
575 sockfd = singleipconnect(conn, ai, 0L, connected);
576 if(sockfd != CURL_SOCKET_BAD) {
577 /* store the new socket descriptor */
578 conn->sock[sockindex] = sockfd;
579 conn->ip_addr = ai;
581 return Curl_store_ip_addr(conn) != CURLE_OK;
583 ai = ai->ai_next;
585 return TRUE;
589 * Curl_is_connected() is used from the multi interface to check if the
590 * firstsocket has connected.
593 CURLcode Curl_is_connected(struct connectdata *conn,
594 int sockindex,
595 bool *connected)
597 int rc;
598 struct SessionHandle *data = conn->data;
599 CURLcode code = CURLE_OK;
600 curl_socket_t sockfd = conn->sock[sockindex];
601 long allow = DEFAULT_CONNECT_TIMEOUT;
603 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
605 *connected = FALSE; /* a very negative world view is best */
607 if(conn->bits.tcpconnect) {
608 /* we are connected already! */
609 long allow_total = 0;
611 /* subtract the most strict timeout of the ones */
612 if(data->set.timeout)
613 allow_total = data->set.timeout;
615 Curl_expire(data, allow_total);
616 *connected = TRUE;
617 return CURLE_OK;
620 /* figure out how long time we have left to connect */
621 allow = Curl_timeleft(conn, NULL, TRUE);
623 if(allow < 0) {
624 /* time-out, bail out, go home */
625 failf(data, "Connection time-out");
626 return CURLE_OPERATION_TIMEDOUT;
629 Curl_expire(data, allow);
631 /* check for connect without timeout as we want to return immediately */
632 rc = waitconnect(sockfd, 0);
634 if(WAITCONN_CONNECTED == rc) {
635 int error;
636 if(verifyconnect(sockfd, &error)) {
637 /* we are connected, awesome! */
638 *connected = TRUE;
639 return CURLE_OK;
641 /* nope, not connected for real */
642 data->state.os_errno = error;
643 infof(data, "Connection failed\n");
644 if(trynextip(conn, sockindex, connected)) {
645 failf(data, "Failed connect to %s:%d; %s",
646 conn->host.name, conn->port, Curl_strerror(conn, error));
647 code = CURLE_COULDNT_CONNECT;
650 else if(WAITCONN_TIMEOUT != rc) {
651 int error = 0;
653 /* nope, not connected */
654 if(WAITCONN_FDSET_ERROR == rc) {
655 (void)verifyconnect(sockfd, &error);
656 data->state.os_errno = error;
657 infof(data, "%s\n",Curl_strerror(conn,error));
659 else
660 infof(data, "Connection failed\n");
662 if(trynextip(conn, sockindex, connected)) {
663 error = SOCKERRNO;
664 data->state.os_errno = error;
665 failf(data, "Failed connect to %s:%d; %s",
666 conn->host.name, conn->port, Curl_strerror(conn, error));
667 code = CURLE_COULDNT_CONNECT;
671 * If the connection failed here, we should attempt to connect to the "next
672 * address" for the given host.
675 return code;
678 static void tcpnodelay(struct connectdata *conn,
679 curl_socket_t sockfd)
681 #ifdef TCP_NODELAY
682 struct SessionHandle *data= conn->data;
683 socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
684 int proto = IPPROTO_TCP;
686 #if 0
687 /* The use of getprotobyname() is disabled since it isn't thread-safe on
688 numerous systems. On these getprotobyname_r() should be used instead, but
689 that exists in at least one 4 arg version and one 5 arg version, and
690 since the proto number rarely changes anyway we now just use the hard
691 coded number. The "proper" fix would need a configure check for the
692 correct function much in the same style the gethostbyname_r versions are
693 detected. */
694 struct protoent *pe = getprotobyname("tcp");
695 if(pe)
696 proto = pe->p_proto;
697 #endif
699 if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
700 sizeof(onoff)) < 0)
701 infof(data, "Could not set TCP_NODELAY: %s\n",
702 Curl_strerror(conn, SOCKERRNO));
703 else
704 infof(data,"TCP_NODELAY set\n");
705 #else
706 (void)conn;
707 (void)sockfd;
708 #endif
711 #ifdef SO_NOSIGPIPE
712 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
713 sending data to a dead peer (instead of relying on the 4th argument to send
714 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
715 systems? */
716 static void nosigpipe(struct connectdata *conn,
717 curl_socket_t sockfd)
719 struct SessionHandle *data= conn->data;
720 int onoff = 1;
721 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
722 sizeof(onoff)) < 0)
723 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
724 Curl_strerror(conn, SOCKERRNO));
726 #else
727 #define nosigpipe(x,y)
728 #endif
730 /* singleipconnect() connects to the given IP only, and it may return without
731 having connected if used from the multi interface. */
732 static curl_socket_t
733 singleipconnect(struct connectdata *conn,
734 const Curl_addrinfo *ai,
735 long timeout_ms,
736 bool *connected)
738 char addr_buf[128];
739 int rc;
740 int error;
741 bool isconnected;
742 struct SessionHandle *data = conn->data;
743 curl_socket_t sockfd;
744 CURLcode res;
746 * Curl_sockaddr_storage, which is basically sockaddr_storage has a space
747 * for a largest possible struct sockaddr only. We should add some space for
748 * the other fields we are using. Hence the addr_storage size math.
750 char addr_storage[sizeof(struct curl_sockaddr)-
751 sizeof(struct sockaddr)+
752 sizeof(struct Curl_sockaddr_storage)];
753 struct curl_sockaddr *addr=(struct curl_sockaddr*)&addr_storage;
754 const void *iptoprint;
756 addr->family=ai->ai_family;
757 addr->socktype=conn->socktype;
758 addr->protocol=ai->ai_protocol;
759 addr->addrlen =
760 (ai->ai_addrlen < (socklen_t)sizeof(struct Curl_sockaddr_storage)) ?
761 (unsigned int)ai->ai_addrlen : sizeof(struct Curl_sockaddr_storage);
762 memcpy(&addr->addr, ai->ai_addr, addr->addrlen);
764 /* If set, use opensocket callback to get the socket */
765 if(data->set.fopensocket)
766 sockfd = data->set.fopensocket(data->set.opensocket_client,
767 CURLSOCKTYPE_IPCXN, addr);
768 else
769 sockfd = socket(addr->family, addr->socktype, addr->protocol);
770 if(sockfd == CURL_SOCKET_BAD)
771 return CURL_SOCKET_BAD;
773 *connected = FALSE; /* default is not connected */
775 #ifdef CURLRES_IPV6
776 if (conn->scope && (addr->family == AF_INET6)) {
777 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)&addr->addr;
778 in6->sin6_scope_id = conn->scope;
780 #endif
782 /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
783 argument? */
784 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
785 if(addr->family==AF_UNIX) {
786 infof(data, " Trying %s... ",
787 ((const struct sockaddr_un*)(&addr->addr))->sun_path);
788 snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
789 ((const struct sockaddr_un*)(&addr->addr))->sun_path);
791 else
792 #endif
794 #ifdef ENABLE_IPV6
795 if(addr->family==AF_INET6)
796 iptoprint= &((const struct sockaddr_in6*)(&addr->addr))->sin6_addr;
797 else
798 #endif
799 iptoprint = &((const struct sockaddr_in*)(&addr->addr))->sin_addr;
801 if(Curl_inet_ntop(addr->family, iptoprint, addr_buf,
802 sizeof(addr_buf)) != NULL) {
803 infof(data, " Trying %s... ", addr_buf);
804 snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
808 if(data->set.tcp_nodelay)
809 tcpnodelay(conn, sockfd);
811 nosigpipe(conn, sockfd);
813 if(data->set.fsockopt) {
814 /* activate callback for setting socket options */
815 error = data->set.fsockopt(data->set.sockopt_client,
816 sockfd,
817 CURLSOCKTYPE_IPCXN);
818 if(error) {
819 sclose(sockfd); /* close the socket and bail out */
820 return CURL_SOCKET_BAD;
824 /* possibly bind the local end to an IP, interface or port */
825 res = bindlocal(conn, sockfd);
826 if(res) {
827 sclose(sockfd); /* close socket and bail out */
828 return CURL_SOCKET_BAD;
831 /* set socket non-blocking */
832 Curl_nonblock(sockfd, TRUE);
834 /* Connect TCP sockets, bind UDP */
835 if(conn->socktype == SOCK_STREAM)
836 rc = connect(sockfd, &addr->addr, addr->addrlen);
837 else
838 rc = 0;
840 if(-1 == rc) {
841 error = SOCKERRNO;
843 switch (error) {
844 case EINPROGRESS:
845 case EWOULDBLOCK:
846 #if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
847 /* On some platforms EAGAIN and EWOULDBLOCK are the
848 * same value, and on others they are different, hence
849 * the odd #if
851 case EAGAIN:
852 #endif
853 rc = waitconnect(sockfd, timeout_ms);
854 break;
855 default:
856 /* unknown error, fallthrough and try another address! */
857 failf(data, "Failed to connect to %s: %s",
858 addr_buf, Curl_strerror(conn,error));
859 data->state.os_errno = error;
860 break;
864 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
865 connect(). We can be sure of this since connect() cannot return 1. */
866 if((WAITCONN_TIMEOUT == rc) &&
867 (data->state.used_interface == Curl_if_multi)) {
868 /* Timeout when running the multi interface */
869 return sockfd;
872 isconnected = verifyconnect(sockfd, &error);
874 if(!rc && isconnected) {
875 /* we are connected, awesome! */
876 *connected = TRUE; /* this is a true connect */
877 infof(data, "connected\n");
878 return sockfd;
880 else if(WAITCONN_TIMEOUT == rc)
881 infof(data, "Timeout\n");
882 else {
883 data->state.os_errno = error;
884 infof(data, "%s\n", Curl_strerror(conn, error));
887 /* connect failed or timed out */
888 sclose(sockfd);
890 return CURL_SOCKET_BAD;
894 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
895 * There might be more than one IP address to try out. Fill in the passed
896 * pointer with the connected socket.
899 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
900 const struct Curl_dns_entry *remotehost,
901 curl_socket_t *sockconn, /* the connected socket */
902 Curl_addrinfo **addr, /* the one we used */
903 bool *connected) /* really connected? */
905 struct SessionHandle *data = conn->data;
906 curl_socket_t sockfd = CURL_SOCKET_BAD;
907 int aliasindex;
908 int num_addr;
909 Curl_addrinfo *ai;
910 Curl_addrinfo *curr_addr;
912 struct timeval after;
913 struct timeval before = Curl_tvnow();
915 /*************************************************************
916 * Figure out what maximum time we have left
917 *************************************************************/
918 long timeout_ms;
919 long timeout_per_addr;
921 DEBUGASSERT(sockconn);
922 *connected = FALSE; /* default to not connected */
924 /* get the timeout left */
925 timeout_ms = Curl_timeleft(conn, &before, TRUE);
927 if(timeout_ms < 0) {
928 /* a precaution, no need to continue if time already is up */
929 failf(data, "Connection time-out");
930 return CURLE_OPERATION_TIMEDOUT;
932 Curl_expire(data, timeout_ms);
934 /* Max time for each address */
935 num_addr = Curl_num_addresses(remotehost->addr);
936 timeout_per_addr = timeout_ms / num_addr;
938 ai = remotehost->addr;
940 /* Below is the loop that attempts to connect to all IP-addresses we
941 * know for the given host. One by one until one IP succeeds.
944 if(data->state.used_interface == Curl_if_multi)
945 /* don't hang when doing multi */
946 timeout_per_addr = 0;
949 * Connecting with a Curl_addrinfo chain
951 for (curr_addr = ai, aliasindex=0; curr_addr;
952 curr_addr = curr_addr->ai_next, aliasindex++) {
954 /* start connecting to the IP curr_addr points to */
955 sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
957 if(sockfd != CURL_SOCKET_BAD)
958 break;
960 /* get a new timeout for next attempt */
961 after = Curl_tvnow();
962 timeout_ms -= Curl_tvdiff(after, before);
963 if(timeout_ms < 0) {
964 failf(data, "connect() timed out!");
965 return CURLE_OPERATION_TIMEDOUT;
967 before = after;
968 } /* end of connect-to-each-address loop */
970 *sockconn = sockfd; /* the socket descriptor we've connected */
972 if(sockfd == CURL_SOCKET_BAD) {
973 /* no good connect was made */
974 failf(data, "couldn't connect to host");
975 return CURLE_COULDNT_CONNECT;
978 /* leave the socket in non-blocking mode */
980 /* store the address we use */
981 if(addr)
982 *addr = curr_addr;
984 data->info.numconnects++; /* to track the number of connections made */
986 return CURLE_OK;
990 * Used to extract socket and connectdata struct for the most recent
991 * transfer on the given SessionHandle.
993 * The socket 'long' will be -1 in case of failure!
995 CURLcode Curl_getconnectinfo(struct SessionHandle *data,
996 long *param_longp,
997 struct connectdata **connp)
999 if((data->state.lastconnect != -1) &&
1000 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1001 struct connectdata *c =
1002 data->state.connc->connects[data->state.lastconnect];
1003 if(connp)
1004 /* only store this if the caller cares for it */
1005 *connp = c;
1006 *param_longp = c->sock[FIRSTSOCKET];
1007 /* we have a socket connected, let's determine if the server shut down */
1008 /* determine if ssl */
1009 if(c->ssl[FIRSTSOCKET].use) {
1010 /* use the SSL context */
1011 if(!Curl_ssl_check_cxn(c))
1012 *param_longp = -1; /* FIN received */
1014 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1015 #ifdef MSG_PEEK
1016 else {
1017 /* use the socket */
1018 char buf;
1019 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1020 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1021 *param_longp = -1; /* FIN received */
1024 #endif
1026 else
1027 *param_longp = -1;
1029 return CURLE_OK;