1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
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.
13 *
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.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * $Id: connect.c,v 1.213 2009-02-28 01:35:53 yangtse Exp $
22 ***************************************************************************/
23
24 #include "setup.h"
25
26 #ifdef HAVE_SYS_TIME_H
27 #include <sys/time.h>
28 #endif
29 #ifdef HAVE_SYS_SOCKET_H
30 #include <sys/socket.h>
31 #endif
32 #ifdef HAVE_NETINET_IN_H
33 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
34 #endif
35 #ifdef HAVE_SYS_UN_H
36 #include <sys/un.h> /* for sockaddr_un */
37 #endif
38 #ifdef HAVE_NETINET_TCP_H
39 #include <netinet/tcp.h> /* for TCP_NODELAY */
40 #endif
41 #ifdef HAVE_SYS_IOCTL_H
42 #include <sys/ioctl.h>
43 #endif
44 #ifdef HAVE_UNISTD_H
45 #include <unistd.h>
46 #endif
47 #ifdef HAVE_NETDB_H
48 #include <netdb.h>
49 #endif
50 #ifdef HAVE_FCNTL_H
51 #include <fcntl.h>
52 #endif
53 #ifdef HAVE_ARPA_INET_H
54 #include <arpa/inet.h>
55 #endif
56 #ifdef HAVE_STDLIB_H
57 #include <stdlib.h>
58 #endif
59
60 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
61 #include <sys/filio.h>
62 #endif
63 #ifdef NETWARE
64 #undef in_addr_t
65 #define in_addr_t unsigned long
66 #endif
67 #ifdef VMS
68 #include <in.h>
69 #include <inet.h>
70 #endif
71
72 #include <stdio.h>
73 #include <errno.h>
74 #include <string.h>
75
76 #define _MPRINTF_REPLACE /* use our functions only */
77 #include <curl/mprintf.h>
78
79 #include "urldata.h"
80 #include "sendf.h"
81 #include "if2ip.h"
82 #include "strerror.h"
83 #include "connect.h"
84 #include "memory.h"
85 #include "select.h"
86 #include "url.h" /* for Curl_safefree() */
87 #include "multiif.h"
88 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
89 #include "inet_ntop.h"
90 #include "inet_pton.h"
91 #include "sslgen.h" /* for Curl_ssl_check_cxn() */
92
93 /* The last #include file should be: */
94 #include "memdebug.h"
95
96 #ifdef __SYMBIAN32__
97 /* This isn't actually supported under Symbian OS */
98 #undef SO_NOSIGPIPE
99 #endif
100
101 struct Curl_sockaddr_ex {
102 int family;
103 int socktype;
104 int protocol;
105 unsigned int addrlen;
106 union {
107 struct sockaddr addr;
108 struct Curl_sockaddr_storage buff;
109 } _sa_ex_u;
110 };
111 #define sa_addr _sa_ex_u.addr
112
113 static bool verifyconnect(curl_socket_t sockfd, int *error);
114
115 static curl_socket_t
116 singleipconnect(struct connectdata *conn,
117 const Curl_addrinfo *ai, /* start connecting to this */
118 long timeout_ms,
119 bool *connected);
120
121 /*
122 * Curl_timeleft() returns the amount of milliseconds left allowed for the
123 * transfer/connection. If the value is negative, the timeout time has already
124 * elapsed.
125 *
126 * If 'nowp' is non-NULL, it points to the current time.
127 * 'duringconnect' is FALSE if not during a connect, as then of course the
128 * connect timeout is not taken into account!
129 */
Curl_timeleft(struct connectdata * conn,struct timeval * nowp,bool duringconnect)130 long Curl_timeleft(struct connectdata *conn,
131 struct timeval *nowp,
132 bool duringconnect)
133 {
134 struct SessionHandle *data = conn->data;
135 int timeout_set = 0;
136 long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
137 struct timeval now;
138
139 /* if a timeout is set, use the most restrictive one */
140
141 if(data->set.timeout > 0)
142 timeout_set |= 1;
143 if(duringconnect && (data->set.connecttimeout > 0))
144 timeout_set |= 2;
145
146 switch (timeout_set) {
147 case 1:
148 timeout_ms = data->set.timeout;
149 break;
150 case 2:
151 timeout_ms = data->set.connecttimeout;
152 break;
153 case 3:
154 if(data->set.timeout < data->set.connecttimeout)
155 timeout_ms = data->set.timeout;
156 else
157 timeout_ms = data->set.connecttimeout;
158 break;
159 default:
160 /* use the default */
161 if(!duringconnect)
162 /* if we're not during connect, there's no default timeout so if we're
163 at zero we better just return zero and not make it a negative number
164 by the math below */
165 return 0;
166 break;
167 }
168
169 if(!nowp) {
170 now = Curl_tvnow();
171 nowp = &now;
172 }
173
174 /* substract elapsed time */
175 timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
176
177 return timeout_ms;
178 }
179
180
181 /*
182 * Curl_nonblock() set the given socket to either blocking or non-blocking
183 * mode based on the 'nonblock' boolean argument. This function is highly
184 * portable.
185 */
Curl_nonblock(curl_socket_t sockfd,int nonblock)186 int Curl_nonblock(curl_socket_t sockfd, /* operate on this */
187 int nonblock /* TRUE or FALSE */)
188 {
189 #if defined(USE_BLOCKING_SOCKETS)
190
191 return 0; /* returns success */
192
193 #elif defined(HAVE_FCNTL_O_NONBLOCK)
194
195 /* most recent unix versions */
196 int flags;
197 flags = fcntl(sockfd, F_GETFL, 0);
198 if(FALSE != nonblock)
199 return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
200 else
201 return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
202
203 #elif defined(HAVE_IOCTL_FIONBIO)
204
205 /* older unix versions */
206 int flags;
207 flags = nonblock;
208 return ioctl(sockfd, FIONBIO, &flags);
209
210 #elif defined(HAVE_IOCTLSOCKET_FIONBIO)
211
212 /* Windows */
213 unsigned long flags;
214 flags = nonblock;
215 return ioctlsocket(sockfd, FIONBIO, &flags);
216
217 #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
218
219 /* Amiga */
220 return IoctlSocket(sockfd, FIONBIO, (long)nonblock);
221
222 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
223
224 /* BeOS */
225 long b = nonblock ? 1 : 0;
226 return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
227
228 #else
229 # error "no non-blocking method was found/used/set"
230 #endif
231 }
232
233 /*
234 * waitconnect() waits for a TCP connect on the given socket for the specified
235 * number if milliseconds. It returns:
236 * 0 fine connect
237 * -1 select() error
238 * 1 select() timeout
239 * 2 select() returned with an error condition fd_set
240 */
241
242 #define WAITCONN_CONNECTED 0
243 #define WAITCONN_SELECT_ERROR -1
244 #define WAITCONN_TIMEOUT 1
245 #define WAITCONN_FDSET_ERROR 2
246
247 static
waitconnect(curl_socket_t sockfd,long timeout_msec)248 int waitconnect(curl_socket_t sockfd, /* socket */
249 long timeout_msec)
250 {
251 int rc;
252 #ifdef mpeix
253 /* Call this function once now, and ignore the results. We do this to
254 "clear" the error state on the socket so that we can later read it
255 reliably. This is reported necessary on the MPE/iX operating system. */
256 (void)verifyconnect(sockfd, NULL);
257 #endif
258
259 /* now select() until we get connect or timeout */
260 rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, (int)timeout_msec);
261 if(-1 == rc)
262 /* error, no connect here, try next */
263 return WAITCONN_SELECT_ERROR;
264
265 else if(0 == rc)
266 /* timeout, no connect today */
267 return WAITCONN_TIMEOUT;
268
269 if(rc & CURL_CSELECT_ERR)
270 /* error condition caught */
271 return WAITCONN_FDSET_ERROR;
272
273 /* we have a connect! */
274 return WAITCONN_CONNECTED;
275 }
276
bindlocal(struct connectdata * conn,curl_socket_t sockfd,int af)277 static CURLcode bindlocal(struct connectdata *conn,
278 curl_socket_t sockfd, int af)
279 {
280 struct SessionHandle *data = conn->data;
281
282 struct Curl_sockaddr_storage sa;
283 struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
284 socklen_t sizeof_sa = 0; /* size of the data sock points to */
285 struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
286 #ifdef ENABLE_IPV6
287 struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
288 #endif
289
290 struct Curl_dns_entry *h=NULL;
291 unsigned short port = data->set.localport; /* use this port number, 0 for
292 "random" */
293 /* how many port numbers to try to bind to, increasing one at a time */
294 int portnum = data->set.localportrange;
295 const char *dev = data->set.str[STRING_DEVICE];
296 int error;
297 char myhost[256] = "";
298 int done = 0; /* -1 for error, 1 for address found */
299
300 /*************************************************************
301 * Select device to bind socket to
302 *************************************************************/
303 if ( !dev && !port )
304 /* no local kind of binding was requested */
305 return CURLE_OK;
306
307 memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
308
309 if(dev && (strlen(dev)<255) ) {
310
311 /* interface */
312 if(Curl_if2ip(af, dev, myhost, sizeof(myhost))) {
313 /*
314 * We now have the numerical IP address in the 'myhost' buffer
315 */
316 infof(data, "Local Interface %s is ip %s using address family %i\n",
317 dev, myhost, af);
318 done = 1;
319
320 #ifdef SO_BINDTODEVICE
321 /* I am not sure any other OSs than Linux that provide this feature, and
322 * at the least I cannot test. --Ben
323 *
324 * This feature allows one to tightly bind the local socket to a
325 * particular interface. This will force even requests to other local
326 * interfaces to go out the external interface.
327 *
328 *
329 * Only bind to the interface when specified as interface, not just as a
330 * hostname or ip address.
331 */
332 if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
333 dev, strlen(dev)+1) != 0) {
334 error = SOCKERRNO;
335 infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
336 " will do regular bind\n",
337 dev, error, Curl_strerror(conn, error));
338 /* This is typically "errno 1, error: Operation not permitted" if
339 you're not running as root or another suitable privileged user */
340 }
341 #endif
342 }
343 else {
344 /*
345 * This was not an interface, resolve the name as a host name
346 * or IP number
347 *
348 * Temporarily force name resolution to use only the address type
349 * of the connection. The resolve functions should really be changed
350 * to take a type parameter instead.
351 */
352 long ipver = data->set.ip_version;
353 int rc;
354
355 if (af == AF_INET)
356 data->set.ip_version = CURL_IPRESOLVE_V4;
357 #ifdef ENABLE_IPV6
358 else if (af == AF_INET6)
359 data->set.ip_version = CURL_IPRESOLVE_V6;
360 #endif
361
362 rc = Curl_resolv(conn, dev, 0, &h);
363 if(rc == CURLRESOLV_PENDING)
364 (void)Curl_wait_for_resolv(conn, &h);
365 data->set.ip_version = ipver;
366
367 if(h) {
368 /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
369 Curl_printable_address(h->addr, myhost, sizeof(myhost));
370 infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
371 dev, af, myhost, h->addr->ai_family);
372 Curl_resolv_unlock(data, h);
373 done = 1;
374 }
375 else {
376 /*
377 * provided dev was no interface (or interfaces are not supported
378 * e.g. solaris) no ip address and no domain we fail here
379 */
380 done = -1;
381 }
382 }
383
384 if(done > 0) {
385 #ifdef ENABLE_IPV6
386 /* ipv6 address */
387 if((af == AF_INET6) &&
388 (Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0)) {
389 si6->sin6_family = AF_INET6;
390 si6->sin6_port = htons(port);
391 sizeof_sa = sizeof(struct sockaddr_in6);
392 }
393 else
394 #endif
395 /* ipv4 address */
396 if((af == AF_INET) &&
397 (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
398 si4->sin_family = AF_INET;
399 si4->sin_port = htons(port);
400 sizeof_sa = sizeof(struct sockaddr_in);
401 }
402 }
403
404 if(done < 1) {
405 failf(data, "Couldn't bind to '%s'", dev);
406 return CURLE_INTERFACE_FAILED;
407 }
408 }
409 else {
410 /* no device was given, prepare sa to match af's needs */
411 #ifdef ENABLE_IPV6
412 if ( af == AF_INET6 ) {
413 si6->sin6_family = AF_INET6;
414 si6->sin6_port = htons(port);
415 sizeof_sa = sizeof(struct sockaddr_in6);
416 }
417 else
418 #endif
419 if ( af == AF_INET ) {
420 si4->sin_family = AF_INET;
421 si4->sin_port = htons(port);
422 sizeof_sa = sizeof(struct sockaddr_in);
423 }
424 }
425
426 do {
427 if( bind(sockfd, sock, sizeof_sa) >= 0) {
428 /* we succeeded to bind */
429 struct Curl_sockaddr_storage add;
430 socklen_t size = sizeof(add);
431 memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
432 if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
433 data->state.os_errno = error = SOCKERRNO;
434 failf(data, "getsockname() failed with errno %d: %s",
435 error, Curl_strerror(conn, error));
436 return CURLE_INTERFACE_FAILED;
437 }
438 infof(data, "Local port: %d\n", port);
439 conn->bits.bound = TRUE;
440 return CURLE_OK;
441 }
442
443 if(--portnum > 0) {
444 infof(data, "Bind to local port %d failed, trying next\n", port);
445 port++; /* try next port */
446 /* We re-use/clobber the port variable here below */
447 if(sock->sa_family == AF_INET)
448 si4->sin_port = ntohs(port);
449 #ifdef ENABLE_IPV6
450 else
451 si6->sin6_port = ntohs(port);
452 #endif
453 }
454 else
455 break;
456 } while(1);
457
458 data->state.os_errno = error = SOCKERRNO;
459 failf(data, "bind failed with errno %d: %s",
460 error, Curl_strerror(conn, error));
461
462 return CURLE_INTERFACE_FAILED;
463 }
464
465 /*
466 * verifyconnect() returns TRUE if the connect really has happened.
467 */
verifyconnect(curl_socket_t sockfd,int * error)468 static bool verifyconnect(curl_socket_t sockfd, int *error)
469 {
470 bool rc = TRUE;
471 #ifdef SO_ERROR
472 int err = 0;
473 socklen_t errSize = sizeof(err);
474
475 #ifdef WIN32
476 /*
477 * In October 2003 we effectively nullified this function on Windows due to
478 * problems with it using all CPU in multi-threaded cases.
479 *
480 * In May 2004, we bring it back to offer more info back on connect failures.
481 * Gisle Vanem could reproduce the former problems with this function, but
482 * could avoid them by adding this SleepEx() call below:
483 *
484 * "I don't have Rational Quantify, but the hint from his post was
485 * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
486 * just Sleep(0) would be enough?) would release whatever
487 * mutex/critical-section the ntdll call is waiting on.
488 *
489 * Someone got to verify this on Win-NT 4.0, 2000."
490 */
491
492 #ifdef _WIN32_WCE
493 Sleep(0);
494 #else
495 SleepEx(0, FALSE);
496 #endif
497
498 #endif
499
500 if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
501 err = SOCKERRNO;
502 #ifdef _WIN32_WCE
503 /* Old WinCE versions don't support SO_ERROR */
504 if(WSAENOPROTOOPT == err) {
505 SET_SOCKERRNO(0);
506 err = 0;
507 }
508 #endif
509 #ifdef __minix
510 /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
511 if(EBADIOCTL == err) {
512 SET_SOCKERRNO(0);
513 err = 0;
514 }
515 #endif
516 if((0 == err) || (EISCONN == err))
517 /* we are connected, awesome! */
518 rc = TRUE;
519 else
520 /* This wasn't a successful connect */
521 rc = FALSE;
522 if(error)
523 *error = err;
524 #else
525 (void)sockfd;
526 if(error)
527 *error = SOCKERRNO;
528 #endif
529 return rc;
530 }
531
532 /* Used within the multi interface. Try next IP address, return TRUE if no
533 more address exists or error */
trynextip(struct connectdata * conn,int sockindex,bool * connected)534 static bool trynextip(struct connectdata *conn,
535 int sockindex,
536 bool *connected)
537 {
538 curl_socket_t sockfd;
539 Curl_addrinfo *ai;
540
541 /* first close the failed socket */
542 sclose(conn->sock[sockindex]);
543 conn->sock[sockindex] = CURL_SOCKET_BAD;
544 *connected = FALSE;
545
546 if(sockindex != FIRSTSOCKET)
547 return TRUE; /* no next */
548
549 /* try the next address */
550 ai = conn->ip_addr->ai_next;
551
552 while(ai) {
553 sockfd = singleipconnect(conn, ai, 0L, connected);
554 if(sockfd != CURL_SOCKET_BAD) {
555 /* store the new socket descriptor */
556 conn->sock[sockindex] = sockfd;
557 conn->ip_addr = ai;
558 break;
559 }
560 ai = ai->ai_next;
561 }
562 return TRUE;
563 }
564
565 /*
566 * Curl_is_connected() is used from the multi interface to check if the
567 * firstsocket has connected.
568 */
569
Curl_is_connected(struct connectdata * conn,int sockindex,bool * connected)570 CURLcode Curl_is_connected(struct connectdata *conn,
571 int sockindex,
572 bool *connected)
573 {
574 int rc;
575 struct SessionHandle *data = conn->data;
576 CURLcode code = CURLE_OK;
577 curl_socket_t sockfd = conn->sock[sockindex];
578 long allow = DEFAULT_CONNECT_TIMEOUT;
579
580 DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
581
582 *connected = FALSE; /* a very negative world view is best */
583
584 if(conn->bits.tcpconnect) {
585 /* we are connected already! */
586 long allow_total = 0;
587
588 /* subtract the most strict timeout of the ones */
589 if(data->set.timeout)
590 allow_total = data->set.timeout;
591
592 Curl_expire(data, allow_total);
593 *connected = TRUE;
594 return CURLE_OK;
595 }
596
597 /* figure out how long time we have left to connect */
598 allow = Curl_timeleft(conn, NULL, TRUE);
599
600 if(allow < 0) {
601 /* time-out, bail out, go home */
602 failf(data, "Connection time-out");
603 return CURLE_OPERATION_TIMEDOUT;
604 }
605
606 Curl_expire(data, allow);
607
608 /* check for connect without timeout as we want to return immediately */
609 rc = waitconnect(sockfd, 0);
610
611 if(WAITCONN_CONNECTED == rc) {
612 int error;
613 if(verifyconnect(sockfd, &error)) {
614 /* we are connected, awesome! */
615 *connected = TRUE;
616 return CURLE_OK;
617 }
618 /* nope, not connected for real */
619 data->state.os_errno = error;
620 infof(data, "Connection failed\n");
621 if(trynextip(conn, sockindex, connected)) {
622 failf(data, "Failed connect to %s:%d; %s",
623 conn->host.name, conn->port, Curl_strerror(conn, error));
624 code = CURLE_COULDNT_CONNECT;
625 }
626 }
627 else if(WAITCONN_TIMEOUT != rc) {
628 int error = 0;
629
630 /* nope, not connected */
631 if(WAITCONN_FDSET_ERROR == rc) {
632 (void)verifyconnect(sockfd, &error);
633 data->state.os_errno = error;
634 infof(data, "%s\n",Curl_strerror(conn,error));
635 }
636 else
637 infof(data, "Connection failed\n");
638
639 if(trynextip(conn, sockindex, connected)) {
640 error = SOCKERRNO;
641 data->state.os_errno = error;
642 failf(data, "Failed connect to %s:%d; %s",
643 conn->host.name, conn->port, Curl_strerror(conn, error));
644 code = CURLE_COULDNT_CONNECT;
645 }
646 }
647 /*
648 * If the connection failed here, we should attempt to connect to the "next
649 * address" for the given host.
650 */
651
652 return code;
653 }
654
tcpnodelay(struct connectdata * conn,curl_socket_t sockfd)655 static void tcpnodelay(struct connectdata *conn,
656 curl_socket_t sockfd)
657 {
658 #ifdef TCP_NODELAY
659 struct SessionHandle *data= conn->data;
660 socklen_t onoff = (socklen_t) data->set.tcp_nodelay;
661 int proto = IPPROTO_TCP;
662
663 #if 0
664 /* The use of getprotobyname() is disabled since it isn't thread-safe on
665 numerous systems. On these getprotobyname_r() should be used instead, but
666 that exists in at least one 4 arg version and one 5 arg version, and
667 since the proto number rarely changes anyway we now just use the hard
668 coded number. The "proper" fix would need a configure check for the
669 correct function much in the same style the gethostbyname_r versions are
670 detected. */
671 struct protoent *pe = getprotobyname("tcp");
672 if(pe)
673 proto = pe->p_proto;
674 #endif
675
676 if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff,
677 sizeof(onoff)) < 0)
678 infof(data, "Could not set TCP_NODELAY: %s\n",
679 Curl_strerror(conn, SOCKERRNO));
680 else
681 infof(data,"TCP_NODELAY set\n");
682 #else
683 (void)conn;
684 (void)sockfd;
685 #endif
686 }
687
688 #ifdef SO_NOSIGPIPE
689 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
690 sending data to a dead peer (instead of relying on the 4th argument to send
691 being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
692 systems? */
nosigpipe(struct connectdata * conn,curl_socket_t sockfd)693 static void nosigpipe(struct connectdata *conn,
694 curl_socket_t sockfd)
695 {
696 struct SessionHandle *data= conn->data;
697 int onoff = 1;
698 if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
699 sizeof(onoff)) < 0)
700 infof(data, "Could not set SO_NOSIGPIPE: %s\n",
701 Curl_strerror(conn, SOCKERRNO));
702 }
703 #else
704 #define nosigpipe(x,y)
705 #endif
706
707 /* singleipconnect() connects to the given IP only, and it may return without
708 having connected if used from the multi interface. */
709 static curl_socket_t
singleipconnect(struct connectdata * conn,const Curl_addrinfo * ai,long timeout_ms,bool * connected)710 singleipconnect(struct connectdata *conn,
711 const Curl_addrinfo *ai,
712 long timeout_ms,
713 bool *connected)
714 {
715 struct Curl_sockaddr_ex addr;
716 char addr_buf[128];
717 int rc;
718 int error;
719 bool isconnected;
720 struct SessionHandle *data = conn->data;
721 curl_socket_t sockfd;
722 CURLcode res;
723 const void *iptoprint;
724 struct sockaddr_in * const sa4 = (void *)&addr.sa_addr;
725 #ifdef ENABLE_IPV6
726 struct sockaddr_in6 * const sa6 = (void *)&addr.sa_addr;
727 #endif
728
729 /*
730 * The Curl_sockaddr_ex structure is basically libcurl's external API
731 * curl_sockaddr structure with enough space available to directly hold
732 * any protocol-specific address structures. The variable declared here
733 * will be used to pass / receive data to/from the fopensocket callback
734 * if this has been set, before that, it is initialized from parameters.
735 */
736
737 addr.family = ai->ai_family;
738 addr.socktype = conn->socktype;
739 addr.protocol = ai->ai_protocol;
740 addr.addrlen = ai->ai_addrlen;
741
742 if(addr.addrlen > sizeof(struct Curl_sockaddr_storage))
743 addr.addrlen = sizeof(struct Curl_sockaddr_storage);
744 memcpy(&addr.sa_addr, ai->ai_addr, addr.addrlen);
745
746 *connected = FALSE; /* default is not connected */
747
748 if(data->set.fopensocket)
749 /*
750 * If the opensocket callback is set, all the destination address information
751 * is passed to the callback. Depending on this information the callback may
752 * opt to abort the connection, this is indicated returning CURL_SOCKET_BAD;
753 * otherwise it will return a not-connected socket. When the callback returns
754 * a valid socket the destination address information might have been changed
755 * and this 'new' address will actually be used here to connect.
756 */
757 sockfd = data->set.fopensocket(data->set.opensocket_client,
758 CURLSOCKTYPE_IPCXN,
759 (struct curl_sockaddr *)&addr);
760 else
761 /* opensocket callback not set, so simply create the socket now */
762 sockfd = socket(addr.family, addr.socktype, addr.protocol);
763
764 if(sockfd == CURL_SOCKET_BAD)
765 /* no socket, no connection */
766 return CURL_SOCKET_BAD;
767
768 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
769 if (conn->scope && (addr.family == AF_INET6))
770 sa6->sin6_scope_id = conn->scope;
771 #endif
772
773 /* FIXME: do we have Curl_printable_address-like with struct sockaddr* as
774 argument? */
775 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
776 if(addr.family == AF_UNIX) {
777 infof(data, " Trying %s... ",
778 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
779 snprintf(data->info.ip, MAX_IPADR_LEN, "%s",
780 ((const struct sockaddr_un*)(&addr.sa_addr))->sun_path);
781 strcpy(conn->ip_addr_str, data->info.ip);
782 }
783 else
784 #endif
785 {
786 #ifdef ENABLE_IPV6
787 if(addr.family == AF_INET6) {
788 iptoprint = &sa6->sin6_addr;
789 conn->bits.ipv6 = TRUE;
790 }
791 else
792 #endif
793 {
794 iptoprint = &sa4->sin_addr;
795 }
796
797 if(Curl_inet_ntop(addr.family, iptoprint, addr_buf,
798 sizeof(addr_buf)) != NULL) {
799 infof(data, " Trying %s... ", addr_buf);
800 snprintf(data->info.ip, MAX_IPADR_LEN, "%s", addr_buf);
801 strcpy(conn->ip_addr_str, data->info.ip);
802 }
803 }
804
805 if(data->set.tcp_nodelay)
806 tcpnodelay(conn, sockfd);
807
808 nosigpipe(conn, sockfd);
809
810 if(data->set.fsockopt) {
811 /* activate callback for setting socket options */
812 error = data->set.fsockopt(data->set.sockopt_client,
813 sockfd,
814 CURLSOCKTYPE_IPCXN);
815 if(error) {
816 sclose(sockfd); /* close the socket and bail out */
817 return CURL_SOCKET_BAD;
818 }
819 }
820
821 /* possibly bind the local end to an IP, interface or port */
822 res = bindlocal(conn, sockfd, addr.family);
823 if(res) {
824 sclose(sockfd); /* close socket and bail out */
825 return CURL_SOCKET_BAD;
826 }
827
828 /* set socket non-blocking */
829 Curl_nonblock(sockfd, TRUE);
830
831 /* Connect TCP sockets, bind UDP */
832 if(conn->socktype == SOCK_STREAM)
833 rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
834 else
835 rc = 0;
836
837 if(-1 == rc) {
838 error = SOCKERRNO;
839
840 switch (error) {
841 case EINPROGRESS:
842 case EWOULDBLOCK:
843 #if defined(EAGAIN)
844 #if (EAGAIN) != (EWOULDBLOCK)
845 /* On some platforms EAGAIN and EWOULDBLOCK are the
846 * same value, and on others they are different, hence
847 * the odd #if
848 */
849 case EAGAIN:
850 #endif
851 #endif
852 rc = waitconnect(sockfd, timeout_ms);
853 break;
854 default:
855 /* unknown error, fallthrough and try another address! */
856 failf(data, "Failed to connect to %s: %s",
857 addr_buf, Curl_strerror(conn,error));
858 data->state.os_errno = error;
859 break;
860 }
861 }
862
863 /* The 'WAITCONN_TIMEOUT == rc' comes from the waitconnect(), and not from
864 connect(). We can be sure of this since connect() cannot return 1. */
865 if((WAITCONN_TIMEOUT == rc) &&
866 (data->state.used_interface == Curl_if_multi)) {
867 /* Timeout when running the multi interface */
868 return sockfd;
869 }
870
871 isconnected = verifyconnect(sockfd, &error);
872
873 if(!rc && isconnected) {
874 /* we are connected, awesome! */
875 *connected = TRUE; /* this is a true connect */
876 infof(data, "connected\n");
877 return sockfd;
878 }
879 else if(WAITCONN_TIMEOUT == rc)
880 infof(data, "Timeout\n");
881 else {
882 data->state.os_errno = error;
883 infof(data, "%s\n", Curl_strerror(conn, error));
884 }
885
886 /* connect failed or timed out */
887 sclose(sockfd);
888
889 return CURL_SOCKET_BAD;
890 }
891
892 /*
893 * TCP connect to the given host with timeout, proxy or remote doesn't matter.
894 * There might be more than one IP address to try out. Fill in the passed
895 * pointer with the connected socket.
896 */
897
Curl_connecthost(struct connectdata * conn,const struct Curl_dns_entry * remotehost,curl_socket_t * sockconn,Curl_addrinfo ** addr,bool * connected)898 CURLcode Curl_connecthost(struct connectdata *conn, /* context */
899 const struct Curl_dns_entry *remotehost,
900 curl_socket_t *sockconn, /* the connected socket */
901 Curl_addrinfo **addr, /* the one we used */
902 bool *connected) /* really connected? */
903 {
904 struct SessionHandle *data = conn->data;
905 curl_socket_t sockfd = CURL_SOCKET_BAD;
906 int aliasindex;
907 int num_addr;
908 Curl_addrinfo *ai;
909 Curl_addrinfo *curr_addr;
910
911 struct timeval after;
912 struct timeval before = Curl_tvnow();
913
914 /*************************************************************
915 * Figure out what maximum time we have left
916 *************************************************************/
917 long timeout_ms;
918 long timeout_per_addr;
919
920 DEBUGASSERT(sockconn);
921 *connected = FALSE; /* default to not connected */
922
923 /* get the timeout left */
924 timeout_ms = Curl_timeleft(conn, &before, TRUE);
925
926 if(timeout_ms < 0) {
927 /* a precaution, no need to continue if time already is up */
928 failf(data, "Connection time-out");
929 return CURLE_OPERATION_TIMEDOUT;
930 }
931 Curl_expire(data, timeout_ms);
932
933 /* Max time for each address */
934 num_addr = Curl_num_addresses(remotehost->addr);
935 timeout_per_addr = timeout_ms / num_addr;
936
937 ai = remotehost->addr;
938
939 /* Below is the loop that attempts to connect to all IP-addresses we
940 * know for the given host. One by one until one IP succeeds.
941 */
942
943 if(data->state.used_interface == Curl_if_multi)
944 /* don't hang when doing multi */
945 timeout_per_addr = 0;
946
947 /*
948 * Connecting with a Curl_addrinfo chain
949 */
950 for (curr_addr = ai, aliasindex=0; curr_addr;
951 curr_addr = curr_addr->ai_next, aliasindex++) {
952
953 /* start connecting to the IP curr_addr points to */
954 sockfd = singleipconnect(conn, curr_addr, timeout_per_addr, connected);
955
956 if(sockfd != CURL_SOCKET_BAD)
957 break;
958
959 /* get a new timeout for next attempt */
960 after = Curl_tvnow();
961 timeout_ms -= Curl_tvdiff(after, before);
962 if(timeout_ms < 0) {
963 failf(data, "connect() timed out!");
964 return CURLE_OPERATION_TIMEDOUT;
965 }
966 before = after;
967 } /* end of connect-to-each-address loop */
968
969 *sockconn = sockfd; /* the socket descriptor we've connected */
970
971 if(sockfd == CURL_SOCKET_BAD) {
972 /* no good connect was made */
973 failf(data, "couldn't connect to host");
974 return CURLE_COULDNT_CONNECT;
975 }
976
977 /* leave the socket in non-blocking mode */
978
979 /* store the address we use */
980 if(addr)
981 *addr = curr_addr;
982
983 data->info.numconnects++; /* to track the number of connections made */
984
985 return CURLE_OK;
986 }
987
988 /*
989 * Used to extract socket and connectdata struct for the most recent
990 * transfer on the given SessionHandle.
991 *
992 * The socket 'long' will be -1 in case of failure!
993 */
Curl_getconnectinfo(struct SessionHandle * data,long * param_longp,struct connectdata ** connp)994 CURLcode Curl_getconnectinfo(struct SessionHandle *data,
995 long *param_longp,
996 struct connectdata **connp)
997 {
998 if((data->state.lastconnect != -1) &&
999 (data->state.connc->connects[data->state.lastconnect] != NULL)) {
1000 struct connectdata *c =
1001 data->state.connc->connects[data->state.lastconnect];
1002 if(connp)
1003 /* only store this if the caller cares for it */
1004 *connp = c;
1005 *param_longp = c->sock[FIRSTSOCKET];
1006 /* we have a socket connected, let's determine if the server shut down */
1007 /* determine if ssl */
1008 if(c->ssl[FIRSTSOCKET].use) {
1009 /* use the SSL context */
1010 if(!Curl_ssl_check_cxn(c))
1011 *param_longp = -1; /* FIN received */
1012 }
1013 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1014 #ifdef MSG_PEEK
1015 else {
1016 /* use the socket */
1017 char buf;
1018 if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1019 (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1020 *param_longp = -1; /* FIN received */
1021 }
1022 }
1023 #endif
1024 }
1025 else
1026 *param_longp = -1;
1027
1028 return CURLE_OK;
1029 }
1030