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