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