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