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