xref: /curl/lib/cf-socket.c (revision aa1a1539)
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 
604   memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
605 
606   if(iface && (strlen(iface) < 255) ) {
607     char myhost[256] = "";
608     int done = 0; /* -1 for error, 1 for address found */
609     if2ip_result_t if2ip_result = IF2IP_NOT_FOUND;
610 
611     /* interface */
612 #ifdef SO_BINDTODEVICE
613     /*
614       * This binds the local socket to a particular interface. This will
615       * force even requests to other local interfaces to go out the external
616       * interface. Only bind to the interface when specified as interface,
617       * not just as a hostname or ip address.
618       *
619       * The interface might be a VRF, eg: vrf-blue, which means it cannot be
620       * converted to an IP address and would fail Curl_if2ip. Simply try to
621       * use it straight away.
622       */
623     if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
624                   iface, (curl_socklen_t)strlen(iface) + 1) == 0) {
625       /* This is often "errno 1, error: Operation not permitted" if you are
626         * not running as root or another suitable privileged user. If it
627         * succeeds it means the parameter was a valid interface and not an IP
628         * address. Return immediately.
629         */
630       if(!host_input) {
631         infof(data, "socket successfully bound to interface '%s'", iface);
632         return CURLE_OK;
633       }
634     }
635 #endif
636     if(!host_input) {
637       /* Discover IP from input device, then bind to it */
638       if2ip_result = Curl_if2ip(af,
639 #ifdef USE_IPV6
640                       scope, conn->scope_id,
641 #endif
642                       iface, myhost, sizeof(myhost));
643     }
644     switch(if2ip_result) {
645       case IF2IP_NOT_FOUND:
646         if(iface_input && !host_input) {
647           /* Do not fall back to treating it as a hostname */
648           char buffer[STRERROR_LEN];
649           data->state.os_errno = error = SOCKERRNO;
650           failf(data, "Couldn't bind to interface '%s' with errno %d: %s",
651                 iface, error, Curl_strerror(error, buffer, sizeof(buffer)));
652           return CURLE_INTERFACE_FAILED;
653         }
654         break;
655       case IF2IP_AF_NOT_SUPPORTED:
656         /* Signal the caller to try another address family if available */
657         return CURLE_UNSUPPORTED_PROTOCOL;
658       case IF2IP_FOUND:
659         /*
660           * We now have the numerical IP address in the 'myhost' buffer
661           */
662         host = myhost;
663         infof(data, "Local Interface %s is ip %s using address family %i",
664               iface, host, af);
665         done = 1;
666         break;
667     }
668     if(!iface_input || host_input) {
669       /*
670        * This was not an interface, resolve the name as a hostname
671        * or IP number
672        *
673        * Temporarily force name resolution to use only the address type
674        * of the connection. The resolve functions should really be changed
675        * to take a type parameter instead.
676        */
677       unsigned char ipver = conn->ip_version;
678       int rc;
679 
680       if(af == AF_INET)
681         conn->ip_version = CURL_IPRESOLVE_V4;
682 #ifdef USE_IPV6
683       else if(af == AF_INET6)
684         conn->ip_version = CURL_IPRESOLVE_V6;
685 #endif
686 
687       rc = Curl_resolv(data, host, 80, FALSE, &h);
688       if(rc == CURLRESOLV_PENDING)
689         (void)Curl_resolver_wait_resolv(data, &h);
690       conn->ip_version = ipver;
691 
692       if(h) {
693         int h_af = h->addr->ai_family;
694         /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
695         Curl_printable_address(h->addr, myhost, sizeof(myhost));
696         infof(data, "Name '%s' family %i resolved to '%s' family %i",
697               host, af, myhost, h_af);
698         Curl_resolv_unlink(data, &h); /* this will NULL, potential free h */
699         if(af != h_af) {
700           /* bad IP version combo, signal the caller to try another address
701              family if available */
702           return CURLE_UNSUPPORTED_PROTOCOL;
703         }
704         done = 1;
705       }
706       else {
707         /*
708          * provided dev was no interface (or interfaces are not supported
709          * e.g. Solaris) no ip address and no domain we fail here
710          */
711         done = -1;
712       }
713     }
714 
715     if(done > 0) {
716 #ifdef USE_IPV6
717       /* IPv6 address */
718       if(af == AF_INET6) {
719 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
720         char *scope_ptr = strchr(myhost, '%');
721         if(scope_ptr)
722           *(scope_ptr++) = '\0';
723 #endif
724         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) {
725           si6->sin6_family = AF_INET6;
726           si6->sin6_port = htons(port);
727 #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
728           if(scope_ptr) {
729             /* The "myhost" string either comes from Curl_if2ip or from
730                Curl_printable_address. The latter returns only numeric scope
731                IDs and the former returns none at all. So the scope ID, if
732                present, is known to be numeric */
733             unsigned long scope_id = strtoul(scope_ptr, NULL, 10);
734             if(scope_id > UINT_MAX)
735               return CURLE_UNSUPPORTED_PROTOCOL;
736 
737             si6->sin6_scope_id = (unsigned int)scope_id;
738           }
739 #endif
740         }
741         sizeof_sa = sizeof(struct sockaddr_in6);
742       }
743       else
744 #endif
745       /* IPv4 address */
746       if((af == AF_INET) &&
747          (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
748         si4->sin_family = AF_INET;
749         si4->sin_port = htons(port);
750         sizeof_sa = sizeof(struct sockaddr_in);
751       }
752     }
753 
754     if(done < 1) {
755       /* errorbuf is set false so failf will overwrite any message already in
756          the error buffer, so the user receives this error message instead of a
757          generic resolve error. */
758       char buffer[STRERROR_LEN];
759       data->state.errorbuf = FALSE;
760       data->state.os_errno = error = SOCKERRNO;
761       failf(data, "Couldn't bind to '%s' with errno %d: %s",
762             host, error, Curl_strerror(error, buffer, sizeof(buffer)));
763       return CURLE_INTERFACE_FAILED;
764     }
765   }
766   else {
767     /* no device was given, prepare sa to match af's needs */
768 #ifdef USE_IPV6
769     if(af == AF_INET6) {
770       si6->sin6_family = AF_INET6;
771       si6->sin6_port = htons(port);
772       sizeof_sa = sizeof(struct sockaddr_in6);
773     }
774     else
775 #endif
776     if(af == AF_INET) {
777       si4->sin_family = AF_INET;
778       si4->sin_port = htons(port);
779       sizeof_sa = sizeof(struct sockaddr_in);
780     }
781   }
782 #ifdef IP_BIND_ADDRESS_NO_PORT
783   (void)setsockopt(sockfd, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &on, sizeof(on));
784 #endif
785   for(;;) {
786     if(bind(sockfd, sock, sizeof_sa) >= 0) {
787       /* we succeeded to bind */
788       infof(data, "Local port: %hu", port);
789       conn->bits.bound = TRUE;
790       return CURLE_OK;
791     }
792 
793     if(--portnum > 0) {
794       port++; /* try next port */
795       if(port == 0)
796         break;
797       infof(data, "Bind to local port %d failed, trying next", port - 1);
798       /* We reuse/clobber the port variable here below */
799       if(sock->sa_family == AF_INET)
800         si4->sin_port = ntohs(port);
801 #ifdef USE_IPV6
802       else
803         si6->sin6_port = ntohs(port);
804 #endif
805     }
806     else
807       break;
808   }
809   {
810     char buffer[STRERROR_LEN];
811     data->state.os_errno = error = SOCKERRNO;
812     failf(data, "bind failed with errno %d: %s",
813           error, Curl_strerror(error, buffer, sizeof(buffer)));
814   }
815 
816   return CURLE_INTERFACE_FAILED;
817 }
818 #endif
819 
820 /*
821  * verifyconnect() returns TRUE if the connect really has happened.
822  */
verifyconnect(curl_socket_t sockfd,int * error)823 static bool verifyconnect(curl_socket_t sockfd, int *error)
824 {
825   bool rc = TRUE;
826 #ifdef SO_ERROR
827   int err = 0;
828   curl_socklen_t errSize = sizeof(err);
829 
830 #ifdef _WIN32
831   /*
832    * In October 2003 we effectively nullified this function on Windows due to
833    * problems with it using all CPU in multi-threaded cases.
834    *
835    * In May 2004, we bring it back to offer more info back on connect failures.
836    * Gisle Vanem could reproduce the former problems with this function, but
837    * could avoid them by adding this SleepEx() call below:
838    *
839    *    "I do not have Rational Quantify, but the hint from his post was
840    *    ntdll::NtRemoveIoCompletion(). I would assume the SleepEx (or maybe
841    *    just Sleep(0) would be enough?) would release whatever
842    *    mutex/critical-section the ntdll call is waiting on.
843    *
844    *    Someone got to verify this on Win-NT 4.0, 2000."
845    */
846 
847 #ifdef _WIN32_WCE
848   Sleep(0);
849 #else
850   SleepEx(0, FALSE);
851 #endif
852 
853 #endif
854 
855   if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
856     err = SOCKERRNO;
857 #ifdef _WIN32_WCE
858   /* Old Windows CE versions do not support SO_ERROR */
859   if(WSAENOPROTOOPT == err) {
860     SET_SOCKERRNO(0);
861     err = 0;
862   }
863 #endif
864 #if defined(EBADIOCTL) && defined(__minix)
865   /* Minix 3.1.x does not support getsockopt on UDP sockets */
866   if(EBADIOCTL == err) {
867     SET_SOCKERRNO(0);
868     err = 0;
869   }
870 #endif
871   if((0 == err) || (EISCONN == err))
872     /* we are connected, awesome! */
873     rc = TRUE;
874   else
875     /* This was not a successful connect */
876     rc = FALSE;
877   if(error)
878     *error = err;
879 #else
880   (void)sockfd;
881   if(error)
882     *error = SOCKERRNO;
883 #endif
884   return rc;
885 }
886 
887 /**
888  * Determine the curl code for a socket connect() == -1 with errno.
889  */
socket_connect_result(struct Curl_easy * data,const char * ipaddress,int error)890 static CURLcode socket_connect_result(struct Curl_easy *data,
891                                       const char *ipaddress, int error)
892 {
893   switch(error) {
894   case EINPROGRESS:
895   case EWOULDBLOCK:
896 #if defined(EAGAIN)
897 #if (EAGAIN) != (EWOULDBLOCK)
898     /* On some platforms EAGAIN and EWOULDBLOCK are the
899      * same value, and on others they are different, hence
900      * the odd #if
901      */
902   case EAGAIN:
903 #endif
904 #endif
905     return CURLE_OK;
906 
907   default:
908     /* unknown error, fallthrough and try another address! */
909 #ifdef CURL_DISABLE_VERBOSE_STRINGS
910     (void)ipaddress;
911 #else
912     {
913       char buffer[STRERROR_LEN];
914       infof(data, "Immediate connect fail for %s: %s",
915             ipaddress, Curl_strerror(error, buffer, sizeof(buffer)));
916     }
917 #endif
918     data->state.os_errno = error;
919     /* connect failed */
920     return CURLE_COULDNT_CONNECT;
921   }
922 }
923 
924 /* We have a recv buffer to enhance reads with len < NW_SMALL_READS.
925  * This happens often on TLS connections where the TLS implementation
926  * tries to read the head of a TLS record, determine the length of the
927  * full record and then make a subsequent read for that.
928  * On large reads, we will not fill the buffer to avoid the double copy. */
929 #define NW_RECV_CHUNK_SIZE    (64 * 1024)
930 #define NW_RECV_CHUNKS         1
931 #define NW_SMALL_READS        (1024)
932 
933 struct cf_socket_ctx {
934   int transport;
935   struct Curl_sockaddr_ex addr;      /* address to connect to */
936   curl_socket_t sock;                /* current attempt socket */
937   struct ip_quadruple ip;            /* The IP quadruple 2x(addr+port) */
938   struct curltime started_at;        /* when socket was created */
939   struct curltime connected_at;      /* when socket connected/got first byte */
940   struct curltime first_byte_at;     /* when first byte was recvd */
941 #ifdef USE_WINSOCK
942   struct curltime last_sndbuf_query_at;  /* when SO_SNDBUF last queried */
943   ULONG sndbuf_size;                     /* the last set SO_SNDBUF size */
944 #endif
945   int error;                         /* errno of last failure or 0 */
946 #ifdef DEBUGBUILD
947   int wblock_percent;                /* percent of writes doing EAGAIN */
948   int wpartial_percent;              /* percent of bytes written in send */
949   int rblock_percent;                /* percent of reads doing EAGAIN */
950   size_t recv_max;                  /* max enforced read size */
951 #endif
952   BIT(got_first_byte);               /* if first byte was received */
953   BIT(listening);                    /* socket is listening */
954   BIT(accepted);                     /* socket was accepted, not connected */
955   BIT(sock_connected);               /* socket is "connected", e.g. in UDP */
956   BIT(active);
957 };
958 
cf_socket_ctx_init(struct cf_socket_ctx * ctx,const struct Curl_addrinfo * ai,int transport)959 static void cf_socket_ctx_init(struct cf_socket_ctx *ctx,
960                                const struct Curl_addrinfo *ai,
961                                int transport)
962 {
963   memset(ctx, 0, sizeof(*ctx));
964   ctx->sock = CURL_SOCKET_BAD;
965   ctx->transport = transport;
966   Curl_sock_assign_addr(&ctx->addr, ai, transport);
967 #ifdef DEBUGBUILD
968   {
969     char *p = getenv("CURL_DBG_SOCK_WBLOCK");
970     if(p) {
971       long l = strtol(p, NULL, 10);
972       if(l >= 0 && l <= 100)
973         ctx->wblock_percent = (int)l;
974     }
975     p = getenv("CURL_DBG_SOCK_WPARTIAL");
976     if(p) {
977       long l = strtol(p, NULL, 10);
978       if(l >= 0 && l <= 100)
979         ctx->wpartial_percent = (int)l;
980     }
981     p = getenv("CURL_DBG_SOCK_RBLOCK");
982     if(p) {
983       long l = strtol(p, NULL, 10);
984       if(l >= 0 && l <= 100)
985         ctx->rblock_percent = (int)l;
986     }
987     p = getenv("CURL_DBG_SOCK_RMAX");
988     if(p) {
989       long l = strtol(p, NULL, 10);
990       if(l >= 0)
991         ctx->recv_max = (size_t)l;
992     }
993   }
994 #endif
995 }
996 
cf_socket_close(struct Curl_cfilter * cf,struct Curl_easy * data)997 static void cf_socket_close(struct Curl_cfilter *cf, struct Curl_easy *data)
998 {
999   struct cf_socket_ctx *ctx = cf->ctx;
1000 
1001   if(ctx && CURL_SOCKET_BAD != ctx->sock) {
1002     CURL_TRC_CF(data, cf, "cf_socket_close(%" FMT_SOCKET_T ")", ctx->sock);
1003     if(ctx->sock == cf->conn->sock[cf->sockindex])
1004       cf->conn->sock[cf->sockindex] = CURL_SOCKET_BAD;
1005     socket_close(data, cf->conn, !ctx->accepted, ctx->sock);
1006     ctx->sock = CURL_SOCKET_BAD;
1007     if(ctx->active && cf->sockindex == FIRSTSOCKET)
1008       cf->conn->remote_addr = NULL;
1009     ctx->active = FALSE;
1010     memset(&ctx->started_at, 0, sizeof(ctx->started_at));
1011     memset(&ctx->connected_at, 0, sizeof(ctx->connected_at));
1012   }
1013 
1014   cf->connected = FALSE;
1015 }
1016 
cf_socket_shutdown(struct Curl_cfilter * cf,struct Curl_easy * data,bool * done)1017 static CURLcode cf_socket_shutdown(struct Curl_cfilter *cf,
1018                                    struct Curl_easy *data,
1019                                    bool *done)
1020 {
1021   if(cf->connected) {
1022     struct cf_socket_ctx *ctx = cf->ctx;
1023 
1024     CURL_TRC_CF(data, cf, "cf_socket_shutdown(%" FMT_SOCKET_T ")", ctx->sock);
1025     /* On TCP, and when the socket looks well and non-blocking mode
1026      * can be enabled, receive dangling bytes before close to avoid
1027      * entering RST states unnecessarily. */
1028     if(ctx->sock != CURL_SOCKET_BAD &&
1029        ctx->transport == TRNSPRT_TCP &&
1030        (curlx_nonblock(ctx->sock, TRUE) >= 0)) {
1031       unsigned char buf[1024];
1032       (void)sread(ctx->sock, buf, sizeof(buf));
1033     }
1034   }
1035   *done = TRUE;
1036   return CURLE_OK;
1037 }
1038 
cf_socket_destroy(struct Curl_cfilter * cf,struct Curl_easy * data)1039 static void cf_socket_destroy(struct Curl_cfilter *cf, struct Curl_easy *data)
1040 {
1041   struct cf_socket_ctx *ctx = cf->ctx;
1042 
1043   cf_socket_close(cf, data);
1044   CURL_TRC_CF(data, cf, "destroy");
1045   free(ctx);
1046   cf->ctx = NULL;
1047 }
1048 
set_local_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1049 static CURLcode set_local_ip(struct Curl_cfilter *cf,
1050                              struct Curl_easy *data)
1051 {
1052   struct cf_socket_ctx *ctx = cf->ctx;
1053 
1054 #ifdef HAVE_GETSOCKNAME
1055   if((ctx->sock != CURL_SOCKET_BAD) &&
1056      !(data->conn->handler->protocol & CURLPROTO_TFTP)) {
1057     /* TFTP does not connect, so it cannot get the IP like this */
1058 
1059     char buffer[STRERROR_LEN];
1060     struct Curl_sockaddr_storage ssloc;
1061     curl_socklen_t slen = sizeof(struct Curl_sockaddr_storage);
1062 
1063     memset(&ssloc, 0, sizeof(ssloc));
1064     if(getsockname(ctx->sock, (struct sockaddr*) &ssloc, &slen)) {
1065       int error = SOCKERRNO;
1066       failf(data, "getsockname() failed with errno %d: %s",
1067             error, Curl_strerror(error, buffer, sizeof(buffer)));
1068       return CURLE_FAILED_INIT;
1069     }
1070     if(!Curl_addr2string((struct sockaddr*)&ssloc, slen,
1071                          ctx->ip.local_ip, &ctx->ip.local_port)) {
1072       failf(data, "ssloc inet_ntop() failed with errno %d: %s",
1073             errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1074       return CURLE_FAILED_INIT;
1075     }
1076   }
1077 #else
1078   (void)data;
1079   ctx->ip.local_ip[0] = 0;
1080   ctx->ip.local_port = -1;
1081 #endif
1082   return CURLE_OK;
1083 }
1084 
set_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)1085 static CURLcode set_remote_ip(struct Curl_cfilter *cf,
1086                               struct Curl_easy *data)
1087 {
1088   struct cf_socket_ctx *ctx = cf->ctx;
1089 
1090   /* store remote address and port used in this connection attempt */
1091   if(!Curl_addr2string(&ctx->addr.curl_sa_addr,
1092                        (curl_socklen_t)ctx->addr.addrlen,
1093                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
1094     char buffer[STRERROR_LEN];
1095 
1096     ctx->error = errno;
1097     /* malformed address or bug in inet_ntop, try next address */
1098     failf(data, "curl_sa_addr inet_ntop() failed with errno %d: %s",
1099           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
1100     return CURLE_FAILED_INIT;
1101   }
1102   return CURLE_OK;
1103 }
1104 
cf_socket_open(struct Curl_cfilter * cf,struct Curl_easy * data)1105 static CURLcode cf_socket_open(struct Curl_cfilter *cf,
1106                               struct Curl_easy *data)
1107 {
1108   struct cf_socket_ctx *ctx = cf->ctx;
1109   int error = 0;
1110   bool isconnected = FALSE;
1111   CURLcode result = CURLE_COULDNT_CONNECT;
1112   bool is_tcp;
1113 
1114   (void)data;
1115   DEBUGASSERT(ctx->sock == CURL_SOCKET_BAD);
1116   ctx->started_at = Curl_now();
1117 #ifdef SOCK_NONBLOCK
1118   /* Do not tuck SOCK_NONBLOCK into socktype when opensocket callback is set
1119    * because we would not know how socketype is about to be used in the
1120    * callback, SOCK_NONBLOCK might get factored out before calling socket().
1121    */
1122   if(!data->set.fopensocket)
1123     ctx->addr.socktype |= SOCK_NONBLOCK;
1124 #endif
1125   result = socket_open(data, &ctx->addr, &ctx->sock);
1126 #ifdef SOCK_NONBLOCK
1127   /* Restore the socktype after the socket is created. */
1128   if(!data->set.fopensocket)
1129     ctx->addr.socktype &= ~SOCK_NONBLOCK;
1130 #endif
1131   if(result)
1132     goto out;
1133 
1134   result = set_remote_ip(cf, data);
1135   if(result)
1136     goto out;
1137 
1138 #ifdef USE_IPV6
1139   if(ctx->addr.family == AF_INET6) {
1140     set_ipv6_v6only(ctx->sock, 0);
1141     infof(data, "  Trying [%s]:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1142   }
1143   else
1144 #endif
1145     infof(data, "  Trying %s:%d...", ctx->ip.remote_ip, ctx->ip.remote_port);
1146 
1147 #ifdef USE_IPV6
1148   is_tcp = (ctx->addr.family == AF_INET
1149             || ctx->addr.family == AF_INET6) &&
1150            ctx->addr.socktype == SOCK_STREAM;
1151 #else
1152   is_tcp = (ctx->addr.family == AF_INET) &&
1153            ctx->addr.socktype == SOCK_STREAM;
1154 #endif
1155   if(is_tcp && data->set.tcp_nodelay)
1156     tcpnodelay(data, ctx->sock);
1157 
1158   nosigpipe(data, ctx->sock);
1159 
1160   Curl_sndbuf_init(ctx->sock);
1161 
1162   if(is_tcp && data->set.tcp_keepalive)
1163     tcpkeepalive(data, ctx->sock);
1164 
1165   if(data->set.fsockopt) {
1166     /* activate callback for setting socket options */
1167     Curl_set_in_callback(data, true);
1168     error = data->set.fsockopt(data->set.sockopt_client,
1169                                ctx->sock,
1170                                CURLSOCKTYPE_IPCXN);
1171     Curl_set_in_callback(data, false);
1172 
1173     if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
1174       isconnected = TRUE;
1175     else if(error) {
1176       result = CURLE_ABORTED_BY_CALLBACK;
1177       goto out;
1178     }
1179   }
1180 
1181 #ifndef CURL_DISABLE_BINDLOCAL
1182   /* possibly bind the local end to an IP, interface or port */
1183   if(ctx->addr.family == AF_INET
1184 #ifdef USE_IPV6
1185      || ctx->addr.family == AF_INET6
1186 #endif
1187     ) {
1188     result = bindlocal(data, cf->conn, ctx->sock, ctx->addr.family,
1189                        Curl_ipv6_scope(&ctx->addr.curl_sa_addr));
1190     if(result) {
1191       if(result == CURLE_UNSUPPORTED_PROTOCOL) {
1192         /* The address family is not supported on this interface.
1193            We can continue trying addresses */
1194         result = CURLE_COULDNT_CONNECT;
1195       }
1196       goto out;
1197     }
1198   }
1199 #endif
1200 
1201 #ifndef SOCK_NONBLOCK
1202   /* Set socket non-blocking, must be a non-blocking socket for
1203    * a non-blocking connect. */
1204   error = curlx_nonblock(ctx->sock, TRUE);
1205   if(error < 0) {
1206     result = CURLE_UNSUPPORTED_PROTOCOL;
1207     ctx->error = SOCKERRNO;
1208     goto out;
1209   }
1210 #else
1211   if(data->set.fopensocket) {
1212     /* Set socket non-blocking, must be a non-blocking socket for
1213      * a non-blocking connect. */
1214     error = curlx_nonblock(ctx->sock, TRUE);
1215     if(error < 0) {
1216       result = CURLE_UNSUPPORTED_PROTOCOL;
1217       ctx->error = SOCKERRNO;
1218       goto out;
1219     }
1220   }
1221 #endif
1222   ctx->sock_connected = (ctx->addr.socktype != SOCK_DGRAM);
1223 out:
1224   if(result) {
1225     if(ctx->sock != CURL_SOCKET_BAD) {
1226       socket_close(data, cf->conn, TRUE, ctx->sock);
1227       ctx->sock = CURL_SOCKET_BAD;
1228     }
1229   }
1230   else if(isconnected) {
1231     set_local_ip(cf, data);
1232     ctx->connected_at = Curl_now();
1233     cf->connected = TRUE;
1234   }
1235   CURL_TRC_CF(data, cf, "cf_socket_open() -> %d, fd=%" FMT_SOCKET_T,
1236               result, ctx->sock);
1237   return result;
1238 }
1239 
do_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool is_tcp_fastopen)1240 static int do_connect(struct Curl_cfilter *cf, struct Curl_easy *data,
1241                       bool is_tcp_fastopen)
1242 {
1243   struct cf_socket_ctx *ctx = cf->ctx;
1244 #ifdef TCP_FASTOPEN_CONNECT
1245   int optval = 1;
1246 #endif
1247   int rc = -1;
1248 
1249   (void)data;
1250   if(is_tcp_fastopen) {
1251 #if defined(CONNECT_DATA_IDEMPOTENT) /* Darwin */
1252 #  if defined(HAVE_BUILTIN_AVAILABLE)
1253     /* while connectx function is available since macOS 10.11 / iOS 9,
1254        it did not have the interface declared correctly until
1255        Xcode 9 / macOS SDK 10.13 */
1256     if(__builtin_available(macOS 10.11, iOS 9.0, tvOS 9.0, watchOS 2.0, *)) {
1257       sa_endpoints_t endpoints;
1258       endpoints.sae_srcif = 0;
1259       endpoints.sae_srcaddr = NULL;
1260       endpoints.sae_srcaddrlen = 0;
1261       endpoints.sae_dstaddr = &ctx->addr.curl_sa_addr;
1262       endpoints.sae_dstaddrlen = ctx->addr.addrlen;
1263 
1264       rc = connectx(ctx->sock, &endpoints, SAE_ASSOCID_ANY,
1265                     CONNECT_RESUME_ON_READ_WRITE | CONNECT_DATA_IDEMPOTENT,
1266                     NULL, 0, NULL, NULL);
1267     }
1268     else {
1269       rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1270     }
1271 #  else
1272     rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1273 #  endif /* HAVE_BUILTIN_AVAILABLE */
1274 #elif defined(TCP_FASTOPEN_CONNECT) /* Linux >= 4.11 */
1275     if(setsockopt(ctx->sock, IPPROTO_TCP, TCP_FASTOPEN_CONNECT,
1276                   (void *)&optval, sizeof(optval)) < 0)
1277       infof(data, "Failed to enable TCP Fast Open on fd %" FMT_SOCKET_T,
1278             ctx->sock);
1279 
1280     rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1281 #elif defined(MSG_FASTOPEN) /* old Linux */
1282     if(cf->conn->given->flags & PROTOPT_SSL)
1283       rc = connect(ctx->sock, &ctx->addr.curl_sa_addr, ctx->addr.addrlen);
1284     else
1285       rc = 0; /* Do nothing */
1286 #endif
1287   }
1288   else {
1289     rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1290                  (curl_socklen_t)ctx->addr.addrlen);
1291   }
1292   return rc;
1293 }
1294 
cf_tcp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1295 static CURLcode cf_tcp_connect(struct Curl_cfilter *cf,
1296                                struct Curl_easy *data,
1297                                bool blocking, bool *done)
1298 {
1299   struct cf_socket_ctx *ctx = cf->ctx;
1300   CURLcode result = CURLE_COULDNT_CONNECT;
1301   int rc = 0;
1302 
1303   (void)data;
1304   if(cf->connected) {
1305     *done = TRUE;
1306     return CURLE_OK;
1307   }
1308 
1309   /* TODO: need to support blocking connect? */
1310   if(blocking)
1311     return CURLE_UNSUPPORTED_PROTOCOL;
1312 
1313   *done = FALSE; /* a very negative world view is best */
1314   if(ctx->sock == CURL_SOCKET_BAD) {
1315     int error;
1316 
1317     result = cf_socket_open(cf, data);
1318     if(result)
1319       goto out;
1320 
1321     if(cf->connected) {
1322       *done = TRUE;
1323       return CURLE_OK;
1324     }
1325 
1326     /* Connect TCP socket */
1327     rc = do_connect(cf, data, cf->conn->bits.tcp_fastopen);
1328     error = SOCKERRNO;
1329     set_local_ip(cf, data);
1330     CURL_TRC_CF(data, cf, "local address %s port %d...",
1331                 ctx->ip.local_ip, ctx->ip.local_port);
1332     if(-1 == rc) {
1333       result = socket_connect_result(data, ctx->ip.remote_ip, error);
1334       goto out;
1335     }
1336   }
1337 
1338 #ifdef mpeix
1339   /* Call this function once now, and ignore the results. We do this to
1340      "clear" the error state on the socket so that we can later read it
1341      reliably. This is reported necessary on the MPE/iX operating
1342      system. */
1343   (void)verifyconnect(ctx->sock, NULL);
1344 #endif
1345   /* check socket for connect */
1346   rc = SOCKET_WRITABLE(ctx->sock, 0);
1347 
1348   if(rc == 0) { /* no connection yet */
1349     CURL_TRC_CF(data, cf, "not connected yet");
1350     return CURLE_OK;
1351   }
1352   else if(rc == CURL_CSELECT_OUT || cf->conn->bits.tcp_fastopen) {
1353     if(verifyconnect(ctx->sock, &ctx->error)) {
1354       /* we are connected with TCP, awesome! */
1355       ctx->connected_at = Curl_now();
1356       set_local_ip(cf, data);
1357       *done = TRUE;
1358       cf->connected = TRUE;
1359       CURL_TRC_CF(data, cf, "connected");
1360       return CURLE_OK;
1361     }
1362   }
1363   else if(rc & CURL_CSELECT_ERR) {
1364     (void)verifyconnect(ctx->sock, &ctx->error);
1365     result = CURLE_COULDNT_CONNECT;
1366   }
1367 
1368 out:
1369   if(result) {
1370     if(ctx->error) {
1371       set_local_ip(cf, data);
1372       data->state.os_errno = ctx->error;
1373       SET_SOCKERRNO(ctx->error);
1374 #ifndef CURL_DISABLE_VERBOSE_STRINGS
1375       {
1376         char buffer[STRERROR_LEN];
1377         infof(data, "connect to %s port %u from %s port %d failed: %s",
1378               ctx->ip.remote_ip, ctx->ip.remote_port,
1379               ctx->ip.local_ip, ctx->ip.local_port,
1380               Curl_strerror(ctx->error, buffer, sizeof(buffer)));
1381       }
1382 #endif
1383     }
1384     if(ctx->sock != CURL_SOCKET_BAD) {
1385       socket_close(data, cf->conn, TRUE, ctx->sock);
1386       ctx->sock = CURL_SOCKET_BAD;
1387     }
1388     *done = FALSE;
1389   }
1390   return result;
1391 }
1392 
cf_socket_get_host(struct Curl_cfilter * cf,struct Curl_easy * data,const char ** phost,const char ** pdisplay_host,int * pport)1393 static void cf_socket_get_host(struct Curl_cfilter *cf,
1394                                struct Curl_easy *data,
1395                                const char **phost,
1396                                const char **pdisplay_host,
1397                                int *pport)
1398 {
1399   struct cf_socket_ctx *ctx = cf->ctx;
1400   (void)data;
1401   *phost = cf->conn->host.name;
1402   *pdisplay_host = cf->conn->host.dispname;
1403   *pport = ctx->ip.remote_port;
1404 }
1405 
cf_socket_adjust_pollset(struct Curl_cfilter * cf,struct Curl_easy * data,struct easy_pollset * ps)1406 static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
1407                                       struct Curl_easy *data,
1408                                       struct easy_pollset *ps)
1409 {
1410   struct cf_socket_ctx *ctx = cf->ctx;
1411 
1412   if(ctx->sock != CURL_SOCKET_BAD) {
1413     /* A listening socket filter needs to be connected before the accept
1414      * for some weird FTP interaction. This should be rewritten, so that
1415      * FTP no longer does the socket checks and accept calls and delegates
1416      * all that to the filter. TODO. */
1417     if(ctx->listening) {
1418       Curl_pollset_set_in_only(data, ps, ctx->sock);
1419       CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
1420                   FMT_SOCKET_T, ctx->sock);
1421     }
1422     else if(!cf->connected) {
1423       Curl_pollset_set_out_only(data, ps, ctx->sock);
1424       CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
1425                   FMT_SOCKET_T, ctx->sock);
1426     }
1427     else if(!ctx->active) {
1428       Curl_pollset_add_in(data, ps, ctx->sock);
1429       CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
1430                   FMT_SOCKET_T, ctx->sock);
1431     }
1432   }
1433 }
1434 
cf_socket_data_pending(struct Curl_cfilter * cf,const struct Curl_easy * data)1435 static bool cf_socket_data_pending(struct Curl_cfilter *cf,
1436                                    const struct Curl_easy *data)
1437 {
1438   struct cf_socket_ctx *ctx = cf->ctx;
1439   int readable;
1440 
1441   (void)data;
1442   readable = SOCKET_READABLE(ctx->sock, 0);
1443   return (readable > 0 && (readable & CURL_CSELECT_IN));
1444 }
1445 
1446 #ifdef USE_WINSOCK
1447 
1448 #ifndef SIO_IDEAL_SEND_BACKLOG_QUERY
1449 #define SIO_IDEAL_SEND_BACKLOG_QUERY 0x4004747B
1450 #endif
1451 
win_update_sndbuf_size(struct cf_socket_ctx * ctx)1452 static void win_update_sndbuf_size(struct cf_socket_ctx *ctx)
1453 {
1454   ULONG ideal;
1455   DWORD ideallen;
1456   struct curltime n = Curl_now();
1457 
1458   if(Curl_timediff(n, ctx->last_sndbuf_query_at) > 1000) {
1459     if(!WSAIoctl(ctx->sock, SIO_IDEAL_SEND_BACKLOG_QUERY, 0, 0,
1460                   &ideal, sizeof(ideal), &ideallen, 0, 0) &&
1461        ideal != ctx->sndbuf_size &&
1462        !setsockopt(ctx->sock, SOL_SOCKET, SO_SNDBUF,
1463                    (const char *)&ideal, sizeof(ideal))) {
1464       ctx->sndbuf_size = ideal;
1465     }
1466     ctx->last_sndbuf_query_at = n;
1467   }
1468 }
1469 
1470 #endif /* USE_WINSOCK */
1471 
cf_socket_send(struct Curl_cfilter * cf,struct Curl_easy * data,const void * buf,size_t len,bool eos,CURLcode * err)1472 static ssize_t cf_socket_send(struct Curl_cfilter *cf, struct Curl_easy *data,
1473                               const void *buf, size_t len, bool eos,
1474                               CURLcode *err)
1475 {
1476   struct cf_socket_ctx *ctx = cf->ctx;
1477   curl_socket_t fdsave;
1478   ssize_t nwritten;
1479   size_t orig_len = len;
1480 
1481   (void)eos; /* unused */
1482   *err = CURLE_OK;
1483   fdsave = cf->conn->sock[cf->sockindex];
1484   cf->conn->sock[cf->sockindex] = ctx->sock;
1485 
1486 #ifdef DEBUGBUILD
1487   /* simulate network blocking/partial writes */
1488   if(ctx->wblock_percent > 0) {
1489     unsigned char c = 0;
1490     Curl_rand_bytes(data, FALSE, &c, 1);
1491     if(c >= ((100-ctx->wblock_percent)*256/100)) {
1492       CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE EWOULDBLOCK", orig_len);
1493       *err = CURLE_AGAIN;
1494       nwritten = -1;
1495       cf->conn->sock[cf->sockindex] = fdsave;
1496       return nwritten;
1497     }
1498   }
1499   if(cf->cft != &Curl_cft_udp && ctx->wpartial_percent > 0 && len > 8) {
1500     len = len * ctx->wpartial_percent / 100;
1501     if(!len)
1502       len = 1;
1503     CURL_TRC_CF(data, cf, "send(len=%zu) SIMULATE partial write of %zu bytes",
1504                 orig_len, len);
1505   }
1506 #endif
1507 
1508 #if defined(MSG_FASTOPEN) && !defined(TCP_FASTOPEN_CONNECT) /* Linux */
1509   if(cf->conn->bits.tcp_fastopen) {
1510     nwritten = sendto(ctx->sock, buf, len, MSG_FASTOPEN,
1511                       &cf->conn->remote_addr->curl_sa_addr,
1512                       cf->conn->remote_addr->addrlen);
1513     cf->conn->bits.tcp_fastopen = FALSE;
1514   }
1515   else
1516 #endif
1517     nwritten = swrite(ctx->sock, buf, len);
1518 
1519   if(-1 == nwritten) {
1520     int sockerr = SOCKERRNO;
1521 
1522     if(
1523 #ifdef WSAEWOULDBLOCK
1524       /* This is how Windows does it */
1525       (WSAEWOULDBLOCK == sockerr)
1526 #else
1527       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1528          due to its inability to send off data without blocking. We therefore
1529          treat both error codes the same here */
1530       (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr) ||
1531       (EINPROGRESS == sockerr)
1532 #endif
1533       ) {
1534       /* this is just a case of EWOULDBLOCK */
1535       *err = CURLE_AGAIN;
1536     }
1537     else {
1538       char buffer[STRERROR_LEN];
1539       failf(data, "Send failure: %s",
1540             Curl_strerror(sockerr, buffer, sizeof(buffer)));
1541       data->state.os_errno = sockerr;
1542       *err = CURLE_SEND_ERROR;
1543     }
1544   }
1545 
1546 #if defined(USE_WINSOCK)
1547   if(!*err)
1548     win_update_sndbuf_size(ctx);
1549 #endif
1550 
1551   CURL_TRC_CF(data, cf, "send(len=%zu) -> %d, err=%d",
1552               orig_len, (int)nwritten, *err);
1553   cf->conn->sock[cf->sockindex] = fdsave;
1554   return nwritten;
1555 }
1556 
cf_socket_recv(struct Curl_cfilter * cf,struct Curl_easy * data,char * buf,size_t len,CURLcode * err)1557 static ssize_t cf_socket_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
1558                               char *buf, size_t len, CURLcode *err)
1559 {
1560   struct cf_socket_ctx *ctx = cf->ctx;
1561   ssize_t nread;
1562 
1563   *err = CURLE_OK;
1564 
1565 #ifdef DEBUGBUILD
1566   /* simulate network blocking/partial reads */
1567   if(cf->cft != &Curl_cft_udp && ctx->rblock_percent > 0) {
1568     unsigned char c = 0;
1569     Curl_rand(data, &c, 1);
1570     if(c >= ((100-ctx->rblock_percent)*256/100)) {
1571       CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE EWOULDBLOCK", len);
1572       *err = CURLE_AGAIN;
1573       return -1;
1574     }
1575   }
1576   if(cf->cft != &Curl_cft_udp && ctx->recv_max && ctx->recv_max < len) {
1577     size_t orig_len = len;
1578     len = ctx->recv_max;
1579     CURL_TRC_CF(data, cf, "recv(len=%zu) SIMULATE max read of %zu bytes",
1580                 orig_len, len);
1581   }
1582 #endif
1583 
1584   *err = CURLE_OK;
1585   nread = sread(ctx->sock, buf, len);
1586 
1587   if(-1 == nread) {
1588     int sockerr = SOCKERRNO;
1589 
1590     if(
1591 #ifdef WSAEWOULDBLOCK
1592       /* This is how Windows does it */
1593       (WSAEWOULDBLOCK == sockerr)
1594 #else
1595       /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
1596          due to its inability to send off data without blocking. We therefore
1597          treat both error codes the same here */
1598       (EWOULDBLOCK == sockerr) || (EAGAIN == sockerr) || (EINTR == sockerr)
1599 #endif
1600       ) {
1601       /* this is just a case of EWOULDBLOCK */
1602       *err = CURLE_AGAIN;
1603     }
1604     else {
1605       char buffer[STRERROR_LEN];
1606 
1607       failf(data, "Recv failure: %s",
1608             Curl_strerror(sockerr, buffer, sizeof(buffer)));
1609       data->state.os_errno = sockerr;
1610       *err = CURLE_RECV_ERROR;
1611     }
1612   }
1613 
1614   CURL_TRC_CF(data, cf, "recv(len=%zu) -> %d, err=%d", len, (int)nread,
1615               *err);
1616   if(nread > 0 && !ctx->got_first_byte) {
1617     ctx->first_byte_at = Curl_now();
1618     ctx->got_first_byte = TRUE;
1619   }
1620   return nread;
1621 }
1622 
cf_socket_update_data(struct Curl_cfilter * cf,struct Curl_easy * data)1623 static void cf_socket_update_data(struct Curl_cfilter *cf,
1624                                   struct Curl_easy *data)
1625 {
1626   /* Update the IP info held in the transfer, if we have that. */
1627   if(cf->connected && (cf->sockindex == FIRSTSOCKET)) {
1628     struct cf_socket_ctx *ctx = cf->ctx;
1629     data->info.primary = ctx->ip;
1630     /* not sure if this is redundant... */
1631     data->info.conn_remote_port = cf->conn->remote_port;
1632   }
1633 }
1634 
cf_socket_active(struct Curl_cfilter * cf,struct Curl_easy * data)1635 static void cf_socket_active(struct Curl_cfilter *cf, struct Curl_easy *data)
1636 {
1637   struct cf_socket_ctx *ctx = cf->ctx;
1638 
1639   /* use this socket from now on */
1640   cf->conn->sock[cf->sockindex] = ctx->sock;
1641   set_local_ip(cf, data);
1642   if(cf->sockindex == FIRSTSOCKET) {
1643     cf->conn->primary = ctx->ip;
1644     cf->conn->remote_addr = &ctx->addr;
1645   #ifdef USE_IPV6
1646     cf->conn->bits.ipv6 = (ctx->addr.family == AF_INET6) ? TRUE : FALSE;
1647   #endif
1648   }
1649   else {
1650     cf->conn->secondary = ctx->ip;
1651   }
1652   ctx->active = TRUE;
1653 }
1654 
cf_socket_cntrl(struct Curl_cfilter * cf,struct Curl_easy * data,int event,int arg1,void * arg2)1655 static CURLcode cf_socket_cntrl(struct Curl_cfilter *cf,
1656                                 struct Curl_easy *data,
1657                                 int event, int arg1, void *arg2)
1658 {
1659   struct cf_socket_ctx *ctx = cf->ctx;
1660 
1661   (void)arg1;
1662   (void)arg2;
1663   switch(event) {
1664   case CF_CTRL_CONN_INFO_UPDATE:
1665     cf_socket_active(cf, data);
1666     cf_socket_update_data(cf, data);
1667     break;
1668   case CF_CTRL_DATA_SETUP:
1669     cf_socket_update_data(cf, data);
1670     break;
1671   case CF_CTRL_FORGET_SOCKET:
1672     ctx->sock = CURL_SOCKET_BAD;
1673     break;
1674   }
1675   return CURLE_OK;
1676 }
1677 
cf_socket_conn_is_alive(struct Curl_cfilter * cf,struct Curl_easy * data,bool * input_pending)1678 static bool cf_socket_conn_is_alive(struct Curl_cfilter *cf,
1679                                     struct Curl_easy *data,
1680                                     bool *input_pending)
1681 {
1682   struct cf_socket_ctx *ctx = cf->ctx;
1683   struct pollfd pfd[1];
1684   int r;
1685 
1686   *input_pending = FALSE;
1687   (void)data;
1688   if(!ctx || ctx->sock == CURL_SOCKET_BAD)
1689     return FALSE;
1690 
1691   /* Check with 0 timeout if there are any events pending on the socket */
1692   pfd[0].fd = ctx->sock;
1693   pfd[0].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
1694   pfd[0].revents = 0;
1695 
1696   r = Curl_poll(pfd, 1, 0);
1697   if(r < 0) {
1698     CURL_TRC_CF(data, cf, "is_alive: poll error, assume dead");
1699     return FALSE;
1700   }
1701   else if(r == 0) {
1702     CURL_TRC_CF(data, cf, "is_alive: poll timeout, assume alive");
1703     return TRUE;
1704   }
1705   else if(pfd[0].revents & (POLLERR|POLLHUP|POLLPRI|POLLNVAL)) {
1706     CURL_TRC_CF(data, cf, "is_alive: err/hup/etc events, assume dead");
1707     return FALSE;
1708   }
1709 
1710   CURL_TRC_CF(data, cf, "is_alive: valid events, looks alive");
1711   *input_pending = TRUE;
1712   return TRUE;
1713 }
1714 
cf_socket_query(struct Curl_cfilter * cf,struct Curl_easy * data,int query,int * pres1,void * pres2)1715 static CURLcode cf_socket_query(struct Curl_cfilter *cf,
1716                                 struct Curl_easy *data,
1717                                 int query, int *pres1, void *pres2)
1718 {
1719   struct cf_socket_ctx *ctx = cf->ctx;
1720 
1721   switch(query) {
1722   case CF_QUERY_SOCKET:
1723     DEBUGASSERT(pres2);
1724     *((curl_socket_t *)pres2) = ctx->sock;
1725     return CURLE_OK;
1726   case CF_QUERY_CONNECT_REPLY_MS:
1727     if(ctx->got_first_byte) {
1728       timediff_t ms = Curl_timediff(ctx->first_byte_at, ctx->started_at);
1729       *pres1 = (ms < INT_MAX) ? (int)ms : INT_MAX;
1730     }
1731     else
1732       *pres1 = -1;
1733     return CURLE_OK;
1734   case CF_QUERY_TIMER_CONNECT: {
1735     struct curltime *when = pres2;
1736     switch(ctx->transport) {
1737     case TRNSPRT_UDP:
1738     case TRNSPRT_QUIC:
1739       /* Since UDP connected sockets work different from TCP, we use the
1740        * time of the first byte from the peer as the "connect" time. */
1741       if(ctx->got_first_byte) {
1742         *when = ctx->first_byte_at;
1743         break;
1744       }
1745       FALLTHROUGH();
1746     default:
1747       *when = ctx->connected_at;
1748       break;
1749     }
1750     return CURLE_OK;
1751   }
1752   case CF_QUERY_IP_INFO:
1753 #ifdef USE_IPV6
1754     *pres1 = (ctx->addr.family == AF_INET6) ? TRUE : FALSE;
1755 #else
1756     *pres1 = FALSE;
1757 #endif
1758     *(struct ip_quadruple *)pres2 = ctx->ip;
1759     return CURLE_OK;
1760   default:
1761     break;
1762   }
1763   return cf->next ?
1764     cf->next->cft->query(cf->next, data, query, pres1, pres2) :
1765     CURLE_UNKNOWN_OPTION;
1766 }
1767 
1768 struct Curl_cftype Curl_cft_tcp = {
1769   "TCP",
1770   CF_TYPE_IP_CONNECT,
1771   CURL_LOG_LVL_NONE,
1772   cf_socket_destroy,
1773   cf_tcp_connect,
1774   cf_socket_close,
1775   cf_socket_shutdown,
1776   cf_socket_get_host,
1777   cf_socket_adjust_pollset,
1778   cf_socket_data_pending,
1779   cf_socket_send,
1780   cf_socket_recv,
1781   cf_socket_cntrl,
1782   cf_socket_conn_is_alive,
1783   Curl_cf_def_conn_keep_alive,
1784   cf_socket_query,
1785 };
1786 
Curl_cf_tcp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1787 CURLcode Curl_cf_tcp_create(struct Curl_cfilter **pcf,
1788                             struct Curl_easy *data,
1789                             struct connectdata *conn,
1790                             const struct Curl_addrinfo *ai,
1791                             int transport)
1792 {
1793   struct cf_socket_ctx *ctx = NULL;
1794   struct Curl_cfilter *cf = NULL;
1795   CURLcode result;
1796 
1797   (void)data;
1798   (void)conn;
1799   DEBUGASSERT(transport == TRNSPRT_TCP);
1800   ctx = calloc(1, sizeof(*ctx));
1801   if(!ctx) {
1802     result = CURLE_OUT_OF_MEMORY;
1803     goto out;
1804   }
1805   cf_socket_ctx_init(ctx, ai, transport);
1806 
1807   result = Curl_cf_create(&cf, &Curl_cft_tcp, ctx);
1808 
1809 out:
1810   *pcf = (!result) ? cf : NULL;
1811   if(result) {
1812     Curl_safefree(cf);
1813     Curl_safefree(ctx);
1814   }
1815 
1816   return result;
1817 }
1818 
cf_udp_setup_quic(struct Curl_cfilter * cf,struct Curl_easy * data)1819 static CURLcode cf_udp_setup_quic(struct Curl_cfilter *cf,
1820                                   struct Curl_easy *data)
1821 {
1822   struct cf_socket_ctx *ctx = cf->ctx;
1823   int rc;
1824   int one = 1;
1825 
1826   (void)one;
1827 
1828   /* QUIC needs a connected socket, nonblocking */
1829   DEBUGASSERT(ctx->sock != CURL_SOCKET_BAD);
1830 
1831   rc = connect(ctx->sock, &ctx->addr.curl_sa_addr,
1832                (curl_socklen_t)ctx->addr.addrlen);
1833   if(-1 == rc) {
1834     return socket_connect_result(data, ctx->ip.remote_ip, SOCKERRNO);
1835   }
1836   ctx->sock_connected = TRUE;
1837   set_local_ip(cf, data);
1838   CURL_TRC_CF(data, cf, "%s socket %" FMT_SOCKET_T
1839               " connected: [%s:%d] -> [%s:%d]",
1840               (ctx->transport == TRNSPRT_QUIC) ? "QUIC" : "UDP",
1841               ctx->sock, ctx->ip.local_ip, ctx->ip.local_port,
1842               ctx->ip.remote_ip, ctx->ip.remote_port);
1843 
1844   /* Currently, cf->ctx->sock is always non-blocking because the only
1845    * caller to cf_udp_setup_quic() is cf_udp_connect() that passes the
1846    * non-blocking socket created by cf_socket_open() to it. Thus, we
1847    * do not need to call curlx_nonblock() in cf_udp_setup_quic() anymore.
1848    */
1849   switch(ctx->addr.family) {
1850 #if defined(__linux__) && defined(IP_MTU_DISCOVER)
1851   case AF_INET: {
1852     int val = IP_PMTUDISC_DO;
1853     (void)setsockopt(ctx->sock, IPPROTO_IP, IP_MTU_DISCOVER, &val,
1854                      sizeof(val));
1855     break;
1856   }
1857 #endif
1858 #if defined(__linux__) && defined(IPV6_MTU_DISCOVER)
1859   case AF_INET6: {
1860     int val = IPV6_PMTUDISC_DO;
1861     (void)setsockopt(ctx->sock, IPPROTO_IPV6, IPV6_MTU_DISCOVER, &val,
1862                      sizeof(val));
1863     break;
1864   }
1865 #endif
1866   }
1867 
1868 #if defined(__linux__) && defined(UDP_GRO) &&                                 \
1869   (defined(HAVE_SENDMMSG) || defined(HAVE_SENDMSG)) &&                        \
1870   ((defined(USE_NGTCP2) && defined(USE_NGHTTP3)) || defined(USE_QUICHE))
1871   (void)setsockopt(ctx->sock, IPPROTO_UDP, UDP_GRO, &one,
1872                    (socklen_t)sizeof(one));
1873 #endif
1874 
1875   return CURLE_OK;
1876 }
1877 
cf_udp_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)1878 static CURLcode cf_udp_connect(struct Curl_cfilter *cf,
1879                                struct Curl_easy *data,
1880                                bool blocking, bool *done)
1881 {
1882   struct cf_socket_ctx *ctx = cf->ctx;
1883   CURLcode result = CURLE_COULDNT_CONNECT;
1884 
1885   (void)blocking;
1886   if(cf->connected) {
1887     *done = TRUE;
1888     return CURLE_OK;
1889   }
1890   *done = FALSE;
1891   if(ctx->sock == CURL_SOCKET_BAD) {
1892     result = cf_socket_open(cf, data);
1893     if(result) {
1894       CURL_TRC_CF(data, cf, "cf_udp_connect(), open failed -> %d", result);
1895       goto out;
1896     }
1897 
1898     if(ctx->transport == TRNSPRT_QUIC) {
1899       result = cf_udp_setup_quic(cf, data);
1900       if(result)
1901         goto out;
1902       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1903                   FMT_SOCKET_T " (%s:%d)",
1904                   ctx->sock, ctx->ip.local_ip, ctx->ip.local_port);
1905     }
1906     else {
1907       CURL_TRC_CF(data, cf, "cf_udp_connect(), opened socket=%"
1908                   FMT_SOCKET_T " (unconnected)", ctx->sock);
1909     }
1910     *done = TRUE;
1911     cf->connected = TRUE;
1912   }
1913 out:
1914   return result;
1915 }
1916 
1917 struct Curl_cftype Curl_cft_udp = {
1918   "UDP",
1919   CF_TYPE_IP_CONNECT,
1920   CURL_LOG_LVL_NONE,
1921   cf_socket_destroy,
1922   cf_udp_connect,
1923   cf_socket_close,
1924   cf_socket_shutdown,
1925   cf_socket_get_host,
1926   cf_socket_adjust_pollset,
1927   cf_socket_data_pending,
1928   cf_socket_send,
1929   cf_socket_recv,
1930   cf_socket_cntrl,
1931   cf_socket_conn_is_alive,
1932   Curl_cf_def_conn_keep_alive,
1933   cf_socket_query,
1934 };
1935 
Curl_cf_udp_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1936 CURLcode Curl_cf_udp_create(struct Curl_cfilter **pcf,
1937                             struct Curl_easy *data,
1938                             struct connectdata *conn,
1939                             const struct Curl_addrinfo *ai,
1940                             int transport)
1941 {
1942   struct cf_socket_ctx *ctx = NULL;
1943   struct Curl_cfilter *cf = NULL;
1944   CURLcode result;
1945 
1946   (void)data;
1947   (void)conn;
1948   DEBUGASSERT(transport == TRNSPRT_UDP || transport == TRNSPRT_QUIC);
1949   ctx = calloc(1, sizeof(*ctx));
1950   if(!ctx) {
1951     result = CURLE_OUT_OF_MEMORY;
1952     goto out;
1953   }
1954   cf_socket_ctx_init(ctx, ai, transport);
1955 
1956   result = Curl_cf_create(&cf, &Curl_cft_udp, ctx);
1957 
1958 out:
1959   *pcf = (!result) ? cf : NULL;
1960   if(result) {
1961     Curl_safefree(cf);
1962     Curl_safefree(ctx);
1963   }
1964 
1965   return result;
1966 }
1967 
1968 /* this is the TCP filter which can also handle this case */
1969 struct Curl_cftype Curl_cft_unix = {
1970   "UNIX",
1971   CF_TYPE_IP_CONNECT,
1972   CURL_LOG_LVL_NONE,
1973   cf_socket_destroy,
1974   cf_tcp_connect,
1975   cf_socket_close,
1976   cf_socket_shutdown,
1977   cf_socket_get_host,
1978   cf_socket_adjust_pollset,
1979   cf_socket_data_pending,
1980   cf_socket_send,
1981   cf_socket_recv,
1982   cf_socket_cntrl,
1983   cf_socket_conn_is_alive,
1984   Curl_cf_def_conn_keep_alive,
1985   cf_socket_query,
1986 };
1987 
Curl_cf_unix_create(struct Curl_cfilter ** pcf,struct Curl_easy * data,struct connectdata * conn,const struct Curl_addrinfo * ai,int transport)1988 CURLcode Curl_cf_unix_create(struct Curl_cfilter **pcf,
1989                              struct Curl_easy *data,
1990                              struct connectdata *conn,
1991                              const struct Curl_addrinfo *ai,
1992                              int transport)
1993 {
1994   struct cf_socket_ctx *ctx = NULL;
1995   struct Curl_cfilter *cf = NULL;
1996   CURLcode result;
1997 
1998   (void)data;
1999   (void)conn;
2000   DEBUGASSERT(transport == TRNSPRT_UNIX);
2001   ctx = calloc(1, sizeof(*ctx));
2002   if(!ctx) {
2003     result = CURLE_OUT_OF_MEMORY;
2004     goto out;
2005   }
2006   cf_socket_ctx_init(ctx, ai, transport);
2007 
2008   result = Curl_cf_create(&cf, &Curl_cft_unix, ctx);
2009 
2010 out:
2011   *pcf = (!result) ? cf : NULL;
2012   if(result) {
2013     Curl_safefree(cf);
2014     Curl_safefree(ctx);
2015   }
2016 
2017   return result;
2018 }
2019 
cf_tcp_accept_connect(struct Curl_cfilter * cf,struct Curl_easy * data,bool blocking,bool * done)2020 static CURLcode cf_tcp_accept_connect(struct Curl_cfilter *cf,
2021                                       struct Curl_easy *data,
2022                                       bool blocking, bool *done)
2023 {
2024   /* we start accepted, if we ever close, we cannot go on */
2025   (void)data;
2026   (void)blocking;
2027   if(cf->connected) {
2028     *done = TRUE;
2029     return CURLE_OK;
2030   }
2031   return CURLE_FAILED_INIT;
2032 }
2033 
2034 struct Curl_cftype Curl_cft_tcp_accept = {
2035   "TCP-ACCEPT",
2036   CF_TYPE_IP_CONNECT,
2037   CURL_LOG_LVL_NONE,
2038   cf_socket_destroy,
2039   cf_tcp_accept_connect,
2040   cf_socket_close,
2041   cf_socket_shutdown,
2042   cf_socket_get_host,              /* TODO: not accurate */
2043   cf_socket_adjust_pollset,
2044   cf_socket_data_pending,
2045   cf_socket_send,
2046   cf_socket_recv,
2047   cf_socket_cntrl,
2048   cf_socket_conn_is_alive,
2049   Curl_cf_def_conn_keep_alive,
2050   cf_socket_query,
2051 };
2052 
Curl_conn_tcp_listen_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)2053 CURLcode Curl_conn_tcp_listen_set(struct Curl_easy *data,
2054                                   struct connectdata *conn,
2055                                   int sockindex, curl_socket_t *s)
2056 {
2057   CURLcode result;
2058   struct Curl_cfilter *cf = NULL;
2059   struct cf_socket_ctx *ctx = NULL;
2060 
2061   /* replace any existing */
2062   Curl_conn_cf_discard_all(data, conn, sockindex);
2063   DEBUGASSERT(conn->sock[sockindex] == CURL_SOCKET_BAD);
2064 
2065   ctx = calloc(1, sizeof(*ctx));
2066   if(!ctx) {
2067     result = CURLE_OUT_OF_MEMORY;
2068     goto out;
2069   }
2070   ctx->transport = conn->transport;
2071   ctx->sock = *s;
2072   ctx->listening = TRUE;
2073   ctx->accepted = FALSE;
2074   result = Curl_cf_create(&cf, &Curl_cft_tcp_accept, ctx);
2075   if(result)
2076     goto out;
2077   Curl_conn_cf_add(data, conn, sockindex, cf);
2078 
2079   conn->sock[sockindex] = ctx->sock;
2080   set_local_ip(cf, data);
2081   ctx->active = TRUE;
2082   ctx->connected_at = Curl_now();
2083   cf->connected = TRUE;
2084   CURL_TRC_CF(data, cf, "Curl_conn_tcp_listen_set(%" FMT_SOCKET_T ")",
2085               ctx->sock);
2086 
2087 out:
2088   if(result) {
2089     Curl_safefree(cf);
2090     Curl_safefree(ctx);
2091   }
2092   return result;
2093 }
2094 
set_accepted_remote_ip(struct Curl_cfilter * cf,struct Curl_easy * data)2095 static void set_accepted_remote_ip(struct Curl_cfilter *cf,
2096                                    struct Curl_easy *data)
2097 {
2098   struct cf_socket_ctx *ctx = cf->ctx;
2099 #ifdef HAVE_GETPEERNAME
2100   char buffer[STRERROR_LEN];
2101   struct Curl_sockaddr_storage ssrem;
2102   curl_socklen_t plen;
2103 
2104   ctx->ip.remote_ip[0] = 0;
2105   ctx->ip.remote_port = 0;
2106   plen = sizeof(ssrem);
2107   memset(&ssrem, 0, plen);
2108   if(getpeername(ctx->sock, (struct sockaddr*) &ssrem, &plen)) {
2109     int error = SOCKERRNO;
2110     failf(data, "getpeername() failed with errno %d: %s",
2111           error, Curl_strerror(error, buffer, sizeof(buffer)));
2112     return;
2113   }
2114   if(!Curl_addr2string((struct sockaddr*)&ssrem, plen,
2115                        ctx->ip.remote_ip, &ctx->ip.remote_port)) {
2116     failf(data, "ssrem inet_ntop() failed with errno %d: %s",
2117           errno, Curl_strerror(errno, buffer, sizeof(buffer)));
2118     return;
2119   }
2120 #else
2121   ctx->ip.remote_ip[0] = 0;
2122   ctx->ip.remote_port = 0;
2123   (void)data;
2124 #endif
2125 }
2126 
Curl_conn_tcp_accepted_set(struct Curl_easy * data,struct connectdata * conn,int sockindex,curl_socket_t * s)2127 CURLcode Curl_conn_tcp_accepted_set(struct Curl_easy *data,
2128                                     struct connectdata *conn,
2129                                     int sockindex, curl_socket_t *s)
2130 {
2131   struct Curl_cfilter *cf = NULL;
2132   struct cf_socket_ctx *ctx = NULL;
2133 
2134   cf = conn->cfilter[sockindex];
2135   if(!cf || cf->cft != &Curl_cft_tcp_accept)
2136     return CURLE_FAILED_INIT;
2137 
2138   ctx = cf->ctx;
2139   DEBUGASSERT(ctx->listening);
2140   /* discard the listen socket */
2141   socket_close(data, conn, TRUE, ctx->sock);
2142   ctx->listening = FALSE;
2143   ctx->sock = *s;
2144   conn->sock[sockindex] = ctx->sock;
2145   set_accepted_remote_ip(cf, data);
2146   set_local_ip(cf, data);
2147   ctx->active = TRUE;
2148   ctx->accepted = TRUE;
2149   ctx->connected_at = Curl_now();
2150   cf->connected = TRUE;
2151   CURL_TRC_CF(data, cf, "accepted_set(sock=%" FMT_SOCKET_T
2152               ", remote=%s port=%d)",
2153               ctx->sock, ctx->ip.remote_ip, ctx->ip.remote_port);
2154 
2155   return CURLE_OK;
2156 }
2157 
2158 /**
2159  * Return TRUE iff `cf` is a socket filter.
2160  */
cf_is_socket(struct Curl_cfilter * cf)2161 static bool cf_is_socket(struct Curl_cfilter *cf)
2162 {
2163   return cf && (cf->cft == &Curl_cft_tcp ||
2164                 cf->cft == &Curl_cft_udp ||
2165                 cf->cft == &Curl_cft_unix ||
2166                 cf->cft == &Curl_cft_tcp_accept);
2167 }
2168 
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)2169 CURLcode Curl_cf_socket_peek(struct Curl_cfilter *cf,
2170                              struct Curl_easy *data,
2171                              curl_socket_t *psock,
2172                              const struct Curl_sockaddr_ex **paddr,
2173                              struct ip_quadruple *pip)
2174 {
2175   (void)data;
2176   if(cf_is_socket(cf) && cf->ctx) {
2177     struct cf_socket_ctx *ctx = cf->ctx;
2178 
2179     if(psock)
2180       *psock = ctx->sock;
2181     if(paddr)
2182       *paddr = &ctx->addr;
2183     if(pip)
2184       *pip = ctx->ip;
2185     return CURLE_OK;
2186   }
2187   return CURLE_FAILED_INIT;
2188 }
2189