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