1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2019, 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 https://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  ***************************************************************************/
22 
23 #include "curl_setup.h"
24 
25 #ifdef HAVE_NETINET_IN_H
26 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
27 #endif
28 #ifdef HAVE_SYS_UN_H
29 #include <sys/un.h> /* for sockaddr_un */
30 #endif
31 #ifdef HAVE_LINUX_TCP_H
32 #include <linux/tcp.h>
33 #elif defined(HAVE_NETINET_TCP_H)
34 #include <netinet/tcp.h>
35 #endif
36 #ifdef HAVE_SYS_IOCTL_H
37 #include <sys/ioctl.h>
38 #endif
39 #ifdef HAVE_NETDB_H
40 #include <netdb.h>
41 #endif
42 #ifdef HAVE_FCNTL_H
43 #include <fcntl.h>
44 #endif
45 #ifdef HAVE_ARPA_INET_H
46 #include <arpa/inet.h>
47 #endif
48 
49 #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
50 #include <sys/filio.h>
51 #endif
52 #ifdef NETWARE
53 #undef in_addr_t
54 #define in_addr_t unsigned long
55 #endif
56 #ifdef __VMS
57 #include <in.h>
58 #include <inet.h>
59 #endif
60 
61 #include "urldata.h"
62 #include "sendf.h"
63 #include "if2ip.h"
64 #include "strerror.h"
65 #include "connect.h"
66 #include "select.h"
67 #include "url.h" /* for Curl_safefree() */
68 #include "multiif.h"
69 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
70 #include "inet_ntop.h"
71 #include "inet_pton.h"
72 #include "vtls/vtls.h" /* for Curl_ssl_check_cxn() */
73 #include "progress.h"
74 #include "warnless.h"
75 #include "conncache.h"
76 #include "multihandle.h"
77 #include "system_win32.h"
78 #include "quic.h"
79 #include "socks.h"
80 
81 /* The last 3 #include files should be in this order */
82 #include "curl_printf.h"
83 #include "curl_memory.h"
84 #include "memdebug.h"
85 
86 #ifdef __SYMBIAN32__
87 /* This isn't actually supported under Symbian OS */
88 #undef SO_NOSIGPIPE
89 #endif
90 
91 static bool verifyconnect(curl_socket_t sockfd, int *error);
92 
93 #if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
94 /* DragonFlyBSD and Windows use millisecond units */
95 #define KEEPALIVE_FACTOR(x) (x *= 1000)
96 #else
97 #define KEEPALIVE_FACTOR(x)
98 #endif
99 
100 #if defined(HAVE_WINSOCK2_H) && !defined(SIO_KEEPALIVE_VALS)
101 #define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
102 
103 struct tcp_keepalive {
104   u_long onoff;
105   u_long keepalivetime;
106   u_long keepaliveinterval;
107 };
108 #endif
109 
110 static void
tcpkeepalive(struct Curl_easy * data,curl_socket_t sockfd)111 tcpkeepalive(struct Curl_easy *data,
112              curl_socket_t sockfd)
113 {
114   int optval = data->set.tcp_keepalive?1:0;
115 
116   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
117   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
118         (void *)&optval, sizeof(optval)) < 0) {
119     infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
120   }
121   else {
122 #if defined(SIO_KEEPALIVE_VALS)
123     struct tcp_keepalive vals;
124     DWORD dummy;
125     vals.onoff = 1;
126     optval = curlx_sltosi(data->set.tcp_keepidle);
127     KEEPALIVE_FACTOR(optval);
128     vals.keepalivetime = optval;
129     optval = curlx_sltosi(data->set.tcp_keepintvl);
130     KEEPALIVE_FACTOR(optval);
131     vals.keepaliveinterval = optval;
132     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
133                 NULL, 0, &dummy, NULL, NULL) != 0) {
134       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
135             (int)sockfd, WSAGetLastError());
136     }
137 #else
138 #ifdef TCP_KEEPIDLE
139     optval = curlx_sltosi(data->set.tcp_keepidle);
140     KEEPALIVE_FACTOR(optval);
141     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
142           (void *)&optval, sizeof(optval)) < 0) {
143       infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
144     }
145 #endif
146 #ifdef TCP_KEEPINTVL
147     optval = curlx_sltosi(data->set.tcp_keepintvl);
148     KEEPALIVE_FACTOR(optval);
149     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
150           (void *)&optval, sizeof(optval)) < 0) {
151       infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
152     }
153 #endif
154 #ifdef TCP_KEEPALIVE
155     /* Mac OS X style */
156     optval = curlx_sltosi(data->set.tcp_keepidle);
157     KEEPALIVE_FACTOR(optval);
158     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
159           (void *)&optval, sizeof(optval)) < 0) {
160       infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
161     }
162 #endif
163 #endif
164   }
165 }
166 
167 static CURLcode
168 singleipconnect(struct connectdata *conn,
169                 const Curl_addrinfo *ai, /* start connecting to this */
170                 int sockindex);          /* 0 or 1 among the temp ones */
171 
172 /*
173  * Curl_timeleft() returns the amount of milliseconds left allowed for the
174  * transfer/connection. If the value is negative, the timeout time has already
175  * elapsed.
176  *
177  * The start time is stored in progress.t_startsingle - as set with
178  * Curl_pgrsTime(..., TIMER_STARTSINGLE);
179  *
180  * If 'nowp' is non-NULL, it points to the current time.
181  * 'duringconnect' is FALSE if not during a connect, as then of course the
182  * connect timeout is not taken into account!
183  *
184  * @unittest: 1303
185  */
Curl_timeleft(struct Curl_easy * data,struct curltime * nowp,bool duringconnect)186 timediff_t Curl_timeleft(struct Curl_easy *data,
187                          struct curltime *nowp,
188                          bool duringconnect)
189 {
190   int timeout_set = 0;
191   timediff_t timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
192   struct curltime now;
193 
194   /* if a timeout is set, use the most restrictive one */
195 
196   if(data->set.timeout > 0)
197     timeout_set |= 1;
198   if(duringconnect && (data->set.connecttimeout > 0))
199     timeout_set |= 2;
200 
201   switch(timeout_set) {
202   case 1:
203     timeout_ms = data->set.timeout;
204     break;
205   case 2:
206     timeout_ms = data->set.connecttimeout;
207     break;
208   case 3:
209     if(data->set.timeout < data->set.connecttimeout)
210       timeout_ms = data->set.timeout;
211     else
212       timeout_ms = data->set.connecttimeout;
213     break;
214   default:
215     /* use the default */
216     if(!duringconnect)
217       /* if we're not during connect, there's no default timeout so if we're
218          at zero we better just return zero and not make it a negative number
219          by the math below */
220       return 0;
221     break;
222   }
223 
224   if(!nowp) {
225     now = Curl_now();
226     nowp = &now;
227   }
228 
229   /* subtract elapsed time */
230   if(duringconnect)
231     /* since this most recent connect started */
232     timeout_ms -= Curl_timediff(*nowp, data->progress.t_startsingle);
233   else
234     /* since the entire operation started */
235     timeout_ms -= Curl_timediff(*nowp, data->progress.t_startop);
236   if(!timeout_ms)
237     /* avoid returning 0 as that means no timeout! */
238     return -1;
239 
240   return timeout_ms;
241 }
242 
bindlocal(struct connectdata * conn,curl_socket_t sockfd,int af,unsigned int scope)243 static CURLcode bindlocal(struct connectdata *conn,
244                           curl_socket_t sockfd, int af, unsigned int scope)
245 {
246   struct Curl_easy *data = conn->data;
247 
248   struct Curl_sockaddr_storage sa;
249   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
250   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
251   struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
252 #ifdef ENABLE_IPV6
253   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
254 #endif
255 
256   struct Curl_dns_entry *h = NULL;
257   unsigned short port = data->set.localport; /* use this port number, 0 for
258                                                 "random" */
259   /* how many port numbers to try to bind to, increasing one at a time */
260   int portnum = data->set.localportrange;
261   const char *dev = data->set.str[STRING_DEVICE];
262   int error;
263 
264   /*************************************************************
265    * Select device to bind socket to
266    *************************************************************/
267   if(!dev && !port)
268     /* no local kind of binding was requested */
269     return CURLE_OK;
270 
271   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
272 
273   if(dev && (strlen(dev)<255) ) {
274     char myhost[256] = "";
275     int done = 0; /* -1 for error, 1 for address found */
276     bool is_interface = FALSE;
277     bool is_host = FALSE;
278     static const char *if_prefix = "if!";
279     static const char *host_prefix = "host!";
280 
281     if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
282       dev += strlen(if_prefix);
283       is_interface = TRUE;
284     }
285     else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
286       dev += strlen(host_prefix);
287       is_host = TRUE;
288     }
289 
290     /* interface */
291     if(!is_host) {
292 #ifdef SO_BINDTODEVICE
293       /* I am not sure any other OSs than Linux that provide this feature,
294        * and at the least I cannot test. --Ben
295        *
296        * This feature allows one to tightly bind the local socket to a
297        * particular interface.  This will force even requests to other
298        * local interfaces to go out the external interface.
299        *
300        *
301        * Only bind to the interface when specified as interface, not just
302        * as a hostname or ip address.
303        *
304        * interface might be a VRF, eg: vrf-blue, which means it cannot be
305        * converted to an IP address and would fail Curl_if2ip. Simply try
306        * to use it straight away.
307        */
308       if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
309                     dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
310         /* This is typically "errno 1, error: Operation not permitted" if
311          * you're not running as root or another suitable privileged
312          * user.
313          * If it succeeds it means the parameter was a valid interface and
314          * not an IP address. Return immediately.
315          */
316         return CURLE_OK;
317       }
318 #endif
319 
320       switch(Curl_if2ip(af, scope, conn->scope_id, dev,
321                         myhost, sizeof(myhost))) {
322         case IF2IP_NOT_FOUND:
323           if(is_interface) {
324             /* Do not fall back to treating it as a host name */
325             failf(data, "Couldn't bind to interface '%s'", dev);
326             return CURLE_INTERFACE_FAILED;
327           }
328           break;
329         case IF2IP_AF_NOT_SUPPORTED:
330           /* Signal the caller to try another address family if available */
331           return CURLE_UNSUPPORTED_PROTOCOL;
332         case IF2IP_FOUND:
333           is_interface = TRUE;
334           /*
335            * We now have the numerical IP address in the 'myhost' buffer
336            */
337           infof(data, "Local Interface %s is ip %s using address family %i\n",
338                 dev, myhost, af);
339           done = 1;
340           break;
341       }
342     }
343     if(!is_interface) {
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 = conn->ip_version;
353       int rc;
354 
355       if(af == AF_INET)
356         conn->ip_version = CURL_IPRESOLVE_V4;
357 #ifdef ENABLE_IPV6
358       else if(af == AF_INET6)
359         conn->ip_version = CURL_IPRESOLVE_V6;
360 #endif
361 
362       rc = Curl_resolv(conn, dev, 0, FALSE, &h);
363       if(rc == CURLRESOLV_PENDING)
364         (void)Curl_resolver_wait_resolv(conn, &h);
365       conn->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         if(af != h->addr->ai_family) {
374           /* bad IP version combo, signal the caller to try another address
375              family if available */
376           return CURLE_UNSUPPORTED_PROTOCOL;
377         }
378         done = 1;
379       }
380       else {
381         /*
382          * provided dev was no interface (or interfaces are not supported
383          * e.g. solaris) no ip address and no domain we fail here
384          */
385         done = -1;
386       }
387     }
388 
389     if(done > 0) {
390 #ifdef ENABLE_IPV6
391       /* IPv6 address */
392       if(af == AF_INET6) {
393 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
394         char *scope_ptr = strchr(myhost, '%');
395         if(scope_ptr)
396           *(scope_ptr++) = 0;
397 #endif
398         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
399           si6->sin6_family = AF_INET6;
400           si6->sin6_port = htons(port);
401 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
402           if(scope_ptr)
403             /* The "myhost" string either comes from Curl_if2ip or from
404                Curl_printable_address. The latter returns only numeric scope
405                IDs and the former returns none at all.  So the scope ID, if
406                present, is known to be numeric */
407             si6->sin6_scope_id = atoi(scope_ptr);
408 #endif
409         }
410         sizeof_sa = sizeof(struct sockaddr_in6);
411       }
412       else
413 #endif
414       /* IPv4 address */
415       if((af == AF_INET) &&
416          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
417         si4->sin_family = AF_INET;
418         si4->sin_port = htons(port);
419         sizeof_sa = sizeof(struct sockaddr_in);
420       }
421     }
422 
423     if(done < 1) {
424       /* errorbuf is set false so failf will overwrite any message already in
425          the error buffer, so the user receives this error message instead of a
426          generic resolve error. */
427       data->state.errorbuf = FALSE;
428       failf(data, "Couldn't bind to '%s'", dev);
429       return CURLE_INTERFACE_FAILED;
430     }
431   }
432   else {
433     /* no device was given, prepare sa to match af's needs */
434 #ifdef ENABLE_IPV6
435     if(af == AF_INET6) {
436       si6->sin6_family = AF_INET6;
437       si6->sin6_port = htons(port);
438       sizeof_sa = sizeof(struct sockaddr_in6);
439     }
440     else
441 #endif
442     if(af == AF_INET) {
443       si4->sin_family = AF_INET;
444       si4->sin_port = htons(port);
445       sizeof_sa = sizeof(struct sockaddr_in);
446     }
447   }
448 
449   for(;;) {
450     if(bind(sockfd, sock, sizeof_sa) >= 0) {
451       /* we succeeded to bind */
452       struct Curl_sockaddr_storage add;
453       curl_socklen_t size = sizeof(add);
454       memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
455       if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
456         char buffer[STRERROR_LEN];
457         data->state.os_errno = error = SOCKERRNO;
458         failf(data, "getsockname() failed with errno %d: %s",
459               error, Curl_strerror(error, buffer, sizeof(buffer)));
460         return CURLE_INTERFACE_FAILED;
461       }
462       infof(data, "Local port: %hu\n", port);
463       conn->bits.bound = TRUE;
464       return CURLE_OK;
465     }
466 
467     if(--portnum > 0) {
468       infof(data, "Bind to local port %hu failed, trying next\n", port);
469       port++; /* try next port */
470       /* We re-use/clobber the port variable here below */
471       if(sock->sa_family == AF_INET)
472         si4->sin_port = ntohs(port);
473 #ifdef ENABLE_IPV6
474       else
475         si6->sin6_port = ntohs(port);
476 #endif
477     }
478     else
479       break;
480   }
481   {
482     char buffer[STRERROR_LEN];
483     data->state.os_errno = error = SOCKERRNO;
484     failf(data, "bind failed with errno %d: %s",
485           error, Curl_strerror(error, buffer, sizeof(buffer)));
486   }
487 
488   return CURLE_INTERFACE_FAILED;
489 }
490 
491 /*
492  * verifyconnect() returns TRUE if the connect really has happened.
493  */
verifyconnect(curl_socket_t sockfd,int * error)494 static bool verifyconnect(curl_socket_t sockfd, int *error)
495 {
496   bool rc = TRUE;
497 #ifdef SO_ERROR
498   int err = 0;
499   curl_socklen_t errSize = sizeof(err);
500 
501 #ifdef WIN32
502   /*
503    * In October 2003 we effectively nullified this function on Windows due to
504    * problems with it using all CPU in multi-threaded cases.
505    *
506    * In May 2004, we bring it back to offer more info back on connect failures.
507    * Gisle Vanem could reproduce the former problems with this function, but
508    * could avoid them by adding this SleepEx() call below:
509    *
510    *    "I don't have Rational Quantify, but the hint from his post was
511    *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
512    *    just Sleep(0) would be enough?) would release whatever
513    *    mutex/critical-section the ntdll call is waiting on.
514    *
515    *    Someone got to verify this on Win-NT 4.0, 2000."
516    */
517 
518 #ifdef _WIN32_WCE
519   Sleep(0);
520 #else
521   SleepEx(0, FALSE);
522 #endif
523 
524 #endif
525 
526   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
527     err = SOCKERRNO;
528 #ifdef _WIN32_WCE
529   /* Old WinCE versions don't support SO_ERROR */
530   if(WSAENOPROTOOPT == err) {
531     SET_SOCKERRNO(0);
532     err = 0;
533   }
534 #endif
535 #if defined(EBADIOCTL) && defined(__minix)
536   /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
537   if(EBADIOCTL == err) {
538     SET_SOCKERRNO(0);
539     err = 0;
540   }
541 #endif
542   if((0 == err) || (EISCONN == err))
543     /* we are connected, awesome! */
544     rc = TRUE;
545   else
546     /* This wasn't a successful connect */
547     rc = FALSE;
548   if(error)
549     *error = err;
550 #else
551   (void)sockfd;
552   if(error)
553     *error = SOCKERRNO;
554 #endif
555   return rc;
556 }
557 
558 /* Used within the multi interface. Try next IP address, return TRUE if no
559    more address exists or error */
trynextip(struct connectdata * conn,int sockindex,int tempindex)560 static CURLcode trynextip(struct connectdata *conn,
561                           int sockindex,
562                           int tempindex)
563 {
564   const int other = tempindex ^ 1;
565   CURLcode result = CURLE_COULDNT_CONNECT;
566 
567   /* First clean up after the failed socket.
568      Don't close it yet to ensure that the next IP's socket gets a different
569      file descriptor, which can prevent bugs when the curl_multi_socket_action
570      interface is used with certain select() replacements such as kqueue. */
571   curl_socket_t fd_to_close = conn->tempsock[tempindex];
572   conn->tempsock[tempindex] = CURL_SOCKET_BAD;
573 
574   if(sockindex == FIRSTSOCKET) {
575     Curl_addrinfo *ai = NULL;
576     int family = AF_UNSPEC;
577 
578     if(conn->tempaddr[tempindex]) {
579       /* find next address in the same protocol family */
580       family = conn->tempaddr[tempindex]->ai_family;
581       ai = conn->tempaddr[tempindex]->ai_next;
582     }
583 #ifdef ENABLE_IPV6
584     else if(conn->tempaddr[0]) {
585       /* happy eyeballs - try the other protocol family */
586       int firstfamily = conn->tempaddr[0]->ai_family;
587       family = (firstfamily == AF_INET) ? AF_INET6 : AF_INET;
588       ai = conn->tempaddr[0]->ai_next;
589     }
590 #endif
591 
592     while(ai) {
593       if(conn->tempaddr[other]) {
594         /* we can safely skip addresses of the other protocol family */
595         while(ai && ai->ai_family != family)
596           ai = ai->ai_next;
597       }
598 
599       if(ai) {
600         result = singleipconnect(conn, ai, tempindex);
601         if(result == CURLE_COULDNT_CONNECT) {
602           ai = ai->ai_next;
603           continue;
604         }
605 
606         conn->tempaddr[tempindex] = ai;
607       }
608       break;
609     }
610   }
611 
612   if(fd_to_close != CURL_SOCKET_BAD)
613     Curl_closesocket(conn, fd_to_close);
614 
615   return result;
616 }
617 
618 /* Copies connection info into the session handle to make it available
619    when the session handle is no longer associated with a connection. */
Curl_persistconninfo(struct connectdata * conn)620 void Curl_persistconninfo(struct connectdata *conn)
621 {
622   memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
623   memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
624   conn->data->info.conn_scheme = conn->handler->scheme;
625   conn->data->info.conn_protocol = conn->handler->protocol;
626   conn->data->info.conn_primary_port = conn->primary_port;
627   conn->data->info.conn_local_port = conn->local_port;
628 }
629 
630 /* retrieves ip address and port from a sockaddr structure.
631    note it calls Curl_inet_ntop which sets errno on fail, not SOCKERRNO. */
Curl_addr2string(struct sockaddr * sa,curl_socklen_t salen,char * addr,long * port)632 bool Curl_addr2string(struct sockaddr *sa, curl_socklen_t salen,
633                       char *addr, long *port)
634 {
635   struct sockaddr_in *si = NULL;
636 #ifdef ENABLE_IPV6
637   struct sockaddr_in6 *si6 = NULL;
638 #endif
639 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
640   struct sockaddr_un *su = NULL;
641 #else
642   (void)salen;
643 #endif
644 
645   switch(sa->sa_family) {
646     case AF_INET:
647       si = (struct sockaddr_in *)(void *) sa;
648       if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
649                         addr, MAX_IPADR_LEN)) {
650         unsigned short us_port = ntohs(si->sin_port);
651         *port = us_port;
652         return TRUE;
653       }
654       break;
655 #ifdef ENABLE_IPV6
656     case AF_INET6:
657       si6 = (struct sockaddr_in6 *)(void *) sa;
658       if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
659                         addr, MAX_IPADR_LEN)) {
660         unsigned short us_port = ntohs(si6->sin6_port);
661         *port = us_port;
662         return TRUE;
663       }
664       break;
665 #endif
666 #if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
667     case AF_UNIX:
668       if(salen > sizeof(sa_family_t)) {
669         su = (struct sockaddr_un*)sa;
670         msnprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
671       }
672       else
673         addr[0] = 0; /* socket with no name */
674       *port = 0;
675       return TRUE;
676 #endif
677     default:
678       break;
679   }
680 
681   addr[0] = '\0';
682   *port = 0;
683   errno = EAFNOSUPPORT;
684   return FALSE;
685 }
686 
687 /* retrieves the start/end point information of a socket of an established
688    connection */
Curl_updateconninfo(struct connectdata * conn,curl_socket_t sockfd)689 void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
690 {
691   if(conn->transport != TRNSPRT_TCP)
692     /* there's no TCP connection! */
693     return;
694 
695 #if defined(HAVE_GETPEERNAME) || defined(HAVE_GETSOCKNAME)
696   if(!conn->bits.reuse && !conn->bits.tcp_fastopen) {
697     struct Curl_easy *data = conn->data;
698     char buffer[STRERROR_LEN];
699     struct Curl_sockaddr_storage ssrem;
700     struct Curl_sockaddr_storage ssloc;
701     curl_socklen_t plen;
702     curl_socklen_t slen;
703 #ifdef HAVE_GETPEERNAME
704     plen = sizeof(struct Curl_sockaddr_storage);
705     if(getpeername(sockfd, (struct sockaddr*) &ssrem, &plen)) {
706       int error = SOCKERRNO;
707       failf(data, "getpeername() failed with errno %d: %s",
708             error, Curl_strerror(error, buffer, sizeof(buffer)));
709       return;
710     }
711 #endif
712 #ifdef HAVE_GETSOCKNAME
713     slen = sizeof(struct Curl_sockaddr_storage);
714     memset(&ssloc, 0, sizeof(ssloc));
715     if(getsockname(sockfd, (struct sockaddr*) &ssloc, &slen)) {
716       int error = SOCKERRNO;
717       failf(data, "getsockname() failed with errno %d: %s",
718             error, Curl_strerror(error, buffer, sizeof(buffer)));
719       return;
720     }
721 #endif
722 #ifdef HAVE_GETPEERNAME
723     if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
724                          conn->primary_ip, &conn->primary_port)) {
725       failf(data, "ssrem inet_ntop() failed with errno %d: %s",
726             errno, Curl_strerror(errno, buffer, sizeof(buffer)));
727       return;
728     }
729     memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
730 #endif
731 #ifdef HAVE_GETSOCKNAME
732     if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
733                          conn->local_ip, &conn->local_port)) {
734       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
735             errno, Curl_strerror(errno, buffer, sizeof(buffer)));
736       return;
737     }
738 #endif
739   }
740 #else /* !HAVE_GETSOCKNAME && !HAVE_GETPEERNAME */
741   (void)sockfd; /* unused */
742 #endif
743 
744   /* persist connection info in session handle */
745   Curl_persistconninfo(conn);
746 }
747 
748 /* after a TCP connection to the proxy has been verified, this function does
749    the next magic step.
750 
751    Note: this function's sub-functions call failf()
752 
753 */
connected_proxy(struct connectdata * conn,int sockindex)754 static CURLcode connected_proxy(struct connectdata *conn, int sockindex)
755 {
756   CURLcode result = CURLE_OK;
757 
758   if(conn->bits.socksproxy) {
759 #ifndef CURL_DISABLE_PROXY
760     /* for the secondary socket (FTP), use the "connect to host"
761      * but ignore the "connect to port" (use the secondary port)
762      */
763     const char * const host = conn->bits.httpproxy ?
764                               conn->http_proxy.host.name :
765                               conn->bits.conn_to_host ?
766                               conn->conn_to_host.name :
767                               sockindex == SECONDARYSOCKET ?
768                               conn->secondaryhostname : conn->host.name;
769     const int port = conn->bits.httpproxy ? (int)conn->http_proxy.port :
770                      sockindex == SECONDARYSOCKET ? conn->secondary_port :
771                      conn->bits.conn_to_port ? conn->conn_to_port :
772                      conn->remote_port;
773     conn->bits.socksproxy_connecting = TRUE;
774     switch(conn->socks_proxy.proxytype) {
775     case CURLPROXY_SOCKS5:
776     case CURLPROXY_SOCKS5_HOSTNAME:
777       result = Curl_SOCKS5(conn->socks_proxy.user, conn->socks_proxy.passwd,
778                          host, port, sockindex, conn);
779       break;
780 
781     case CURLPROXY_SOCKS4:
782     case CURLPROXY_SOCKS4A:
783       result = Curl_SOCKS4(conn->socks_proxy.user, host, port, sockindex,
784                            conn);
785       break;
786 
787     default:
788       failf(conn->data, "unknown proxytype option given");
789       result = CURLE_COULDNT_CONNECT;
790     } /* switch proxytype */
791     conn->bits.socksproxy_connecting = FALSE;
792 #else
793   (void)sockindex;
794 #endif /* CURL_DISABLE_PROXY */
795   }
796 
797   return result;
798 }
799 
800 /*
801  * Curl_is_connected() checks if the socket has connected.
802  */
803 
Curl_is_connected(struct connectdata * conn,int sockindex,bool * connected)804 CURLcode Curl_is_connected(struct connectdata *conn,
805                            int sockindex,
806                            bool *connected)
807 {
808   struct Curl_easy *data = conn->data;
809   CURLcode result = CURLE_OK;
810   timediff_t allow;
811   int error = 0;
812   struct curltime now;
813   int rc;
814   int i;
815 
816   DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
817 
818   *connected = FALSE; /* a very negative world view is best */
819 
820   if(conn->bits.tcpconnect[sockindex]) {
821     /* we are connected already! */
822     *connected = TRUE;
823     return CURLE_OK;
824   }
825 
826   now = Curl_now();
827 
828   /* figure out how long time we have left to connect */
829   allow = Curl_timeleft(data, &now, TRUE);
830 
831   if(allow < 0) {
832     /* time-out, bail out, go home */
833     failf(data, "Connection time-out");
834     return CURLE_OPERATION_TIMEDOUT;
835   }
836 
837   for(i = 0; i<2; i++) {
838     const int other = i ^ 1;
839     if(conn->tempsock[i] == CURL_SOCKET_BAD)
840       continue;
841 
842 #ifdef ENABLE_QUIC
843     if(conn->transport == TRNSPRT_QUIC) {
844       result = Curl_quic_is_connected(conn, i, connected);
845       if(result) {
846         error = SOCKERRNO;
847         goto error;
848       }
849       if(*connected) {
850         /* use this socket from now on */
851         conn->sock[sockindex] = conn->tempsock[i];
852         conn->ip_addr = conn->tempaddr[i];
853         conn->tempsock[i] = CURL_SOCKET_BAD;
854         connkeep(conn, "HTTP/3 default");
855       }
856       return result;
857     }
858 #endif
859 
860 #ifdef mpeix
861     /* Call this function once now, and ignore the results. We do this to
862        "clear" the error state on the socket so that we can later read it
863        reliably. This is reported necessary on the MPE/iX operating system. */
864     (void)verifyconnect(conn->tempsock[i], NULL);
865 #endif
866 
867     /* check socket for connect */
868     rc = SOCKET_WRITABLE(conn->tempsock[i], 0);
869 
870     if(rc == 0) { /* no connection yet */
871       error = 0;
872       if(Curl_timediff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
873         infof(data, "After %" CURL_FORMAT_TIMEDIFF_T
874               "ms connect time, move on!\n", conn->timeoutms_per_addr);
875         error = ETIMEDOUT;
876       }
877 
878       /* should we try another protocol family? */
879       if(i == 0 && conn->tempaddr[1] == NULL &&
880          (Curl_timediff(now, conn->connecttime) >=
881           data->set.happy_eyeballs_timeout)) {
882         trynextip(conn, sockindex, 1);
883       }
884     }
885     else if(rc == CURL_CSELECT_OUT || conn->bits.tcp_fastopen) {
886       if(verifyconnect(conn->tempsock[i], &error)) {
887         /* we are connected with TCP, awesome! */
888 
889         /* use this socket from now on */
890         conn->sock[sockindex] = conn->tempsock[i];
891         conn->ip_addr = conn->tempaddr[i];
892         conn->tempsock[i] = CURL_SOCKET_BAD;
893 #ifdef ENABLE_IPV6
894         conn->bits.ipv6 = (conn->ip_addr->ai_family == AF_INET6)?TRUE:FALSE;
895 #endif
896 
897         /* close the other socket, if open */
898         if(conn->tempsock[other] != CURL_SOCKET_BAD) {
899           Curl_closesocket(conn, conn->tempsock[other]);
900           conn->tempsock[other] = CURL_SOCKET_BAD;
901         }
902 
903         /* see if we need to do any proxy magic first once we connected */
904         result = connected_proxy(conn, sockindex);
905         if(result)
906           return result;
907 
908         conn->bits.tcpconnect[sockindex] = TRUE;
909 
910         *connected = TRUE;
911         if(sockindex == FIRSTSOCKET)
912           Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
913         Curl_updateconninfo(conn, conn->sock[sockindex]);
914         Curl_verboseconnect(conn);
915 
916         return CURLE_OK;
917       }
918       infof(data, "Connection failed\n");
919     }
920     else if(rc & CURL_CSELECT_ERR)
921       (void)verifyconnect(conn->tempsock[i], &error);
922 
923 #ifdef ENABLE_QUIC
924     error:
925 #endif
926     /*
927      * The connection failed here, we should attempt to connect to the "next
928      * address" for the given host. But first remember the latest error.
929      */
930     if(error) {
931       data->state.os_errno = error;
932       SET_SOCKERRNO(error);
933       if(conn->tempaddr[i]) {
934         CURLcode status;
935         char ipaddress[MAX_IPADR_LEN];
936         char buffer[STRERROR_LEN];
937         Curl_printable_address(conn->tempaddr[i], ipaddress, MAX_IPADR_LEN);
938         infof(data, "connect to %s port %ld failed: %s\n",
939               ipaddress, conn->port,
940               Curl_strerror(error, buffer, sizeof(buffer)));
941 
942         conn->timeoutms_per_addr = conn->tempaddr[i]->ai_next == NULL ?
943           allow : allow / 2;
944 
945         status = trynextip(conn, sockindex, i);
946         if((status != CURLE_COULDNT_CONNECT) ||
947            conn->tempsock[other] == CURL_SOCKET_BAD)
948           /* the last attempt failed and no other sockets remain open */
949           result = status;
950       }
951     }
952   }
953 
954   if(result) {
955     /* no more addresses to try */
956     const char *hostname;
957     char buffer[STRERROR_LEN];
958 
959     /* if the first address family runs out of addresses to try before
960        the happy eyeball timeout, go ahead and try the next family now */
961     if(conn->tempaddr[1] == NULL) {
962       result = trynextip(conn, sockindex, 1);
963       if(!result)
964         return result;
965     }
966 
967     if(conn->bits.socksproxy)
968       hostname = conn->socks_proxy.host.name;
969     else if(conn->bits.httpproxy)
970       hostname = conn->http_proxy.host.name;
971     else if(conn->bits.conn_to_host)
972       hostname = conn->conn_to_host.name;
973     else
974       hostname = conn->host.name;
975 
976     failf(data, "Failed to connect to %s port %ld: %s",
977           hostname, conn->port,
978           Curl_strerror(error, buffer, sizeof(buffer)));
979   }
980 
981   return result;
982 }
983 
tcpnodelay(struct connectdata * conn,curl_socket_t sockfd)984 static void tcpnodelay(struct connectdata *conn, curl_socket_t sockfd)
985 {
986 #if defined(TCP_NODELAY)
987 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
988   struct Curl_easy *data = conn->data;
989 #endif
990   curl_socklen_t onoff = (curl_socklen_t) 1;
991   int level = IPPROTO_TCP;
992   char buffer[STRERROR_LEN];
993 
994 #if defined(CURL_DISABLE_VERBOSE_STRINGS)
995   (void) conn;
996 #endif
997 
998   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
999                 sizeof(onoff)) < 0)
1000     infof(data, "Could not set TCP_NODELAY: %s\n",
1001           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1002   else
1003     infof(data, "TCP_NODELAY set\n");
1004 #else
1005   (void)conn;
1006   (void)sockfd;
1007 #endif
1008 }
1009 
1010 #ifdef SO_NOSIGPIPE
1011 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
1012    sending data to a dead peer (instead of relying on the 4th argument to send
1013    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
1014    systems? */
nosigpipe(struct connectdata * conn,curl_socket_t sockfd)1015 static void nosigpipe(struct connectdata *conn,
1016                       curl_socket_t sockfd)
1017 {
1018   struct Curl_easy *data = conn->data;
1019   int onoff = 1;
1020   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
1021                 sizeof(onoff)) < 0) {
1022     char buffer[STRERROR_LEN];
1023     infof(data, "Could not set SO_NOSIGPIPE: %s\n",
1024           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1025   }
1026 }
1027 #else
1028 #define nosigpipe(x,y) Curl_nop_stmt
1029 #endif
1030 
1031 #ifdef USE_WINSOCK
1032 /* When you run a program that uses the Windows Sockets API, you may
1033    experience slow performance when you copy data to a TCP server.
1034 
1035    https://support.microsoft.com/kb/823764
1036 
1037    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
1038    Buffer Size
1039 
1040    The problem described in this knowledge-base is applied only to pre-Vista
1041    Windows.  Following function trying to detect OS version and skips
1042    SO_SNDBUF adjustment for Windows Vista and above.
1043 */
1044 #define DETECT_OS_NONE 0
1045 #define DETECT_OS_PREVISTA 1
1046 #define DETECT_OS_VISTA_OR_LATER 2
1047 
Curl_sndbufset(curl_socket_t sockfd)1048 void Curl_sndbufset(curl_socket_t sockfd)
1049 {
1050   int val = CURL_MAX_WRITE_SIZE + 32;
1051   int curval = 0;
1052   int curlen = sizeof(curval);
1053 
1054   static int detectOsState = DETECT_OS_NONE;
1055 
1056   if(detectOsState == DETECT_OS_NONE) {
1057     if(Curl_verify_windows_version(6, 0, PLATFORM_WINNT,
1058                                    VERSION_GREATER_THAN_EQUAL))
1059       detectOsState = DETECT_OS_VISTA_OR_LATER;
1060     else
1061       detectOsState = DETECT_OS_PREVISTA;
1062   }
1063 
1064   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
1065     return;
1066 
1067   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
1068     if(curval > val)
1069       return;
1070 
1071   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
1072 }
1073 #endif
1074 
1075 /*
1076  * singleipconnect()
1077  *
1078  * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
1079  * CURL_SOCKET_BAD. Other errors will however return proper errors.
1080  *
1081  * singleipconnect() connects to the given IP only, and it may return without
1082  * having connected.
1083  */
singleipconnect(struct connectdata * conn,const Curl_addrinfo * ai,int sockindex)1084 static CURLcode singleipconnect(struct connectdata *conn,
1085                                 const Curl_addrinfo *ai,
1086                                 int sockindex)
1087 {
1088   struct Curl_sockaddr_ex addr;
1089   int rc = -1;
1090   int error = 0;
1091   bool isconnected = FALSE;
1092   struct Curl_easy *data = conn->data;
1093   curl_socket_t sockfd;
1094   CURLcode result;
1095   char ipaddress[MAX_IPADR_LEN];
1096   long port;
1097   bool is_tcp;
1098 #ifdef TCP_FASTOPEN_CONNECT
1099   int optval = 1;
1100 #endif
1101   char buffer[STRERROR_LEN];
1102   curl_socket_t *sockp = &conn->tempsock[sockindex];
1103   *sockp = CURL_SOCKET_BAD;
1104 
1105   result = Curl_socket(conn, ai, &addr, &sockfd);
1106   if(result)
1107     /* Failed to create the socket, but still return OK since we signal the
1108        lack of socket as well. This allows the parent function to keep looping
1109        over alternative addresses/socket families etc. */
1110     return CURLE_OK;
1111 
1112   /* store remote address and port used in this connection attempt */
1113   if(!Curl_addr2string((struct sockaddr*)&addr.sa_addr, addr.addrlen,
1114                        ipaddress, &port)) {
1115     /* malformed address or bug in inet_ntop, try next address */
1116     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
1117           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1118     Curl_closesocket(conn, sockfd);
1119     return CURLE_OK;
1120   }
1121   infof(data, "  Trying %s:%ld...\n", ipaddress, port);
1122 
1123 #ifdef ENABLE_IPV6
1124   is_tcp = (addr.family == AF_INET || addr.family == AF_INET6) &&
1125     addr.socktype == SOCK_STREAM;
1126 #else
1127   is_tcp = (addr.family == AF_INET) && addr.socktype == SOCK_STREAM;
1128 #endif
1129   if(is_tcp && data->set.tcp_nodelay)
1130     tcpnodelay(conn, sockfd);
1131 
1132   nosigpipe(conn, sockfd);
1133 
1134   Curl_sndbufset(sockfd);
1135 
1136   if(is_tcp && data->set.tcp_keepalive)
1137     tcpkeepalive(data, sockfd);
1138 
1139   if(data->set.fsockopt) {
1140     /* activate callback for setting socket options */
1141     Curl_set_in_callback(data, true);
1142     error = data->set.fsockopt(data->set.sockopt_client,
1143                                sockfd,
1144                                CURLSOCKTYPE_IPCXN);
1145     Curl_set_in_callback(data, false);
1146 
1147     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1148       isconnected = TRUE;
1149     else if(error) {
1150       Curl_closesocket(conn, sockfd); /* close the socket and bail out */
1151       return CURLE_ABORTED_BY_CALLBACK;
1152     }
1153   }
1154 
1155   /* possibly bind the local end to an IP, interface or port */
1156   if(addr.family == AF_INET
1157 #ifdef ENABLE_IPV6
1158      || addr.family == AF_INET6
1159 #endif
1160     ) {
1161     result = bindlocal(conn, sockfd, addr.family,
1162                        Curl_ipv6_scope((struct sockaddr*)&addr.sa_addr));
1163     if(result) {
1164       Curl_closesocket(conn, sockfd); /* close socket and bail out */
1165       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1166         /* The address family is not supported on this interface.
1167            We can continue trying addresses */
1168         return CURLE_COULDNT_CONNECT;
1169       }
1170       return result;
1171     }
1172   }
1173 
1174   /* set socket non-blocking */
1175   (void)curlx_nonblock(sockfd, TRUE);
1176 
1177   conn->connecttime = Curl_now();
1178   if(conn->num_addr > 1)
1179     Curl_expire(data, conn->timeoutms_per_addr, EXPIRE_DNS_PER_NAME);
1180 
1181   /* Connect TCP and QUIC sockets */
1182   if(!isconnected && (conn->transport != TRNSPRT_UDP)) {
1183     if(conn->bits.tcp_fastopen) {
1184 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1185 #  if defined(HAVE_BUILTIN_AVAILABLE)
1186       /* while connectx function is available since macOS 10.11 / iOS 9,
1187          it did not have the interface declared correctly until
1188          Xcode 9 / macOS SDK 10.13 */
1189       if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1190         sa_endpoints_t endpoints;
1191         endpoints.sae_srcif = 0;
1192         endpoints.sae_srcaddr = NULL;
1193         endpoints.sae_srcaddrlen = 0;
1194         endpoints.sae_dstaddr = &addr.sa_addr;
1195         endpoints.sae_dstaddrlen = addr.addrlen;
1196 
1197         rc = connectx(sockfd, &endpoints, SAE_ASSOCID_ANY,
1198                       CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1199                       NULL, 0, NULL, NULL);
1200       }
1201       else {
1202         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1203       }
1204 #  else
1205       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1206 #  endif /* HAVE_BUILTIN_AVAILABLE */
1207 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1208       if(setsockopt(sockfd, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1209                     (void *)&optval, sizeof(optval)) < 0)
1210         infof(data, "Failed to enable TCP Fast Open on fd %d\n", sockfd);
1211       else
1212         infof(data, "TCP_FASTOPEN_CONNECT set\n");
1213 
1214       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1215 #elif defined(MSG_FASTOPEN) /* old Linux */
1216       if(conn->given->flags & PROTOPT_SSL)
1217         rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1218       else
1219         rc = 0; /* Do nothing */
1220 #endif
1221     }
1222     else {
1223       rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
1224     }
1225 
1226     if(-1 == rc)
1227       error = SOCKERRNO;
1228 #ifdef ENABLE_QUIC
1229     else if(conn->transport == TRNSPRT_QUIC) {
1230       /* pass in 'sockfd' separately since it hasn't been put into the
1231          tempsock array at this point */
1232       result = Curl_quic_connect(conn, sockfd, sockindex,
1233                                  &addr.sa_addr, addr.addrlen);
1234       if(result)
1235         error = SOCKERRNO;
1236     }
1237 #endif
1238   }
1239   else {
1240     *sockp = sockfd;
1241     return CURLE_OK;
1242   }
1243 
1244   if(-1 == rc) {
1245     switch(error) {
1246     case EINPROGRESS:
1247     case EWOULDBLOCK:
1248 #if defined(EAGAIN)
1249 #if (EAGAIN) != (EWOULDBLOCK)
1250       /* On some platforms EAGAIN and EWOULDBLOCK are the
1251        * same value, and on others they are different, hence
1252        * the odd #if
1253        */
1254     case EAGAIN:
1255 #endif
1256 #endif
1257       result = CURLE_OK;
1258       break;
1259 
1260     default:
1261       /* unknown error, fallthrough and try another address! */
1262       infof(data, "Immediate connect fail for %s: %s\n",
1263             ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
1264       data->state.os_errno = error;
1265 
1266       /* connect failed */
1267       Curl_closesocket(conn, sockfd);
1268       result = CURLE_COULDNT_CONNECT;
1269     }
1270   }
1271 
1272   if(!result)
1273     *sockp = sockfd;
1274 
1275   return result;
1276 }
1277 
1278 /*
1279  * TCP connect to the given host with timeout, proxy or remote doesn't matter.
1280  * There might be more than one IP address to try out. Fill in the passed
1281  * pointer with the connected socket.
1282  */
1283 
Curl_connecthost(struct connectdata * conn,const struct Curl_dns_entry * remotehost)1284 CURLcode Curl_connecthost(struct connectdata *conn,  /* context */
1285                           const struct Curl_dns_entry *remotehost)
1286 {
1287   struct Curl_easy *data = conn->data;
1288   struct curltime before = Curl_now();
1289   CURLcode result = CURLE_COULDNT_CONNECT;
1290 
1291   timediff_t timeout_ms = Curl_timeleft(data, &before, TRUE);
1292 
1293   if(timeout_ms < 0) {
1294     /* a precaution, no need to continue if time already is up */
1295     failf(data, "Connection time-out");
1296     return CURLE_OPERATION_TIMEDOUT;
1297   }
1298 
1299   conn->num_addr = Curl_num_addresses(remotehost->addr);
1300   conn->tempaddr[0] = remotehost->addr;
1301   conn->tempaddr[1] = NULL;
1302   conn->tempsock[0] = CURL_SOCKET_BAD;
1303   conn->tempsock[1] = CURL_SOCKET_BAD;
1304 
1305   /* Max time for the next connection attempt */
1306   conn->timeoutms_per_addr =
1307     conn->tempaddr[0]->ai_next == NULL ? timeout_ms : timeout_ms / 2;
1308 
1309   /* start connecting to first IP */
1310   while(conn->tempaddr[0]) {
1311     result = singleipconnect(conn, conn->tempaddr[0], 0);
1312     if(!result)
1313       break;
1314     conn->tempaddr[0] = conn->tempaddr[0]->ai_next;
1315   }
1316 
1317   if(conn->tempsock[0] == CURL_SOCKET_BAD) {
1318     if(!result)
1319       result = CURLE_COULDNT_CONNECT;
1320     return result;
1321   }
1322 
1323   data->info.numconnects++; /* to track the number of connections made */
1324   Curl_expire(conn->data, data->set.happy_eyeballs_timeout,
1325               EXPIRE_HAPPY_EYEBALLS);
1326 
1327   return CURLE_OK;
1328 }
1329 
1330 struct connfind {
1331   struct connectdata *tofind;
1332   bool found;
1333 };
1334 
conn_is_conn(struct connectdata * conn,void * param)1335 static int conn_is_conn(struct connectdata *conn, void *param)
1336 {
1337   struct connfind *f = (struct connfind *)param;
1338   if(conn == f->tofind) {
1339     f->found = TRUE;
1340     return 1;
1341   }
1342   return 0;
1343 }
1344 
1345 /*
1346  * Used to extract socket and connectdata struct for the most recent
1347  * transfer on the given Curl_easy.
1348  *
1349  * The returned socket will be CURL_SOCKET_BAD in case of failure!
1350  */
Curl_getconnectinfo(struct Curl_easy * data,struct connectdata ** connp)1351 curl_socket_t Curl_getconnectinfo(struct Curl_easy *data,
1352                                   struct connectdata **connp)
1353 {
1354   DEBUGASSERT(data);
1355 
1356   /* this works for an easy handle:
1357    * - that has been used for curl_easy_perform()
1358    * - that is associated with a multi handle, and whose connection
1359    *   was detached with CURLOPT_CONNECT_ONLY
1360    */
1361   if(data->state.lastconnect && (data->multi_easy || data->multi)) {
1362     struct connectdata *c = data->state.lastconnect;
1363     struct connfind find;
1364     find.tofind = data->state.lastconnect;
1365     find.found = FALSE;
1366 
1367     Curl_conncache_foreach(data, data->multi_easy?
1368                            &data->multi_easy->conn_cache:
1369                            &data->multi->conn_cache, &find, conn_is_conn);
1370 
1371     if(!find.found) {
1372       data->state.lastconnect = NULL;
1373       return CURL_SOCKET_BAD;
1374     }
1375 
1376     if(connp) {
1377       /* only store this if the caller cares for it */
1378       *connp = c;
1379       c->data = data;
1380     }
1381     return c->sock[FIRSTSOCKET];
1382   }
1383   else
1384     return CURL_SOCKET_BAD;
1385 }
1386 
1387 /*
1388  * Check if a connection seems to be alive.
1389  */
Curl_connalive(struct connectdata * conn)1390 bool Curl_connalive(struct connectdata *conn)
1391 {
1392   /* First determine if ssl */
1393   if(conn->ssl[FIRSTSOCKET].use) {
1394     /* use the SSL context */
1395     if(!Curl_ssl_check_cxn(conn))
1396       return false;   /* FIN received */
1397   }
1398 /* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
1399 #ifdef MSG_PEEK
1400   else if(conn->sock[FIRSTSOCKET] == CURL_SOCKET_BAD)
1401     return false;
1402   else {
1403     /* use the socket */
1404     char buf;
1405     if(recv((RECV_TYPE_ARG1)conn->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
1406             (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
1407       return false;   /* FIN received */
1408     }
1409   }
1410 #endif
1411   return true;
1412 }
1413 
1414 /*
1415  * Close a socket.
1416  *
1417  * 'conn' can be NULL, beware!
1418  */
Curl_closesocket(struct connectdata * conn,curl_socket_t sock)1419 int Curl_closesocket(struct connectdata *conn,
1420                       curl_socket_t sock)
1421 {
1422   if(conn && conn->fclosesocket) {
1423     if((sock == conn->sock[SECONDARYSOCKET]) &&
1424        conn->sock_accepted[SECONDARYSOCKET])
1425       /* if this socket matches the second socket, and that was created with
1426          accept, then we MUST NOT call the callback but clear the accepted
1427          status */
1428       conn->sock_accepted[SECONDARYSOCKET] = FALSE;
1429     else {
1430       int rc;
1431       Curl_multi_closed(conn->data, sock);
1432       Curl_set_in_callback(conn->data, true);
1433       rc = conn->fclosesocket(conn->closesocket_client, sock);
1434       Curl_set_in_callback(conn->data, false);
1435       return rc;
1436     }
1437   }
1438 
1439   if(conn)
1440     /* tell the multi-socket code about this */
1441     Curl_multi_closed(conn->data, sock);
1442 
1443   sclose(sock);
1444 
1445   return 0;
1446 }
1447 
1448 /*
1449  * Create a socket based on info from 'conn' and 'ai'.
1450  *
1451  * 'addr' should be a pointer to the correct struct to get data back, or NULL.
1452  * 'sockfd' must be a pointer to a socket descriptor.
1453  *
1454  * If the open socket callback is set, used that!
1455  *
1456  */
Curl_socket(struct connectdata * conn,const Curl_addrinfo * ai,struct Curl_sockaddr_ex * addr,curl_socket_t * sockfd)1457 CURLcode Curl_socket(struct connectdata *conn,
1458                      const Curl_addrinfo *ai,
1459                      struct Curl_sockaddr_ex *addr,
1460                      curl_socket_t *sockfd)
1461 {
1462   struct Curl_easy *data = conn->data;
1463   struct Curl_sockaddr_ex dummy;
1464 
1465   if(!addr)
1466     /* if the caller doesn't want info back, use a local temp copy */
1467     addr = &dummy;
1468 
1469   /*
1470    * The Curl_sockaddr_ex structure is basically libcurl's external API
1471    * curl_sockaddr structure with enough space available to directly hold
1472    * any protocol-specific address structures. The variable declared here
1473    * will be used to pass / receive data to/from the fopensocket callback
1474    * if this has been set, before that, it is initialized from parameters.
1475    */
1476 
1477   addr->family = ai->ai_family;
1478   addr->socktype = (conn->transport == TRNSPRT_TCP) ? SOCK_STREAM : SOCK_DGRAM;
1479   addr->protocol = conn->transport != TRNSPRT_TCP ? IPPROTO_UDP :
1480     ai->ai_protocol;
1481   addr->addrlen = ai->ai_addrlen;
1482 
1483   if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
1484      addr->addrlen = sizeof(struct Curl_sockaddr_storage);
1485   memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
1486 
1487   if(data->set.fopensocket) {
1488    /*
1489     * If the opensocket callback is set, all the destination address
1490     * information is passed to the callback. Depending on this information the
1491     * callback may opt to abort the connection, this is indicated returning
1492     * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
1493     * the callback returns a valid socket the destination address information
1494     * might have been changed and this 'new' address will actually be used
1495     * here to connect.
1496     */
1497     Curl_set_in_callback(data, true);
1498     *sockfd = data->set.fopensocket(data->set.opensocket_client,
1499                                     CURLSOCKTYPE_IPCXN,
1500                                     (struct curl_sockaddr *)addr);
1501     Curl_set_in_callback(data, false);
1502   }
1503   else
1504     /* opensocket callback not set, so simply create the socket now */
1505     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
1506 
1507   if(*sockfd == CURL_SOCKET_BAD)
1508     /* no socket, no connection */
1509     return CURLE_COULDNT_CONNECT;
1510 
1511 #if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
1512   if(conn->scope_id && (addr->family == AF_INET6)) {
1513     struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
1514     sa6->sin6_scope_id = conn->scope_id;
1515   }
1516 #endif
1517 
1518   return CURLE_OK;
1519 
1520 }
1521 
1522 /*
1523  * Curl_conncontrol() marks streams or connection for closure.
1524  */
Curl_conncontrol(struct connectdata * conn,int ctrl,const char * reason)1525 void Curl_conncontrol(struct connectdata *conn,
1526                       int ctrl /* see defines in header */
1527 #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
1528                       , const char *reason
1529 #endif
1530   )
1531 {
1532   /* close if a connection, or a stream that isn't multiplexed */
1533   bool closeit = (ctrl == CONNCTRL_CONNECTION) ||
1534     ((ctrl == CONNCTRL_STREAM) && !(conn->handler->flags & PROTOPT_STREAM));
1535   if((ctrl == CONNCTRL_STREAM) &&
1536      (conn->handler->flags & PROTOPT_STREAM))
1537     DEBUGF(infof(conn->data, "Kill stream: %s\n", reason));
1538   else if((bit)closeit != conn->bits.close) {
1539     DEBUGF(infof(conn->data, "Marked for [%s]: %s\n",
1540                  closeit?"closure":"keep alive", reason));
1541     conn->bits.close = closeit; /* the only place in the source code that
1542                                    should assign this bit */
1543   }
1544 }
1545 
1546 /* Data received can be cached at various levels, so check them all here. */
Curl_conn_data_pending(struct connectdata * conn,int sockindex)1547 bool Curl_conn_data_pending(struct connectdata *conn, int sockindex)
1548 {
1549   int readable;
1550 
1551   if(Curl_ssl_data_pending(conn, sockindex) ||
1552      Curl_recv_has_postponed_data(conn, sockindex))
1553     return true;
1554 
1555   readable = SOCKET_READABLE(conn->sock[sockindex], 0);
1556   return (readable > 0 && (readable & CURL_CSELECT_IN));
1557 }
1558