quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

cf-socket.c (68180B)


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