• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 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.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  * SPDX-License-Identifier: curl
22  *
23  ***************************************************************************/
24 
25 #include "curl_setup.h"
26 
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h> /* <netinet/tcp.h> may need it */
29 #endif
30 #ifdef HAVE_SYS_UN_H
31 #include <sys/un.h> /* for sockaddr_un */
32 #endif
33 #ifdef HAVE_LINUX_TCP_H
34 #include <linux/tcp.h>
35 #elif defined(HAVE_NETINET_TCP_H)
36 #include <netinet/tcp.h>
37 #endif
38 #ifdef HAVE_SYS_IOCTL_H
39 #include <sys/ioctl.h>
40 #endif
41 #ifdef HAVE_NETDB_H
42 #include <netdb.h>
43 #endif
44 #ifdef HAVE_FCNTL_H
45 #include <fcntl.h>
46 #endif
47 #ifdef HAVE_ARPA_INET_H
48 #include <arpa/inet.h>
49 #endif
50 
51 #ifdef __VMS
52 #include <in.h>
53 #include <inet.h>
54 #endif
55 
56 #include "urldata.h"
57 #include "bufq.h"
58 #include "sendf.h"
59 #include "if2ip.h"
60 #include "strerror.h"
61 #include "cfilters.h"
62 #include "cf-socket.h"
63 #include "connect.h"
64 #include "select.h"
65 #include "url.h" /* for Curl_safefree() */
66 #include "multiif.h"
67 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
68 #include "inet_ntop.h"
69 #include "inet_pton.h"
70 #include "progress.h"
71 #include "warnless.h"
72 #include "conncache.h"
73 #include "multihandle.h"
74 #include "rand.h"
75 #include "share.h"
76 #include "version_win32.h"
77 
78 /* The last 3 #include files should be in this order */
79 #include "curl_printf.h"
80 #include "curl_memory.h"
81 #include "memdebug.h"
82 
83 
84 #if defined(USE_IPV6) && defined(IPV6_V6ONLY) && defined(_WIN32)
85 /* It makes support for IPv4-mapped IPv6 addresses.
86  * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
87  * Windows Vista and later: default is on;
88  * DragonFly BSD: acts like off, and dummy setting;
89  * OpenBSD and earlier Windows: unsupported.
90  * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
91  */
set_ipv6_v6only(curl_socket_t sockfd,int on)92 static void set_ipv6_v6only(curl_socket_t sockfd, int on)
93 {
94   (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
95 }
96 #else
97 #define set_ipv6_v6only(x,y)
98 #endif
99 
tcpnodelay(struct Curl_easy * data,curl_socket_t sockfd)100 static void tcpnodelay(struct Curl_easy *data, curl_socket_t sockfd)
101 {
102 #if defined(TCP_NODELAY)
103   curl_socklen_t onoff = (curl_socklen_t) 1;
104   int level = IPPROTO_TCP;
105   char buffer[STRERROR_LEN];
106 
107   if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
108                 sizeof(onoff)) < 0)
109     infof(data, "Could not set TCP_NODELAY: %s",
110           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
111 #else
112   (void)data;
113   (void)sockfd;
114 #endif
115 }
116 
117 #ifdef SO_NOSIGPIPE
118 /* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
119    sending data to a dead peer (instead of relying on the 4th argument to send
120    being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
121    systems? */
nosigpipe(struct Curl_easy * data,curl_socket_t sockfd)122 static void nosigpipe(struct Curl_easy *data,
123                       curl_socket_t sockfd)
124 {
125   int onoff = 1;
126   (void)data;
127   if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
128                 sizeof(onoff)) < 0) {
129 #if !defined(CURL_DISABLE_VERBOSE_STRINGS)
130     char buffer[STRERROR_LEN];
131     infof(data, "Could not set SO_NOSIGPIPE: %s",
132           Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
133 #endif
134   }
135 }
136 #else
137 #define nosigpipe(x,y) Curl_nop_stmt
138 #endif
139 
140 #if defined(__DragonFly__) || defined(USE_WINSOCK)
141 /* DragonFlyBSD and Windows use millisecond units */
142 #define KEEPALIVE_FACTOR(x) (x *= 1000)
143 #else
144 #define KEEPALIVE_FACTOR(x)
145 #endif
146 
147 #if defined(USE_WINSOCK) && !defined(SIO_KEEPALIVE_VALS)
148 #define SIO_KEEPALIVE_VALS    _WSAIOW(IOC_VENDOR,4)
149 
150 struct tcp_keepalive {
151   u_long onoff;
152   u_long keepalivetime;
153   u_long keepaliveinterval;
154 };
155 #endif
156 
157 static void
tcpkeepalive(struct Curl_easy * data,curl_socket_t sockfd)158 tcpkeepalive(struct Curl_easy *data,
159              curl_socket_t sockfd)
160 {
161   int optval = data->set.tcp_keepalive?1:0;
162 
163   /* only set IDLE and INTVL if setting KEEPALIVE is successful */
164   if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
165         (void *)&optval, sizeof(optval)) < 0) {
166     infof(data, "Failed to set SO_KEEPALIVE on fd "
167           "%" CURL_FORMAT_SOCKET_T ": errno %d",
168           sockfd, SOCKERRNO);
169   }
170   else {
171 #if defined(SIO_KEEPALIVE_VALS)
172     struct tcp_keepalive vals;
173     DWORD dummy;
174     vals.onoff = 1;
175     optval = curlx_sltosi(data->set.tcp_keepidle);
176     KEEPALIVE_FACTOR(optval);
177     vals.keepalivetime = optval;
178     optval = curlx_sltosi(data->set.tcp_keepintvl);
179     KEEPALIVE_FACTOR(optval);
180     vals.keepaliveinterval = optval;
181     if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
182                 NULL, 0, &dummy, NULL, NULL) != 0) {
183       infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd "
184                   "%" CURL_FORMAT_SOCKET_T ": errno %d",
185                   sockfd, SOCKERRNO);
186     }
187 #else
188 #ifdef TCP_KEEPIDLE
189     optval = curlx_sltosi(data->set.tcp_keepidle);
190     KEEPALIVE_FACTOR(optval);
191     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
192           (void *)&optval, sizeof(optval)) < 0) {
193       infof(data, "Failed to set TCP_KEEPIDLE on fd "
194             "%" CURL_FORMAT_SOCKET_T ": errno %d",
195             sockfd, SOCKERRNO);
196     }
197 #elif defined(TCP_KEEPALIVE)
198     /* Mac OS X style */
199     optval = curlx_sltosi(data->set.tcp_keepidle);
200     KEEPALIVE_FACTOR(optval);
201     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
202       (void *)&optval, sizeof(optval)) < 0) {
203       infof(data, "Failed to set TCP_KEEPALIVE on fd "
204             "%" CURL_FORMAT_SOCKET_T ": errno %d",
205             sockfd, SOCKERRNO);
206     }
207 #endif
208 #ifdef TCP_KEEPINTVL
209     optval = curlx_sltosi(data->set.tcp_keepintvl);
210     KEEPALIVE_FACTOR(optval);
211     if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
212           (void *)&optval, sizeof(optval)) < 0) {
213       infof(data, "Failed to set TCP_KEEPINTVL on fd "
214             "%" CURL_FORMAT_SOCKET_T ": errno %d",
215             sockfd, SOCKERRNO);
216     }
217 #endif
218 #endif
219   }
220 }
221 
222 /**
223  * Assign the address `ai` to the Curl_sockaddr_ex `dest` and
224  * set the transport used.
225  */
Curl_sock_assign_addr(struct Curl_sockaddr_ex * dest,const struct Curl_addrinfo * ai,int transport)226 void Curl_sock_assign_addr(struct Curl_sockaddr_ex *dest,
227                            const struct Curl_addrinfo *ai,
228                            int transport)
229 {
230   /*
231    * The Curl_sockaddr_ex structure is basically libcurl's external API
232    * curl_sockaddr structure with enough space available to directly hold
233    * any protocol-specific address structures. The variable declared here
234    * will be used to pass / receive data to/from the fopensocket callback
235    * if this has been set, before that, it is initialized from parameters.
236    */
237   dest->family = ai->ai_family;
238   switch(transport) {
239   case TRNSPRT_TCP:
240     dest->socktype = SOCK_STREAM;
241     dest->protocol = IPPROTO_TCP;
242     break;
243   case TRNSPRT_UNIX:
244     dest->socktype = SOCK_STREAM;
245     dest->protocol = IPPROTO_IP;
246     break;
247   default: /* UDP and QUIC */
248     dest->socktype = SOCK_DGRAM;
249     dest->protocol = IPPROTO_UDP;
250     break;
251   }
252   dest->addrlen = ai->ai_addrlen;
253 
254   if(dest->addrlen > sizeof(struct Curl_sockaddr_storage))
255     dest->addrlen = sizeof(struct Curl_sockaddr_storage);
256   memcpy(&dest->sa_addr, ai->ai_addr, dest->addrlen);
257 }
258 
socket_open(struct Curl_easy * data,struct Curl_sockaddr_ex * addr,curl_socket_t * sockfd)259 static CURLcode socket_open(struct Curl_easy *data,
260                             struct Curl_sockaddr_ex *addr,
261                             curl_socket_t *sockfd)
262 {
263   DEBUGASSERT(data);
264   DEBUGASSERT(data->conn);
265   if(data->set.fopensocket) {
266    /*
267     * If the opensocket callback is set, all the destination address
268     * information is passed to the callback. Depending on this information the
269     * callback may opt to abort the connection, this is indicated returning
270     * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
271     * the callback returns a valid socket the destination address information
272     * might have been changed and this 'new' address will actually be used
273     * here to connect.
274     */
275     Curl_set_in_callback(data, true);
276     *sockfd = data->set.fopensocket(data->set.opensocket_client,
277                                     CURLSOCKTYPE_IPCXN,
278                                     (struct curl_sockaddr *)addr);
279     Curl_set_in_callback(data, false);
280   }
281   else {
282     /* opensocket callback not set, so simply create the socket now */
283     *sockfd = socket(addr->family, addr->socktype, addr->protocol);
284   }
285 
286   if(*sockfd == CURL_SOCKET_BAD)
287     /* no socket, no connection */
288     return CURLE_COULDNT_CONNECT;
289 
290 #if defined(USE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
291   if(data->conn->scope_id && (addr->family == AF_INET6)) {
292     struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
293     sa6->sin6_scope_id = data->conn->scope_id;
294   }
295 #endif
296   return CURLE_OK;
297 }
298 
299 /*
300  * Create a socket based on info from 'conn' and 'ai'.
301  *
302  * 'addr' should be a pointer to the correct struct to get data back, or NULL.
303  * 'sockfd' must be a pointer to a socket descriptor.
304  *
305  * If the open socket callback is set, used that!
306  *
307  */
Curl_socket_open(struct Curl_easy * data,const struct Curl_addrinfo * ai,struct Curl_sockaddr_ex * addr,int transport,curl_socket_t * sockfd)308 CURLcode Curl_socket_open(struct Curl_easy *data,
309                             const struct Curl_addrinfo *ai,
310                             struct Curl_sockaddr_ex *addr,
311                             int transport,
312                             curl_socket_t *sockfd)
313 {
314   struct Curl_sockaddr_ex dummy;
315 
316   if(!addr)
317     /* if the caller doesn't want info back, use a local temp copy */
318     addr = &dummy;
319 
320   Curl_sock_assign_addr(addr, ai, transport);
321   return socket_open(data, addr, sockfd);
322 }
323 
socket_close(struct Curl_easy * data,struct connectdata * conn,int use_callback,curl_socket_t sock)324 static int socket_close(struct Curl_easy *data, struct connectdata *conn,
325                         int use_callback, curl_socket_t sock)
326 {
327   if(use_callback && conn && conn->fclosesocket) {
328     int rc;
329     Curl_multi_closed(data, sock);
330     Curl_set_in_callback(data, true);
331     rc = conn->fclosesocket(conn->closesocket_client, sock);
332     Curl_set_in_callback(data, false);
333     return rc;
334   }
335 
336   if(conn)
337     /* tell the multi-socket code about this */
338     Curl_multi_closed(data, sock);
339 
340   sclose(sock);
341 
342   return 0;
343 }
344 
345 /*
346  * Close a socket.
347  *
348  * 'conn' can be NULL, beware!
349  */
Curl_socket_close(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sock)350 int Curl_socket_close(struct Curl_easy *data, struct connectdata *conn,
351                       curl_socket_t sock)
352 {
353   return socket_close(data, conn, FALSE, sock);
354 }
355 
356 #ifdef USE_WINSOCK
357 /* When you run a program that uses the Windows Sockets API, you may
358    experience slow performance when you copy data to a TCP server.
359 
360    https://support.microsoft.com/kb/823764
361 
362    Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
363    Buffer Size
364 
365    The problem described in this knowledge-base is applied only to pre-Vista
366    Windows.  Following function trying to detect OS version and skips
367    SO_SNDBUF adjustment for Windows Vista and above.
368 */
369 #define DETECT_OS_NONE 0
370 #define DETECT_OS_PREVISTA 1
371 #define DETECT_OS_VISTA_OR_LATER 2
372 
Curl_sndbufset(curl_socket_t sockfd)373 void Curl_sndbufset(curl_socket_t sockfd)
374 {
375   int val = CURL_MAX_WRITE_SIZE + 32;
376   int curval = 0;
377   int curlen = sizeof(curval);
378 
379   static int detectOsState = DETECT_OS_NONE;
380 
381   if(detectOsState == DETECT_OS_NONE) {
382     if(curlx_verify_windows_version(6, 0, 0, PLATFORM_WINNT,
383                                     VERSION_GREATER_THAN_EQUAL))
384       detectOsState = DETECT_OS_VISTA_OR_LATER;
385     else
386       detectOsState = DETECT_OS_PREVISTA;
387   }
388 
389   if(detectOsState == DETECT_OS_VISTA_OR_LATER)
390     return;
391 
392   if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
393     if(curval > val)
394       return;
395 
396   setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
397 }
398 #endif
399 
400 #ifndef CURL_DISABLE_BINDLOCAL
401 #ifdef HTTP_HANDOVER_FEATURE
402 int32_t BindSocket(int32_t fd, uint32_t netId);
bindohosnetid(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sockfd)403 static CURLcode bindohosnetid(struct Curl_easy *data, struct connectdata *conn, curl_socket_t sockfd)
404 {
405   unsigned int netid = data->set.socket_bind_netid;
406   if (netid > 0) {
407     int ret = BindSocket(sockfd, netid);
408     if (ret == 0) {
409       conn->socket_bind_netid = netid;
410       return CURLE_OK;
411     } else {
412       // try bind but failed
413       return CURLE_INTERFACE_FAILED;
414     }
415   }
416   return CURLE_OK;
417 }
418 #endif
419 
bindlocal(struct Curl_easy * data,struct connectdata * conn,curl_socket_t sockfd,int af,unsigned int scope)420 static CURLcode bindlocal(struct Curl_easy *data, struct connectdata *conn,
421                           curl_socket_t sockfd, int af, unsigned int scope)
422 {
423   struct Curl_sockaddr_storage sa;
424   struct sockaddr *sock = (struct sockaddr *)&sa;  /* bind to this address */
425   curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
426   struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
427 #ifdef USE_IPV6
428   struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
429 #endif
430 
431   struct Curl_dns_entry *h = NULL;
432   unsigned short port = data->set.localport; /* use this port number, 0 for
433                                                 "random" */
434   /* how many port numbers to try to bind to, increasing one at a time */
435   int portnum = data->set.localportrange;
436   const char *dev = data->set.str[STRING_DEVICE];
437   int error;
438 #ifdef IP_BIND_ADDRESS_NO_PORT
439   int on = 1;
440 #endif
441 #ifndef USE_IPV6
442   (void)scope;
443 #endif
444 
445   /*************************************************************
446    * Select device to bind socket to
447    *************************************************************/
448 #ifdef HTTP_HANDOVER_FEATURE
449   if (!dev && !port) {
450     /*no local kind of binding was requested */
451     return data->set.socket_bind_netid > 0 ? bindohosnetid(data, conn, sockfd) : CURLE_OK;
452   }
453 #else
454   if(!dev && !port)
455     /* no local kind of binding was requested */
456     return CURLE_OK;
457 #endif
458   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
459 
460   if(dev && (strlen(dev)<255) ) {
461     char myhost[256] = "";
462     int done = 0; /* -1 for error, 1 for address found */
463     bool is_interface = FALSE;
464     bool is_host = FALSE;
465     static const char *if_prefix = "if!";
466     static const char *host_prefix = "host!";
467 
468     if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
469       dev += strlen(if_prefix);
470       is_interface = TRUE;
471     }
472     else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
473       dev += strlen(host_prefix);
474       is_host = TRUE;
475     }
476 
477     /* interface */
478     if(!is_host) {
479 #ifdef SO_BINDTODEVICE
480       /*
481        * This binds the local socket to a particular interface. This will
482        * force even requests to other local interfaces to go out the external
483        * interface. Only bind to the interface when specified as interface,
484        * not just as a hostname or ip address.
485        *
486        * The interface might be a VRF, eg: vrf-blue, which means it cannot be
487        * converted to an IP address and would fail Curl_if2ip. Simply try to
488        * use it straight away.
489        */
490       if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
491                     dev, (curl_socklen_t)strlen(dev) + 1) == 0) {
492         /* This is often "errno 1, error: Operation not permitted" if you're
493          * not running as root or another suitable privileged user. If it
494          * succeeds it means the parameter was a valid interface and not an IP
495          * address. Return immediately.
496          */
497         infof(data, "socket successfully bound to interface '%s'", dev);
498         return CURLE_OK;
499       }
500 #endif
501 
502       switch(Curl_if2ip(af,
503 #ifdef USE_IPV6
504                         scope, conn->scope_id,
505 #endif
506                         dev, myhost, sizeof(myhost))) {
507         case IF2IP_NOT_FOUND:
508           if(is_interface) {
509             /* Do not fall back to treating it as a host name */
510             failf(data, "Couldn't bind to interface '%s'", dev);
511             return CURLE_INTERFACE_FAILED;
512           }
513           break;
514         case IF2IP_AF_NOT_SUPPORTED:
515           /* Signal the caller to try another address family if available */
516           return CURLE_UNSUPPORTED_PROTOCOL;
517         case IF2IP_FOUND:
518           is_interface = TRUE;
519           /*
520            * We now have the numerical IP address in the 'myhost' buffer
521            */
522           infof(data, "Local Interface %s is ip %s using address family %i",
523                 dev, myhost, af);
524           done = 1;
525           break;
526       }
527     }
528     if(!is_interface) {
529       /*
530        * This was not an interface, resolve the name as a host name
531        * or IP number
532        *
533        * Temporarily force name resolution to use only the address type
534        * of the connection. The resolve functions should really be changed
535        * to take a type parameter instead.
536        */
537       unsigned char ipver = conn->ip_version;
538       int rc;
539 
540       if(af == AF_INET)
541         conn->ip_version = CURL_IPRESOLVE_V4;
542 #ifdef USE_IPV6
543       else if(af == AF_INET6)
544         conn->ip_version = CURL_IPRESOLVE_V6;
545 #endif
546 
547       rc = Curl_resolv(data, dev, 80, FALSE, &h);
548       if(rc == CURLRESOLV_PENDING)
549         (void)Curl_resolver_wait_resolv(data, &h);
550       conn->ip_version = ipver;
551 
552       if(h) {
553         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
554         Curl_printable_address(h->addr, myhost, sizeof(myhost));
555         infof(data, "Name '%s' family %i resolved to '%s' family %i",
556               dev, af, myhost, h->addr->ai_family);
557         Curl_resolv_unlock(data, h);
558         if(af != h->addr->ai_family) {
559           /* bad IP version combo, signal the caller to try another address
560              family if available */
561           return CURLE_UNSUPPORTED_PROTOCOL;
562         }
563         done = 1;
564       }
565       else {
566         /*
567          * provided dev was no interface (or interfaces are not supported
568          * e.g. solaris) no ip address and no domain we fail here
569          */
570         done = -1;
571       }
572     }
573 
574     if(done > 0) {
575 #ifdef USE_IPV6
576       /* IPv6 address */
577       if(af == AF_INET6) {
578 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
579         char *scope_ptr = strchr(myhost, '%');
580         if(scope_ptr)
581           *(scope_ptr++) = '\0';
582 #endif
583         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
584           si6->sin6_family = AF_INET6;
585           si6->sin6_port = htons(port);
586 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
587           if(scope_ptr) {
588             /* The "myhost" string either comes from Curl_if2ip or from
589                Curl_printable_address. The latter returns only numeric scope
590                IDs and the former returns none at all.  So the scope ID, if
591                present, is known to be numeric */
592             unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
593             if(scope_id > UINT_MAX)
594               return CURLE_UNSUPPORTED_PROTOCOL;
595 
596             si6->sin6_scope_id = (unsigned int)scope_id;
597           }
598 #endif
599         }
600         sizeof_sa = sizeof(struct sockaddr_in6);
601       }
602       else
603 #endif
604       /* IPv4 address */
605       if((af == AF_INET) &&
606          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
607         si4->sin_family = AF_INET;
608         si4->sin_port = htons(port);
609         sizeof_sa = sizeof(struct sockaddr_in);
610       }
611     }
612 
613     if(done < 1) {
614       /* errorbuf is set false so failf will overwrite any message already in
615          the error buffer, so the user receives this error message instead of a
616          generic resolve error. */
617       data->state.errorbuf = FALSE;
618       failf(data, "Couldn't bind to '%s'", dev);
619       return CURLE_INTERFACE_FAILED;
620     }
621   }
622   else {
623     /* no device was given, prepare sa to match af's needs */
624 #ifdef USE_IPV6
625     if(af == AF_INET6) {
626       si6->sin6_family = AF_INET6;
627       si6->sin6_port = htons(port);
628       sizeof_sa = sizeof(struct sockaddr_in6);
629     }
630     else
631 #endif
632     if(af == AF_INET) {
633       si4->sin_family = AF_INET;
634       si4->sin_port = htons(port);
635       sizeof_sa = sizeof(struct sockaddr_in);
636     }
637   }
638 #ifdef IP_BIND_ADDRESS_NO_PORT
639   (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
640 #endif
641   for(;;) {
642     if(bind(sockfd, sock, sizeof_sa) >= 0) {
643       /* we succeeded to bind */
644       infof(data, "Local port: %hu", port);
645       conn->bits.bound = TRUE;
646       return CURLE_OK;
647     }
648 
649     if(--portnum > 0) {
650       port++; /* try next port */
651       if(port == 0)
652         break;
653       infof(data, "Bind to local port %d failed, trying next", port - 1);
654       /* We reuse/clobber the port variable here below */
655       if(sock->sa_family == AF_INET)
656         si4->sin_port = ntohs(port);
657 #ifdef USE_IPV6
658       else
659         si6->sin6_port = ntohs(port);
660 #endif
661     }
662     else
663       break;
664   }
665   {
666     char buffer[STRERROR_LEN];
667     data->state.os_errno = error = SOCKERRNO;
668     failf(data, "bind failed with errno %d: %s",
669           error, Curl_strerror(error, buffer, sizeof(buffer)));
670   }
671 
672   return CURLE_INTERFACE_FAILED;
673 }
674 #endif
675 
676 /*
677  * verifyconnect() returns TRUE if the connect really has happened.
678  */
verifyconnect(curl_socket_t sockfd,int * error)679 static bool verifyconnect(curl_socket_t sockfd, int *error)
680 {
681   bool rc = TRUE;
682 #ifdef SO_ERROR
683   int err = 0;
684   curl_socklen_t errSize = sizeof(err);
685 
686 #ifdef _WIN32
687   /*
688    * In October 2003 we effectively nullified this function on Windows due to
689    * problems with it using all CPU in multi-threaded cases.
690    *
691    * In May 2004, we bring it back to offer more info back on connect failures.
692    * Gisle Vanem could reproduce the former problems with this function, but
693    * could avoid them by adding this SleepEx() call below:
694    *
695    *    "I don't have Rational Quantify, but the hint from his post was
696    *    ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
697    *    just Sleep(0) would be enough?) would release whatever
698    *    mutex/critical-section the ntdll call is waiting on.
699    *
700    *    Someone got to verify this on Win-NT 4.0, 2000."
701    */
702 
703 #ifdef _WIN32_WCE
704   Sleep(0);
705 #else
706   SleepEx(0, FALSE);
707 #endif
708 
709 #endif
710 
711   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
712     err = SOCKERRNO;
713 #ifdef _WIN32_WCE
714   /* Old WinCE versions don't support SO_ERROR */
715   if(WSAENOPROTOOPT == err) {
716     SET_SOCKERRNO(0);
717     err = 0;
718   }
719 #endif
720 #if defined(EBADIOCTL) && defined(__minix)
721   /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
722   if(EBADIOCTL == err) {
723     SET_SOCKERRNO(0);
724     err = 0;
725   }
726 #endif
727   if((0 == err) || (EISCONN == err))
728     /* we are connected, awesome! */
729     rc = TRUE;
730   else
731     /* This wasn't a successful connect */
732     rc = FALSE;
733   if(error)
734     *error = err;
735 #else
736   (void)sockfd;
737   if(error)
738     *error = SOCKERRNO;
739 #endif
740   return rc;
741 }
742 
743 /**
744  * Determine the curl code for a socket connect() == -1 with errno.
745  */
socket_connect_result(struct Curl_easy * data,const char * ipaddress,int error)746 static CURLcode socket_connect_result(struct Curl_easy *data,
747                                       const char *ipaddress, int error)
748 {
749   switch(error) {
750   case EINPROGRESS:
751   case EWOULDBLOCK:
752 #if defined(EAGAIN)
753 #if (EAGAIN) != (EWOULDBLOCK)
754     /* On some platforms EAGAIN and EWOULDBLOCK are the
755      * same value, and on others they are different, hence
756      * the odd #if
757      */
758   case EAGAIN:
759 #endif
760 #endif
761     return CURLE_OK;
762 
763   default:
764     /* unknown error, fallthrough and try another address! */
765 #ifdef CURL_DISABLE_VERBOSE_STRINGS
766     (void)ipaddress;
767 #else
768     {
769       char buffer[STRERROR_LEN];
770       infof(data, "Immediate connect fail for %s: %s",
771             ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
772     }
773 #endif
774     data->state.os_errno = error;
775     /* connect failed */
776     return CURLE_COULDNT_CONNECT;
777   }
778 }
779 
780 /* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
781  * This happens often on TLS connections where the TLS implementation
782  * tries to read the head of a TLS record, determine the length of the
783  * full record and then make a subsequent read for that.
784  * On large reads, we will not fill the buffer to avoid the double copy. */
785 #define NW_RECV_CHUNK_SIZE    (64 * 1024)
786 #define NW_RECV_CHUNKS         1
787 #define NW_SMALL_READS        (1024)
788 
789 struct cf_socket_ctx {
790   int transport;
791   struct Curl_sockaddr_ex addr;      /* address to connect to */
792   curl_socket_t sock;                /* current attempt socket */
793   struct bufq recvbuf;               /* used when `buffer_recv` is set */
794   struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
795   struct curltime started_at;        /* when socket was created */
796   struct curltime connected_at;      /* when socket connected/got first byte */
797   struct curltime first_byte_at;     /* when first byte was recvd */
798   int error;                         /* errno of last failure or 0 */
799 #ifdef DEBUGBUILD
800   int wblock_percent;                /* percent of writes doing EAGAIN */
801   int wpartial_percent;              /* percent of bytes written in send */
802   int rblock_percent;                /* percent of reads doing EAGAIN */
803   size_t recv_max;                  /* max enforced read size */
804 #endif
805   BIT(got_first_byte);               /* if first byte was received */
806   BIT(accepted);                     /* socket was accepted, not connected */
807   BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
808   BIT(active);
809   BIT(buffer_recv);
810 };
811 
cf_socket_ctx_init(struct cf_socket_ctx * ctx,const struct Curl_addrinfo * ai,int transport)812 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
813                                const struct Curl_addrinfo *ai,
814                                int transport)
815 {
816   memset(ctx, 0, sizeof(*ctx));
817   ctx->sock = CURL_SOCKET_BAD;
818   ctx->transport = transport;
819   Curl_sock_assign_addr(&ctx->addr, ai, transport);
820   Curl_bufq_init(&ctx->recvbuf, NW_RECV_CHUNK_SIZE, NW_RECV_CHUNKS);
821 #ifdef DEBUGBUILD
822   {
823     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
824     if(p) {
825       long l = strtol(p, NULL, 10);
826       if(l >= 0 && l <= 100)
827         ctx->wblock_percent = (int)l;
828     }
829     p = getenv("CURL_DBG_SOCK_WPARTIAL");
830     if(p) {
831       long l = strtol(p, NULL, 10);
832       if(l >= 0 && l <= 100)
833         ctx->wpartial_percent = (int)l;
834     }
835     p = getenv("CURL_DBG_SOCK_RBLOCK");
836     if(p) {
837       long l = strtol(p, NULL, 10);
838       if(l >= 0 && l <= 100)
839         ctx->rblock_percent = (int)l;
840     }
841     p = getenv("CURL_DBG_SOCK_RMAX");
842     if(p) {
843       long l = strtol(p, NULL, 10);
844       if(l >= 0)
845         ctx->recv_max = (size_t)l;
846     }
847   }
848 #endif
849 }
850 
851 struct reader_ctx {
852   struct Curl_cfilter *cf;
853   struct Curl_easy *data;
854 };
855 
nw_in_read(void * reader_ctx,unsigned char * buf,size_t len,CURLcode * err)856 static ssize_t nw_in_read(void *reader_ctx,
857                            unsigned char *buf, size_t len,
858                            CURLcode *err)
859 {
860   struct reader_ctx *rctx = reader_ctx;
861   struct cf_socket_ctx *ctx = rctx->cf->ctx;
862   ssize_t nread;
863 
864   *err = CURLE_OK;
865   nread = sread(ctx->sock, buf, len);
866 
867   if(-1 == nread) {
868     int sockerr = SOCKERRNO;
869 
870     if(
871 #ifdef WSAEWOULDBLOCK
872       /* This is how Windows does it */
873       (WSAEWOULDBLOCK == sockerr)
874 #else
875       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
876          due to its inability to send off data without blocking. We therefore
877          treat both error codes the same here */
878       (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
879 #endif
880       ) {
881       /* this is just a case of EWOULDBLOCK */
882       *err = CURLE_AGAIN;
883       nread = -1;
884     }
885     else {
886       char buffer[STRERROR_LEN];
887 
888       failf(rctx->data, "Recv failure: %s",
889             Curl_strerror(sockerr, buffer, sizeof(buffer)));
890       rctx->data->state.os_errno = sockerr;
891       *err = CURLE_RECV_ERROR;
892       nread = -1;
893     }
894   }
895   CURL_TRC_CF(rctx->data, rctx->cf, "nw_in_read(len=%zu, fd=%"
896               CURL_FORMAT_SOCKET_T ") -> %d, err=%d",
897               len, ctx->sock, (int)nread, *err);
898   return nread;
899 }
900 
cf_socket_close(struct Curl_cfilter * cf,struct Curl_easy * data)901 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
902 {
903   struct cf_socket_ctx *ctx = cf->ctx;
904 
905   if(ctx && CURL_SOCKET_BAD != ctx->sock) {
906     CURL_TRC_CF(data, cf, "cf_socket_close(%" CURL_FORMAT_SOCKET_T
907                 ")", ctx->sock);
908     if(ctx->sock == cf->conn->sock[cf->sockindex])
909       cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
910     socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
911     ctx->sock = CURL_SOCKET_BAD;
912     if(ctx->active && cf->sockindex == FIRSTSOCKET)
913       cf->conn->remote_addr = NULL;
914     Curl_bufq_reset(&ctx->recvbuf);
915     ctx->active = FALSE;
916     ctx->buffer_recv = FALSE;
917     memset(&ctx->started_at, 0, sizeof(ctx->started_at));
918     memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
919   }
920 
921   cf->connected = FALSE;
922 }
923 
cf_socket_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)924 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
925 {
926   struct cf_socket_ctx *ctx = cf->ctx;
927 
928   cf_socket_close(cf, data);
929   CURL_TRC_CF(data, cf, "destroy");
930   Curl_bufq_free(&ctx->recvbuf);
931   free(ctx);
932   cf->ctx = NULL;
933 }
934 
set_local_ip(struct Curl_cfilter * cf,struct Curl_easy * data)935 static CURLcode set_local_ip(struct Curl_cfilter *cf,
936                              struct Curl_easy *data)
937 {
938   struct cf_socket_ctx *ctx = cf->ctx;
939 
940 #ifdef HAVE_GETSOCKNAME
941   if((ctx->sock != CURL_SOCKET_BAD) &&
942      !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
943     /* TFTP does not connect, so it cannot get the IP like this */
944 
945     char buffer[STRERROR_LEN];
946     struct Curl_sockaddr_storage ssloc;
947     curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
948 
949     memset(&ssloc, 0, sizeof(ssloc));
950     if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
951       int error = SOCKERRNO;
952       failf(data, "getsockname() failed with errno %d: %s",
953             error, Curl_strerror(error, buffer, sizeof(buffer)));
954       return CURLE_FAILED_INIT;
955     }
956     if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
957                          ctx->ip.local_ip, &ctx->ip.local_port)) {
958       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
959             errno, Curl_strerror(errno, buffer, sizeof(buffer)));
960       return CURLE_FAILED_INIT;
961     }
962   }
963 #else
964   (void)data;
965   ctx->ip.local_ip[0] = 0;
966   ctx->ip.local_port = -1;
967 #endif
968   return CURLE_OK;
969 }
970 
set_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)971 static CURLcode set_remote_ip(struct Curl_cfilter *cf,
972                               struct Curl_easy *data)
973 {
974   struct cf_socket_ctx *ctx = cf->ctx;
975 
976   /* store remote address and port used in this connection attempt */
977   if(!Curl_addr2string(&ctx->addr.sa_addr, ctx->addr.addrlen,
978                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
979     char buffer[STRERROR_LEN];
980 
981     ctx->error = errno;
982     /* malformed address or bug in inet_ntop, try next address */
983     failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
984           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
985     return CURLE_FAILED_INIT;
986   }
987   return CURLE_OK;
988 }
989 
cf_socket_open(struct Curl_cfilter * cf,struct Curl_easy * data)990 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
991                               struct Curl_easy *data)
992 {
993   struct cf_socket_ctx *ctx = cf->ctx;
994   int error = 0;
995   bool isconnected = FALSE;
996   CURLcode result = CURLE_COULDNT_CONNECT;
997   bool is_tcp;
998 
999   (void)data;
1000   DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
1001   ctx->started_at = Curl_now();
1002   result = socket_open(data, &ctx->addr, &ctx->sock);
1003   if(result)
1004     goto out;
1005 
1006   result = set_remote_ip(cf, data);
1007   if(result)
1008     goto out;
1009 
1010 #ifdef USE_IPV6
1011   if(ctx->addr.family == AF_INET6) {
1012     set_ipv6_v6only(ctx->sock, 0);
1013     infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1014   }
1015   else
1016 #endif
1017     infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1018 
1019 #ifdef USE_IPV6
1020   is_tcp = (ctx->addr.family == AF_INET
1021             || ctx->addr.family == AF_INET6) &&
1022            ctx->addr.socktype == SOCK_STREAM;
1023 #else
1024   is_tcp = (ctx->addr.family == AF_INET) &&
1025            ctx->addr.socktype == SOCK_STREAM;
1026 #endif
1027   if(is_tcp && data->set.tcp_nodelay)
1028     tcpnodelay(data, ctx->sock);
1029 
1030   nosigpipe(data, ctx->sock);
1031 
1032   Curl_sndbufset(ctx->sock);
1033 
1034   if(is_tcp && data->set.tcp_keepalive)
1035     tcpkeepalive(data, ctx->sock);
1036 
1037   if(data->set.fsockopt) {
1038     /* activate callback for setting socket options */
1039     Curl_set_in_callback(data, true);
1040     error = data->set.fsockopt(data->set.sockopt_client,
1041                                ctx->sock,
1042                                CURLSOCKTYPE_IPCXN);
1043     Curl_set_in_callback(data, false);
1044 
1045     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1046       isconnected = TRUE;
1047     else if(error) {
1048       result = CURLE_ABORTED_BY_CALLBACK;
1049       goto out;
1050     }
1051   }
1052 
1053 #ifndef CURL_DISABLE_BINDLOCAL
1054   /* possibly bind the local end to an IP, interface or port */
1055   if(ctx->addr.family == AF_INET
1056 #ifdef USE_IPV6
1057      || ctx->addr.family == AF_INET6
1058 #endif
1059     ) {
1060     result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1061                        Curl_ipv6_scope(&ctx->addr.sa_addr));
1062     if(result) {
1063       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1064         /* The address family is not supported on this interface.
1065            We can continue trying addresses */
1066         result = CURLE_COULDNT_CONNECT;
1067       }
1068       goto out;
1069     }
1070   }
1071 #endif
1072 
1073   /* set socket non-blocking */
1074   (void)curlx_nonblock(ctx->sock, TRUE);
1075   ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1076 out:
1077   if(result) {
1078     if(ctx->sock != CURL_SOCKET_BAD) {
1079       socket_close(data, cf->conn, TRUE, ctx->sock);
1080       ctx->sock = CURL_SOCKET_BAD;
1081     }
1082   }
1083   else if(isconnected) {
1084     set_local_ip(cf, data);
1085     ctx->connected_at = Curl_now();
1086     cf->connected = TRUE;
1087   }
1088   CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" CURL_FORMAT_SOCKET_T,
1089               result, ctx->sock);
1090   return result;
1091 }
1092 
do_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool is_tcp_fastopen)1093 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1094                       bool is_tcp_fastopen)
1095 {
1096   struct cf_socket_ctx *ctx = cf->ctx;
1097 #ifdef TCP_FASTOPEN_CONNECT
1098   int optval = 1;
1099 #endif
1100   int rc = -1;
1101 
1102   (void)data;
1103   if(is_tcp_fastopen) {
1104 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1105 #  if defined(HAVE_BUILTIN_AVAILABLE)
1106     /* while connectx function is available since macOS 10.11 / iOS 9,
1107        it did not have the interface declared correctly until
1108        Xcode 9 / macOS SDK 10.13 */
1109     if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1110       sa_endpoints_t endpoints;
1111       endpoints.sae_srcif = 0;
1112       endpoints.sae_srcaddr = NULL;
1113       endpoints.sae_srcaddrlen = 0;
1114       endpoints.sae_dstaddr = &ctx->addr.sa_addr;
1115       endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1116 
1117       rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1118                     CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1119                     NULL, 0, NULL, NULL);
1120     }
1121     else {
1122       rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1123     }
1124 #  else
1125     rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1126 #  endif /* HAVE_BUILTIN_AVAILABLE */
1127 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1128     if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1129                   (void *)&optval, sizeof(optval)) < 0)
1130       infof(data, "Failed to enable TCP Fast Open on fd %"
1131             CURL_FORMAT_SOCKET_T, ctx->sock);
1132 
1133     rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1134 #elif defined(MSG_FASTOPEN) /* old Linux */
1135     if(cf->conn->given->flags & PROTOPT_SSL)
1136       rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1137     else
1138       rc = 0; /* Do nothing */
1139 #endif
1140   }
1141   else {
1142     rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1143   }
1144   return rc;
1145 }
1146 
cf_tcp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1147 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1148                                struct Curl_easy *data,
1149                                bool blocking, bool *done)
1150 {
1151   struct cf_socket_ctx *ctx = cf->ctx;
1152   CURLcode result = CURLE_COULDNT_CONNECT;
1153   int rc = 0;
1154 
1155   (void)data;
1156   if(cf->connected) {
1157     *done = TRUE;
1158     return CURLE_OK;
1159   }
1160 
1161   /* TODO: need to support blocking connect? */
1162   if(blocking)
1163     return CURLE_UNSUPPORTED_PROTOCOL;
1164 
1165   *done = FALSE; /* a very negative world view is best */
1166   if(ctx->sock == CURL_SOCKET_BAD) {
1167     int error;
1168 
1169     result = cf_socket_open(cf, data);
1170     if(result)
1171       goto out;
1172 
1173     if(cf->connected) {
1174       *done = TRUE;
1175       return CURLE_OK;
1176     }
1177 
1178     /* Connect TCP socket */
1179     rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1180     error = SOCKERRNO;
1181     data->tcp_connect_errno = error;
1182     set_local_ip(cf, data);
1183     CURL_TRC_CF(data, cf, "local address %s port %d...",
1184                 ctx->ip.local_ip, ctx->ip.local_port);
1185     if(-1 == rc) {
1186       result = socket_connect_result(data, ctx->ip.remote_ip, error);
1187       goto out;
1188     }
1189   }
1190 
1191 #ifdef mpeix
1192   /* Call this function once now, and ignore the results. We do this to
1193      "clear" the error state on the socket so that we can later read it
1194      reliably. This is reported necessary on the MPE/iX operating
1195      system. */
1196   (void)verifyconnect(ctx->sock, NULL);
1197 #endif
1198   /* check socket for connect */
1199   rc = SOCKET_WRITABLE(ctx->sock, 0);
1200 
1201   if(rc == 0) { /* no connection yet */
1202     CURL_TRC_CF(data, cf, "not connected yet");
1203     return CURLE_OK;
1204   }
1205   else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1206     if(verifyconnect(ctx->sock, &ctx->error)) {
1207       /* we are connected with TCP, awesome! */
1208       ctx->connected_at = Curl_now();
1209       set_local_ip(cf, data);
1210       *done = TRUE;
1211       cf->connected = TRUE;
1212       CURL_TRC_CF(data, cf, "connected");
1213       return CURLE_OK;
1214     }
1215   }
1216   else if(rc & CURL_CSELECT_ERR) {
1217     (void)verifyconnect(ctx->sock, &ctx->error);
1218     result = CURLE_COULDNT_CONNECT;
1219   }
1220 
1221 out:
1222   if(result) {
1223     if(ctx->error) {
1224       set_local_ip(cf, data);
1225       data->state.os_errno = ctx->error;
1226       SET_SOCKERRNO(ctx->error);
1227 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1228       {
1229         char buffer[STRERROR_LEN];
1230         infof(data, "connect to %s port %u from %s port %d failed: %s",
1231               ctx->ip.remote_ip, ctx->ip.remote_port,
1232               ctx->ip.local_ip, ctx->ip.local_port,
1233               Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1234       }
1235 #endif
1236     }
1237     if(ctx->sock != CURL_SOCKET_BAD) {
1238       socket_close(data, cf->conn, TRUE, ctx->sock);
1239       ctx->sock = CURL_SOCKET_BAD;
1240     }
1241     *done = FALSE;
1242   }
1243   return result;
1244 }
1245 
cf_socket_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)1246 static void cf_socket_get_host(struct Curl_cfilter *cf,
1247                                struct Curl_easy *data,
1248                                const char **phost,
1249                                const char **pdisplay_host,
1250                                int *pport)
1251 {
1252   struct cf_socket_ctx *ctx = cf->ctx;
1253   (void)data;
1254   *phost = cf->conn->host.name;
1255   *pdisplay_host = cf->conn->host.dispname;
1256   *pport = ctx->ip.remote_port;
1257 }
1258 
cf_socket_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)1259 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1260                                       struct Curl_easy *data,
1261                                       struct easy_pollset *ps)
1262 {
1263   struct cf_socket_ctx *ctx = cf->ctx;
1264 
1265   if(ctx->sock != CURL_SOCKET_BAD) {
1266     if(!cf->connected) {
1267       Curl_pollset_set_out_only(data, ps, ctx->sock);
1268       CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1269                   CURL_FORMAT_SOCKET_T, ctx->sock);
1270     }
1271     else if(!ctx->active) {
1272       Curl_pollset_add_in(data, ps, ctx->sock);
1273       CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1274                   CURL_FORMAT_SOCKET_T, ctx->sock);
1275     }
1276   }
1277 }
1278 
cf_socket_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1279 static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1280                                    const struct Curl_easy *data)
1281 {
1282   struct cf_socket_ctx *ctx = cf->ctx;
1283   int readable;
1284 
1285   (void)data;
1286   if(!Curl_bufq_is_empty(&ctx->recvbuf))
1287     return TRUE;
1288 
1289   readable = SOCKET_READABLE(ctx->sock, 0);
1290   return (readable > 0 && (readable & CURL_CSELECT_IN));
1291 }
1292 
cf_socket_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,CURLcode * err)1293 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1294                               const void *buf, size_t len, CURLcode *err)
1295 {
1296   struct cf_socket_ctx *ctx = cf->ctx;
1297   curl_socket_t fdsave;
1298   ssize_t nwritten;
1299   size_t orig_len = len;
1300 
1301   *err = CURLE_OK;
1302   fdsave = cf->conn->sock[cf->sockindex];
1303   cf->conn->sock[cf->sockindex] = ctx->sock;
1304 
1305 #ifdef DEBUGBUILD
1306   /* simulate network blocking/partial writes */
1307   if(ctx->wblock_percent > 0) {
1308     unsigned char c = 0;
1309     Curl_rand(data, &c, 1);
1310     if(c >= ((100-ctx->wblock_percent)*256/100)) {
1311       CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1312       *err = CURLE_AGAIN;
1313       nwritten = -1;
1314       cf->conn->sock[cf->sockindex] = fdsave;
1315       return nwritten;
1316     }
1317   }
1318   if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1319     len = len * ctx->wpartial_percent / 100;
1320     if(!len)
1321       len = 1;
1322     CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1323                 orig_len, len);
1324   }
1325 #endif
1326 
1327 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1328   if(cf->conn->bits.tcp_fastopen) {
1329     nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1330                       &cf->conn->remote_addr->sa_addr,
1331                       cf->conn->remote_addr->addrlen);
1332     cf->conn->bits.tcp_fastopen = FALSE;
1333   }
1334   else
1335 #endif
1336     nwritten = swrite(ctx->sock, buf, len);
1337 
1338   if(-1 == nwritten) {
1339     int sockerr = SOCKERRNO;
1340 
1341     if(
1342 #ifdef WSAEWOULDBLOCK
1343       /* This is how Windows does it */
1344       (WSAEWOULDBLOCK == sockerr)
1345 #else
1346       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1347          due to its inability to send off data without blocking. We therefore
1348          treat both error codes the same here */
1349       (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1350       (EINPROGRESS == sockerr)
1351 #endif
1352       ) {
1353       /* this is just a case of EWOULDBLOCK */
1354       *err = CURLE_AGAIN;
1355     }
1356     else {
1357       char buffer[STRERROR_LEN];
1358       failf(data, "Send failure: %s",
1359             Curl_strerror(sockerr, buffer, sizeof(buffer)));
1360       data->state.os_errno = sockerr;
1361       *err = CURLE_SEND_ERROR;
1362     }
1363   }
1364 
1365   CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1366               orig_len, (int)nwritten, *err);
1367   cf->conn->sock[cf->sockindex] = fdsave;
1368   return nwritten;
1369 }
1370 
cf_socket_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1371 static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1372                               char *buf, size_t len, CURLcode *err)
1373 {
1374   struct cf_socket_ctx *ctx = cf->ctx;
1375   curl_socket_t fdsave;
1376   ssize_t nread;
1377 
1378   *err = CURLE_OK;
1379 
1380   fdsave = cf->conn->sock[cf->sockindex];
1381   cf->conn->sock[cf->sockindex] = ctx->sock;
1382 
1383 #ifdef DEBUGBUILD
1384   /* simulate network blocking/partial reads */
1385   if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1386     unsigned char c = 0;
1387     Curl_rand(data, &c, 1);
1388     if(c >= ((100-ctx->rblock_percent)*256/100)) {
1389       CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1390       *err = CURLE_AGAIN;
1391       nread = -1;
1392       cf->conn->sock[cf->sockindex] = fdsave;
1393       return nread;
1394     }
1395   }
1396   if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1397     size_t orig_len = len;
1398     len = ctx->recv_max;
1399     CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1400                 orig_len, len);
1401   }
1402 #endif
1403 
1404   if(ctx->buffer_recv && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1405     CURL_TRC_CF(data, cf, "recv from buffer");
1406     nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1407   }
1408   else {
1409     struct reader_ctx rctx;
1410 
1411     rctx.cf = cf;
1412     rctx.data = data;
1413 
1414     /* "small" reads may trigger filling our buffer, "large" reads
1415      * are probably not worth the additional copy */
1416     if(ctx->buffer_recv && len < NW_SMALL_READS) {
1417       ssize_t nwritten;
1418       nwritten = Curl_bufq_slurp(&ctx->recvbuf, nw_in_read, &rctx, err);
1419       if(nwritten < 0 && !Curl_bufq_is_empty(&ctx->recvbuf)) {
1420         /* we have a partial read with an error. need to deliver
1421          * what we got, return the error later. */
1422         CURL_TRC_CF(data, cf, "partial read: empty buffer first");
1423         nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1424       }
1425       else if(nwritten < 0) {
1426         nread = -1;
1427         goto out;
1428       }
1429       else if(nwritten == 0) {
1430         /* eof */
1431         *err = CURLE_OK;
1432         nread = 0;
1433       }
1434       else {
1435         CURL_TRC_CF(data, cf, "buffered %zd additional bytes", nwritten);
1436         nread = Curl_bufq_read(&ctx->recvbuf, (unsigned char *)buf, len, err);
1437       }
1438     }
1439     else {
1440       nread = nw_in_read(&rctx, (unsigned char *)buf, len, err);
1441     }
1442   }
1443 
1444 out:
1445   CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1446               *err);
1447   if(nread > 0 && !ctx->got_first_byte) {
1448     ctx->first_byte_at = Curl_now();
1449     ctx->got_first_byte = TRUE;
1450   }
1451   cf->conn->sock[cf->sockindex] = fdsave;
1452   return nread;
1453 }
1454 
cf_socket_active(struct Curl_cfilter * cf,struct Curl_easy * data)1455 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1456 {
1457   struct cf_socket_ctx *ctx = cf->ctx;
1458 
1459   /* use this socket from now on */
1460   cf->conn->sock[cf->sockindex] = ctx->sock;
1461   set_local_ip(cf, data);
1462   if(cf->sockindex == SECONDARYSOCKET)
1463     cf->conn->secondary = ctx->ip;
1464   else
1465     cf->conn->primary = ctx->ip;
1466   /* the first socket info gets some specials */
1467   if(cf->sockindex == FIRSTSOCKET) {
1468     cf->conn->remote_addr = &ctx->addr;
1469   #ifdef USE_IPV6
1470     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6)? TRUE : FALSE;
1471   #endif
1472     Curl_persistconninfo(data, cf->conn, &ctx->ip);
1473     /* buffering is currently disabled by default because we have stalls
1474      * in parallel transfers where not all buffered data is consumed and no
1475      * socket events happen.
1476      */
1477     ctx->buffer_recv = FALSE;
1478   }
1479   ctx->active = TRUE;
1480 }
1481 
cf_socket_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1482 static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1483                                 struct Curl_easy *data,
1484                                 int event, int arg1, void *arg2)
1485 {
1486   struct cf_socket_ctx *ctx = cf->ctx;
1487 
1488   (void)arg1;
1489   (void)arg2;
1490   switch(event) {
1491   case CF_CTRL_CONN_INFO_UPDATE:
1492     cf_socket_active(cf, data);
1493     break;
1494   case CF_CTRL_DATA_SETUP:
1495     Curl_persistconninfo(data, cf->conn, &ctx->ip);
1496     break;
1497   case CF_CTRL_FORGET_SOCKET:
1498     ctx->sock = CURL_SOCKET_BAD;
1499     break;
1500   }
1501   return CURLE_OK;
1502 }
1503 
cf_socket_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1504 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1505                                     struct Curl_easy *data,
1506                                     bool *input_pending)
1507 {
1508   struct cf_socket_ctx *ctx = cf->ctx;
1509   struct pollfd pfd[1];
1510   int r;
1511 
1512   *input_pending = FALSE;
1513   (void)data;
1514   if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1515     return FALSE;
1516 
1517   /* Check with 0 timeout if there are any events pending on the socket */
1518   pfd[0].fd = ctx->sock;
1519   pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1520   pfd[0].revents = 0;
1521 
1522   r = Curl_poll(pfd, 1, 0);
1523   if(r < 0) {
1524     CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1525     return FALSE;
1526   }
1527   else if(r == 0) {
1528     CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1529     return TRUE;
1530   }
1531   else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1532     CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1533     return FALSE;
1534   }
1535 
1536   CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1537   *input_pending = TRUE;
1538   return TRUE;
1539 }
1540 
cf_socket_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)1541 static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1542                                 struct Curl_easy *data,
1543                                 int query, int *pres1, void *pres2)
1544 {
1545   struct cf_socket_ctx *ctx = cf->ctx;
1546 
1547   switch(query) {
1548   case CF_QUERY_SOCKET:
1549     DEBUGASSERT(pres2);
1550     *((curl_socket_t *)pres2) = ctx->sock;
1551     return CURLE_OK;
1552   case CF_QUERY_CONNECT_REPLY_MS:
1553     if(ctx->got_first_byte) {
1554       timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1555       *pres1 = (ms < INT_MAX)? (int)ms : INT_MAX;
1556     }
1557     else
1558       *pres1 = -1;
1559     return CURLE_OK;
1560   case CF_QUERY_TIMER_CONNECT: {
1561     struct curltime *when = pres2;
1562     switch(ctx->transport) {
1563     case TRNSPRT_UDP:
1564     case TRNSPRT_QUIC:
1565       /* Since UDP connected sockets work different from TCP, we use the
1566        * time of the first byte from the peer as the "connect" time. */
1567       if(ctx->got_first_byte) {
1568         *when = ctx->first_byte_at;
1569         break;
1570       }
1571       FALLTHROUGH();
1572     default:
1573       *when = ctx->connected_at;
1574       break;
1575     }
1576     return CURLE_OK;
1577   }
1578   default:
1579     break;
1580   }
1581   return cf->next?
1582     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1583     CURLE_UNKNOWN_OPTION;
1584 }
1585 
1586 struct Curl_cftype Curl_cft_tcp = {
1587   "TCP",
1588   CF_TYPE_IP_CONNECT,
1589   CURL_LOG_LVL_NONE,
1590   cf_socket_destroy,
1591   cf_tcp_connect,
1592   cf_socket_close,
1593   cf_socket_get_host,
1594   cf_socket_adjust_pollset,
1595   cf_socket_data_pending,
1596   cf_socket_send,
1597   cf_socket_recv,
1598   cf_socket_cntrl,
1599   cf_socket_conn_is_alive,
1600   Curl_cf_def_conn_keep_alive,
1601   cf_socket_query,
1602 };
1603 
Curl_cf_tcp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1604 CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1605                             struct Curl_easy *data,
1606                             struct connectdata *conn,
1607                             const struct Curl_addrinfo *ai,
1608                             int transport)
1609 {
1610   struct cf_socket_ctx *ctx = NULL;
1611   struct Curl_cfilter *cf = NULL;
1612   CURLcode result;
1613 
1614   (void)data;
1615   (void)conn;
1616   DEBUGASSERT(transport == TRNSPRT_TCP);
1617   ctx = calloc(1, sizeof(*ctx));
1618   if(!ctx) {
1619     result = CURLE_OUT_OF_MEMORY;
1620     goto out;
1621   }
1622   cf_socket_ctx_init(ctx, ai, transport);
1623 
1624   result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1625 
1626 out:
1627   *pcf = (!result)? cf : NULL;
1628   if(result) {
1629     Curl_safefree(cf);
1630     Curl_safefree(ctx);
1631   }
1632 
1633   return result;
1634 }
1635 
cf_udp_setup_quic(struct Curl_cfilter * cf,struct Curl_easy * data)1636 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1637                                struct Curl_easy *data)
1638 {
1639   struct cf_socket_ctx *ctx = cf->ctx;
1640   int rc;
1641 
1642   /* QUIC needs a connected socket, nonblocking */
1643   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1644 
1645 #if defined(__APPLE__) && defined(USE_OPENSSL_QUIC)
1646   (void)rc;
1647   /* On macOS OpenSSL QUIC fails on connected sockets.
1648    * see: <https://github.com/openssl/openssl/issues/23251> */
1649 #else
1650   rc = connect(ctx->sock, &ctx->addr.sa_addr, ctx->addr.addrlen);
1651   if(-1 == rc) {
1652     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1653   }
1654   ctx->sock_connected = TRUE;
1655 #endif
1656   set_local_ip(cf, data);
1657   CURL_TRC_CF(data, cf, "%s socket %" CURL_FORMAT_SOCKET_T
1658               " connected: [%s:%d] -> [%s:%d]",
1659               (ctx->transport == TRNSPRT_QUIC)? "QUIC" : "UDP",
1660               ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1661               ctx->ip.remote_ip, ctx->ip.remote_port);
1662 
1663   (void)curlx_nonblock(ctx->sock, TRUE);
1664   switch(ctx->addr.family) {
1665 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
1666   case AF_INET: {
1667     int val = IP_PMTUDISC_DO;
1668     (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1669                      sizeof(val));
1670     break;
1671   }
1672 #endif
1673 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1674   case AF_INET6: {
1675     int val = IPV6_PMTUDISC_DO;
1676     (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1677                      sizeof(val));
1678     break;
1679   }
1680 #endif
1681   }
1682   return CURLE_OK;
1683 }
1684 
cf_udp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1685 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1686                                struct Curl_easy *data,
1687                                bool blocking, bool *done)
1688 {
1689   struct cf_socket_ctx *ctx = cf->ctx;
1690   CURLcode result = CURLE_COULDNT_CONNECT;
1691 
1692   (void)blocking;
1693   if(cf->connected) {
1694     *done = TRUE;
1695     return CURLE_OK;
1696   }
1697   *done = FALSE;
1698   if(ctx->sock == CURL_SOCKET_BAD) {
1699     result = cf_socket_open(cf, data);
1700     if(result) {
1701       CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1702       goto out;
1703     }
1704 
1705     if(ctx->transport == TRNSPRT_QUIC) {
1706       result = cf_udp_setup_quic(cf, data);
1707       if(result)
1708         goto out;
1709       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1710                   CURL_FORMAT_SOCKET_T " (%s:%d)",
1711                   ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1712     }
1713     else {
1714       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1715                   CURL_FORMAT_SOCKET_T " (unconnected)", ctx->sock);
1716     }
1717     *done = TRUE;
1718     cf->connected = TRUE;
1719   }
1720 out:
1721   return result;
1722 }
1723 
1724 struct Curl_cftype Curl_cft_udp = {
1725   "UDP",
1726   CF_TYPE_IP_CONNECT,
1727   CURL_LOG_LVL_NONE,
1728   cf_socket_destroy,
1729   cf_udp_connect,
1730   cf_socket_close,
1731   cf_socket_get_host,
1732   cf_socket_adjust_pollset,
1733   cf_socket_data_pending,
1734   cf_socket_send,
1735   cf_socket_recv,
1736   cf_socket_cntrl,
1737   cf_socket_conn_is_alive,
1738   Curl_cf_def_conn_keep_alive,
1739   cf_socket_query,
1740 };
1741 
Curl_cf_udp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1742 CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1743                             struct Curl_easy *data,
1744                             struct connectdata *conn,
1745                             const struct Curl_addrinfo *ai,
1746                             int transport)
1747 {
1748   struct cf_socket_ctx *ctx = NULL;
1749   struct Curl_cfilter *cf = NULL;
1750   CURLcode result;
1751 
1752   (void)data;
1753   (void)conn;
1754   DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1755   ctx = calloc(1, sizeof(*ctx));
1756   if(!ctx) {
1757     result = CURLE_OUT_OF_MEMORY;
1758     goto out;
1759   }
1760   cf_socket_ctx_init(ctx, ai, transport);
1761 
1762   result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1763 
1764 out:
1765   *pcf = (!result)? cf : NULL;
1766   if(result) {
1767     Curl_safefree(cf);
1768     Curl_safefree(ctx);
1769   }
1770 
1771   return result;
1772 }
1773 
1774 /* this is the TCP filter which can also handle this case */
1775 struct Curl_cftype Curl_cft_unix = {
1776   "UNIX",
1777   CF_TYPE_IP_CONNECT,
1778   CURL_LOG_LVL_NONE,
1779   cf_socket_destroy,
1780   cf_tcp_connect,
1781   cf_socket_close,
1782   cf_socket_get_host,
1783   cf_socket_adjust_pollset,
1784   cf_socket_data_pending,
1785   cf_socket_send,
1786   cf_socket_recv,
1787   cf_socket_cntrl,
1788   cf_socket_conn_is_alive,
1789   Curl_cf_def_conn_keep_alive,
1790   cf_socket_query,
1791 };
1792 
Curl_cf_unix_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1793 CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1794                              struct Curl_easy *data,
1795                              struct connectdata *conn,
1796                              const struct Curl_addrinfo *ai,
1797                              int transport)
1798 {
1799   struct cf_socket_ctx *ctx = NULL;
1800   struct Curl_cfilter *cf = NULL;
1801   CURLcode result;
1802 
1803   (void)data;
1804   (void)conn;
1805   DEBUGASSERT(transport == TRNSPRT_UNIX);
1806   ctx = calloc(1, sizeof(*ctx));
1807   if(!ctx) {
1808     result = CURLE_OUT_OF_MEMORY;
1809     goto out;
1810   }
1811   cf_socket_ctx_init(ctx, ai, transport);
1812 
1813   result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
1814 
1815 out:
1816   *pcf = (!result)? cf : NULL;
1817   if(result) {
1818     Curl_safefree(cf);
1819     Curl_safefree(ctx);
1820   }
1821 
1822   return result;
1823 }
1824 
cf_tcp_accept_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1825 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
1826                                       struct Curl_easy *data,
1827                                       bool blocking, bool *done)
1828 {
1829   /* we start accepted, if we ever close, we cannot go on */
1830   (void)data;
1831   (void)blocking;
1832   if(cf->connected) {
1833     *done = TRUE;
1834     return CURLE_OK;
1835   }
1836   return CURLE_FAILED_INIT;
1837 }
1838 
1839 struct Curl_cftype Curl_cft_tcp_accept = {
1840   "TCP-ACCEPT",
1841   CF_TYPE_IP_CONNECT,
1842   CURL_LOG_LVL_NONE,
1843   cf_socket_destroy,
1844   cf_tcp_accept_connect,
1845   cf_socket_close,
1846   cf_socket_get_host,              /* TODO: not accurate */
1847   cf_socket_adjust_pollset,
1848   cf_socket_data_pending,
1849   cf_socket_send,
1850   cf_socket_recv,
1851   cf_socket_cntrl,
1852   cf_socket_conn_is_alive,
1853   Curl_cf_def_conn_keep_alive,
1854   cf_socket_query,
1855 };
1856 
Curl_conn_tcp_listen_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)1857 CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
1858                                   struct connectdata *conn,
1859                                   int sockindex, curl_socket_t *s)
1860 {
1861   CURLcode result;
1862   struct Curl_cfilter *cf = NULL;
1863   struct cf_socket_ctx *ctx = NULL;
1864 
1865   /* replace any existing */
1866   Curl_conn_cf_discard_all(data, conn, sockindex);
1867   DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
1868 
1869   ctx = calloc(1, sizeof(*ctx));
1870   if(!ctx) {
1871     result = CURLE_OUT_OF_MEMORY;
1872     goto out;
1873   }
1874   ctx->transport = conn->transport;
1875   ctx->sock = *s;
1876   ctx->accepted = FALSE;
1877   result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
1878   if(result)
1879     goto out;
1880   Curl_conn_cf_add(data, conn, sockindex, cf);
1881 
1882   conn->sock[sockindex] = ctx->sock;
1883   set_local_ip(cf, data);
1884   ctx->active = TRUE;
1885   ctx->connected_at = Curl_now();
1886   cf->connected = TRUE;
1887   CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%"
1888               CURL_FORMAT_SOCKET_T ")", ctx->sock);
1889 
1890 out:
1891   if(result) {
1892     Curl_safefree(cf);
1893     Curl_safefree(ctx);
1894   }
1895   return result;
1896 }
1897 
set_accepted_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1898 static void set_accepted_remote_ip(struct Curl_cfilter *cf,
1899                                    struct Curl_easy *data)
1900 {
1901   struct cf_socket_ctx *ctx = cf->ctx;
1902 #ifdef HAVE_GETPEERNAME
1903   char buffer[STRERROR_LEN];
1904   struct Curl_sockaddr_storage ssrem;
1905   curl_socklen_t plen;
1906 
1907   ctx->ip.remote_ip[0] = 0;
1908   ctx->ip.remote_port = 0;
1909   plen = sizeof(ssrem);
1910   memset(&ssrem, 0, plen);
1911   if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
1912     int error = SOCKERRNO;
1913     failf(data, "getpeername() failed with errno %d: %s",
1914           error, Curl_strerror(error, buffer, sizeof(buffer)));
1915     return;
1916   }
1917   if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
1918                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1919     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
1920           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1921     return;
1922   }
1923 #else
1924   ctx->ip.remote_ip[0] = 0;
1925   ctx->ip.remote_port = 0;
1926   (void)data;
1927 #endif
1928 }
1929 
Curl_conn_tcp_accepted_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)1930 CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
1931                                     struct connectdata *conn,
1932                                     int sockindex, curl_socket_t *s)
1933 {
1934   struct Curl_cfilter *cf = NULL;
1935   struct cf_socket_ctx *ctx = NULL;
1936 
1937   cf = conn->cfilter[sockindex];
1938   if(!cf || cf->cft != &Curl_cft_tcp_accept)
1939     return CURLE_FAILED_INIT;
1940 
1941   ctx = cf->ctx;
1942   /* discard the listen socket */
1943   socket_close(data, conn, TRUE, ctx->sock);
1944   ctx->sock = *s;
1945   conn->sock[sockindex] = ctx->sock;
1946   set_accepted_remote_ip(cf, data);
1947   set_local_ip(cf, data);
1948   ctx->active = TRUE;
1949   ctx->accepted = TRUE;
1950   ctx->connected_at = Curl_now();
1951   cf->connected = TRUE;
1952   CURL_TRC_CF(data, cf, "accepted_set(sock=%" CURL_FORMAT_SOCKET_T
1953               ", remote=%s port=%d)",
1954               ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
1955 
1956   return CURLE_OK;
1957 }
1958 
1959 /**
1960  * Return TRUE iff `cf` is a socket filter.
1961  */
cf_is_socket(struct Curl_cfilter * cf)1962 static bool cf_is_socket(struct Curl_cfilter *cf)
1963 {
1964   return cf && (cf->cft == &Curl_cft_tcp ||
1965                 cf->cft == &Curl_cft_udp ||
1966                 cf->cft == &Curl_cft_unix ||
1967                 cf->cft == &Curl_cft_tcp_accept);
1968 }
1969 
Curl_cf_socket_peek(struct Curl_cfilter * cf,struct Curl_easy * data,curl_socket_t * psock,const struct Curl_sockaddr_ex ** paddr,struct ip_quadruple * pip)1970 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
1971                              struct Curl_easy *data,
1972                              curl_socket_t *psock,
1973                              const struct Curl_sockaddr_ex **paddr,
1974                              struct ip_quadruple *pip)
1975 {
1976   (void)data;
1977   if(cf_is_socket(cf) && cf->ctx) {
1978     struct cf_socket_ctx *ctx = cf->ctx;
1979 
1980     if(psock)
1981       *psock = ctx->sock;
1982     if(paddr)
1983       *paddr = &ctx->addr;
1984     if(pip)
1985       *pip = ctx->ip;
1986     return CURLE_OK;
1987   }
1988   return CURLE_FAILED_INIT;
1989 }
1990