quickjs-tart

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

ares_set_socket_functions.c (17541B)


      1 /* MIT License
      2  *
      3  * Copyright (c) 2024 Brad House
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining a copy
      6  * of this software and associated documentation files (the "Software"), to deal
      7  * in the Software without restriction, including without limitation the rights
      8  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      9  * copies of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice (including the next
     13  * paragraph) shall be included in all copies or substantial portions of the
     14  * Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  *
     24  * SPDX-License-Identifier: MIT
     25  */
     26 #include "ares_private.h"
     27 #ifdef HAVE_SYS_UIO_H
     28 #  include <sys/uio.h>
     29 #endif
     30 #ifdef HAVE_NETINET_IN_H
     31 #  include <netinet/in.h>
     32 #endif
     33 #ifdef HAVE_NETINET_TCP_H
     34 #  include <netinet/tcp.h>
     35 #endif
     36 #ifdef HAVE_NETDB_H
     37 #  include <netdb.h>
     38 #endif
     39 #ifdef HAVE_ARPA_INET_H
     40 #  include <arpa/inet.h>
     41 #endif
     42 
     43 #ifdef HAVE_STRINGS_H
     44 #  include <strings.h>
     45 #endif
     46 #ifdef HAVE_SYS_IOCTL_H
     47 #  include <sys/ioctl.h>
     48 #endif
     49 #ifdef NETWARE
     50 #  include <sys/filio.h>
     51 #endif
     52 
     53 #include <assert.h>
     54 #include <fcntl.h>
     55 #include <limits.h>
     56 
     57 
     58 #if defined(__linux__) && defined(TCP_FASTOPEN_CONNECT)
     59 #  define TFO_SUPPORTED      1
     60 #  define TFO_SKIP_CONNECT   0
     61 #  define TFO_USE_SENDTO     0
     62 #  define TFO_USE_CONNECTX   0
     63 #  define TFO_CLIENT_SOCKOPT TCP_FASTOPEN_CONNECT
     64 #elif defined(__FreeBSD__) && defined(TCP_FASTOPEN)
     65 #  define TFO_SUPPORTED      1
     66 #  define TFO_SKIP_CONNECT   1
     67 #  define TFO_USE_SENDTO     1
     68 #  define TFO_USE_CONNECTX   0
     69 #  define TFO_CLIENT_SOCKOPT TCP_FASTOPEN
     70 #elif defined(__APPLE__) && defined(HAVE_CONNECTX)
     71 #  define TFO_SUPPORTED    1
     72 #  define TFO_SKIP_CONNECT 0
     73 #  define TFO_USE_SENDTO   0
     74 #  define TFO_USE_CONNECTX 1
     75 #  undef TFO_CLIENT_SOCKOPT
     76 #else
     77 #  define TFO_SUPPORTED 0
     78 #endif
     79 
     80 #ifndef HAVE_WRITEV
     81 /* Structure for scatter/gather I/O. */
     82 struct iovec {
     83   void  *iov_base; /* Pointer to data. */
     84   size_t iov_len;  /* Length of data.  */
     85 };
     86 #endif
     87 
     88 ares_status_t
     89   ares_set_socket_functions_ex(ares_channel_t                        *channel,
     90                                const struct ares_socket_functions_ex *funcs,
     91                                void                                  *user_data)
     92 {
     93   unsigned int known_versions[] = { 1 };
     94   size_t       i;
     95 
     96   if (channel == NULL || funcs == NULL) {
     97     return ARES_EFORMERR;
     98   }
     99 
    100   /* Check to see if we know the version referenced */
    101   for (i = 0; i < sizeof(known_versions) / sizeof(*known_versions); i++) {
    102     if (funcs->version == known_versions[i]) {
    103       break;
    104     }
    105   }
    106   if (i == sizeof(known_versions) / sizeof(*known_versions)) {
    107     return ARES_EFORMERR;
    108   }
    109 
    110   memset(&channel->sock_funcs, 0, sizeof(channel->sock_funcs));
    111 
    112   /* Copy individually for ABI compliance.  memcpy() with a sizeof would do
    113    * invalid reads */
    114   if (funcs->version >= 1) {
    115     if (funcs->asocket == NULL || funcs->aclose == NULL ||
    116         funcs->asetsockopt == NULL || funcs->aconnect == NULL ||
    117         funcs->arecvfrom == NULL || funcs->asendto == NULL) {
    118       return ARES_EFORMERR;
    119     }
    120     channel->sock_funcs.version      = funcs->version;
    121     channel->sock_funcs.flags        = funcs->flags;
    122     channel->sock_funcs.asocket      = funcs->asocket;
    123     channel->sock_funcs.aclose       = funcs->aclose;
    124     channel->sock_funcs.asetsockopt  = funcs->asetsockopt;
    125     channel->sock_funcs.aconnect     = funcs->aconnect;
    126     channel->sock_funcs.arecvfrom    = funcs->arecvfrom;
    127     channel->sock_funcs.asendto      = funcs->asendto;
    128     channel->sock_funcs.agetsockname = funcs->agetsockname;
    129     channel->sock_funcs.abind        = funcs->abind;
    130   }
    131 
    132   /* Implement newer versions here ...*/
    133 
    134 
    135   channel->sock_func_cb_data = user_data;
    136 
    137   return ARES_SUCCESS;
    138 }
    139 
    140 static int setsocknonblock(ares_socket_t sockfd, /* operate on this */
    141                            int           nonblock /* TRUE or FALSE */)
    142 {
    143 #if defined(HAVE_FCNTL_O_NONBLOCK)
    144 
    145   /* most recent unix versions */
    146   int flags;
    147   flags = fcntl(sockfd, F_GETFL, 0);
    148   if (nonblock) {
    149     return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
    150   } else {
    151     return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); /* LCOV_EXCL_LINE */
    152   }
    153 
    154 #elif defined(HAVE_IOCTL_FIONBIO)
    155 
    156   /* older unix versions */
    157   int flags = nonblock ? 1 : 0;
    158   return ioctl(sockfd, FIONBIO, &flags);
    159 
    160 #elif defined(HAVE_IOCTLSOCKET_FIONBIO)
    161 
    162 #  ifdef WATT32
    163   char flags = nonblock ? 1 : 0;
    164 #  else
    165   /* Windows */
    166   unsigned long flags = nonblock ? 1UL : 0UL;
    167 #  endif
    168   return ioctlsocket(sockfd, (long)FIONBIO, &flags);
    169 
    170 #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
    171 
    172   /* Amiga */
    173   long flags = nonblock ? 1L : 0L;
    174   return IoctlSocket(sockfd, FIONBIO, flags);
    175 
    176 #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
    177 
    178   /* BeOS */
    179   long b = nonblock ? 1L : 0L;
    180   return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
    181 
    182 #else
    183 #  error "no non-blocking method was found/used/set"
    184 #endif
    185 }
    186 
    187 static int default_aclose(ares_socket_t sock, void *user_data)
    188 {
    189   (void)user_data;
    190 
    191 #if defined(HAVE_CLOSESOCKET)
    192   return closesocket(sock);
    193 #elif defined(HAVE_CLOSESOCKET_CAMEL)
    194   return CloseSocket(sock);
    195 #elif defined(HAVE_CLOSE_S)
    196   return close_s(sock);
    197 #else
    198   return close(sock);
    199 #endif
    200 }
    201 
    202 static ares_socket_t default_asocket(int domain, int type, int protocol,
    203                                      void *user_data)
    204 {
    205   ares_socket_t s;
    206   (void)user_data;
    207 
    208   s = socket(domain, type, protocol);
    209   if (s == ARES_SOCKET_BAD) {
    210     return s;
    211   }
    212 
    213   if (setsocknonblock(s, 1) != 0) {
    214     goto fail; /* LCOV_EXCL_LINE */
    215   }
    216 
    217 #if defined(FD_CLOEXEC) && !defined(MSDOS)
    218   /* Configure the socket fd as close-on-exec. */
    219   if (fcntl(s, F_SETFD, FD_CLOEXEC) != 0) {
    220     goto fail; /* LCOV_EXCL_LINE */
    221   }
    222 #endif
    223 
    224   /* No need to emit SIGPIPE on socket errors */
    225 #if defined(SO_NOSIGPIPE)
    226   {
    227     int opt = 1;
    228     (void)setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
    229   }
    230 #endif
    231 
    232 
    233   if (type == SOCK_STREAM) {
    234     int opt = 1;
    235 
    236 #ifdef TCP_NODELAY
    237     /*
    238      * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
    239      * in configure_socket). In general, in DNS lookups we're pretty much
    240      * interested in firing off a single request and then waiting for a reply,
    241      * so batching isn't very interesting.
    242      */
    243     if (setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) !=
    244         0) {
    245       goto fail;
    246     }
    247 #endif
    248   }
    249 
    250 #if defined(IPV6_V6ONLY) && defined(USE_WINSOCK)
    251   /* Support for IPv4-mapped IPv6 addresses.
    252    * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
    253    * Windows Vista and later: default is on;
    254    * DragonFly BSD: acts like off, and dummy setting;
    255    * OpenBSD and earlier Windows: unsupported.
    256    * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
    257    */
    258   if (domain == PF_INET6) {
    259     int on = 0;
    260     (void)setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
    261   }
    262 #endif
    263 
    264   return s;
    265 
    266 fail:
    267   default_aclose(s, user_data);
    268   return ARES_SOCKET_BAD;
    269 }
    270 
    271 static int default_asetsockopt(ares_socket_t sock, ares_socket_opt_t opt,
    272                                const void *val, ares_socklen_t val_size,
    273                                void *user_data)
    274 {
    275   switch (opt) {
    276     case ARES_SOCKET_OPT_SENDBUF_SIZE:
    277       if (val_size != sizeof(int)) {
    278         SET_SOCKERRNO(EINVAL);
    279         return -1;
    280       }
    281       return setsockopt(sock, SOL_SOCKET, SO_SNDBUF, val, val_size);
    282 
    283     case ARES_SOCKET_OPT_RECVBUF_SIZE:
    284       if (val_size != sizeof(int)) {
    285         SET_SOCKERRNO(EINVAL);
    286         return -1;
    287       }
    288       return setsockopt(sock, SOL_SOCKET, SO_RCVBUF, val, val_size);
    289 
    290     case ARES_SOCKET_OPT_BIND_DEVICE:
    291       /* Count the number of characters before NULL terminator then
    292        * validate those are all printable */
    293       if (!ares_str_isprint(val, ares_strnlen(val, (size_t)val_size))) {
    294         SET_SOCKERRNO(EINVAL);
    295         return -1;
    296       }
    297 #ifdef SO_BINDTODEVICE
    298       return setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, val, val_size);
    299 #else
    300       SET_SOCKERRNO(ENOSYS);
    301       return -1;
    302 #endif
    303 
    304     case ARES_SOCKET_OPT_TCP_FASTOPEN:
    305       if (val_size != sizeof(ares_bool_t)) {
    306         SET_SOCKERRNO(EINVAL);
    307         return -1;
    308       }
    309 #if defined(TFO_CLIENT_SOCKOPT)
    310       {
    311         int                oval;
    312         const ares_bool_t *pval = val;
    313         oval                    = (int)*pval;
    314         return setsockopt(sock, IPPROTO_TCP, TFO_CLIENT_SOCKOPT, (void *)&oval,
    315                           sizeof(oval));
    316       }
    317 #elif TFO_SUPPORTED
    318       return 0;
    319 #else
    320       SET_SOCKERRNO(ENOSYS);
    321       return -1;
    322 #endif
    323   }
    324 
    325   (void)user_data;
    326   SET_SOCKERRNO(ENOSYS);
    327   return -1;
    328 }
    329 
    330 static int default_aconnect(ares_socket_t sock, const struct sockaddr *address,
    331                             ares_socklen_t address_len, unsigned int flags,
    332                             void *user_data)
    333 {
    334   (void)user_data;
    335 
    336 #if defined(TFO_SKIP_CONNECT) && TFO_SKIP_CONNECT
    337   if (flags & ARES_SOCKET_CONN_TCP_FASTOPEN) {
    338     return 0;
    339   }
    340   return connect(sock, address, address_len);
    341 #elif defined(TFO_USE_CONNECTX) && TFO_USE_CONNECTX
    342   if (flags & ARES_SOCKET_CONN_TCP_FASTOPEN) {
    343     sa_endpoints_t endpoints;
    344 
    345     memset(&endpoints, 0, sizeof(endpoints));
    346     endpoints.sae_dstaddr    = address;
    347     endpoints.sae_dstaddrlen = address_len;
    348 
    349     return connectx(sock, &endpoints, SAE_ASSOCID_ANY,
    350                     CONNECT_DATA_IDEMPOTENT | CONNECT_RESUME_ON_READ_WRITE,
    351                     NULL, 0, NULL, NULL);
    352   } else {
    353     return connect(sock, address, address_len);
    354   }
    355 #else
    356   (void)flags;
    357   return connect(sock, address, address_len);
    358 #endif
    359 }
    360 
    361 static ares_ssize_t default_arecvfrom(ares_socket_t sock, void *buffer,
    362                                       size_t length, int flags,
    363                                       struct sockaddr *address,
    364                                       ares_socklen_t  *address_len,
    365                                       void            *user_data)
    366 {
    367   (void)user_data;
    368 
    369 #ifdef HAVE_RECVFROM
    370   return (ares_ssize_t)recvfrom(sock, buffer, (RECVFROM_TYPE_ARG3)length, flags,
    371                                 address, address_len);
    372 #else
    373   if (address != NULL && address_len != NULL) {
    374     memset(address, 0, (size_t)*address_len);
    375     address->sa_family = AF_UNSPEC;
    376   }
    377   return (ares_ssize_t)recv(sock, buffer, (RECVFROM_TYPE_ARG3)length, flags);
    378 #endif
    379 }
    380 
    381 static ares_ssize_t default_asendto(ares_socket_t sock, const void *buffer,
    382                                     size_t length, int flags,
    383                                     const struct sockaddr *address,
    384                                     ares_socklen_t address_len, void *user_data)
    385 {
    386   (void)user_data;
    387 
    388   if (address != NULL) {
    389 #ifdef HAVE_SENDTO
    390     return (ares_ssize_t)sendto((SEND_TYPE_ARG1)sock, (SEND_TYPE_ARG2)buffer,
    391                                 (SEND_TYPE_ARG3)length, (SEND_TYPE_ARG4)flags,
    392                                 address, address_len);
    393 #else
    394     (void)address_len;
    395 #endif
    396   }
    397 
    398   return (ares_ssize_t)send((SEND_TYPE_ARG1)sock, (SEND_TYPE_ARG2)buffer,
    399                             (SEND_TYPE_ARG3)length, (SEND_TYPE_ARG4)flags);
    400 }
    401 
    402 static int default_agetsockname(ares_socket_t sock, struct sockaddr *address,
    403                                 ares_socklen_t *address_len, void *user_data)
    404 {
    405   (void)user_data;
    406   return getsockname(sock, address, address_len);
    407 }
    408 
    409 static int default_abind(ares_socket_t sock, unsigned int flags,
    410                          const struct sockaddr *address, socklen_t address_len,
    411                          void *user_data)
    412 {
    413   (void)user_data;
    414 
    415 #ifdef IP_BIND_ADDRESS_NO_PORT
    416   if (flags & ARES_SOCKET_BIND_TCP && flags & ARES_SOCKET_BIND_CLIENT) {
    417     int opt = 1;
    418     (void)setsockopt(sock, SOL_IP, IP_BIND_ADDRESS_NO_PORT, &opt, sizeof(opt));
    419   }
    420 #else
    421   (void)flags;
    422 #endif
    423 
    424   return bind(sock, address, address_len);
    425 }
    426 
    427 static unsigned int default_aif_nametoindex(const char *ifname, void *user_data)
    428 {
    429   (void)user_data;
    430   return ares_os_if_nametoindex(ifname);
    431 }
    432 
    433 static const char *default_aif_indextoname(unsigned int ifindex,
    434                                            char        *ifname_buf,
    435                                            size_t       ifname_buf_len,
    436                                            void        *user_data)
    437 {
    438   (void)user_data;
    439   return ares_os_if_indextoname(ifindex, ifname_buf, ifname_buf_len);
    440 }
    441 
    442 static const struct ares_socket_functions_ex default_socket_functions = {
    443   1,
    444   ARES_SOCKFUNC_FLAG_NONBLOCKING,
    445   default_asocket,
    446   default_aclose,
    447   default_asetsockopt,
    448   default_aconnect,
    449   default_arecvfrom,
    450   default_asendto,
    451   default_agetsockname,
    452   default_abind,
    453   default_aif_nametoindex,
    454   default_aif_indextoname
    455 };
    456 
    457 void ares_set_socket_functions_def(ares_channel_t *channel)
    458 {
    459   ares_set_socket_functions_ex(channel, &default_socket_functions, NULL);
    460 }
    461 
    462 static int legacycb_aclose(ares_socket_t sock, void *user_data)
    463 {
    464   ares_channel_t *channel = user_data;
    465 
    466   if (channel->legacy_sock_funcs != NULL &&
    467       channel->legacy_sock_funcs->aclose != NULL) {
    468     return channel->legacy_sock_funcs->aclose(
    469       sock, channel->legacy_sock_funcs_cb_data);
    470   }
    471 
    472   return default_aclose(sock, NULL);
    473 }
    474 
    475 static ares_socket_t legacycb_asocket(int domain, int type, int protocol,
    476                                       void *user_data)
    477 {
    478   ares_channel_t *channel = user_data;
    479 
    480   if (channel->legacy_sock_funcs != NULL &&
    481       channel->legacy_sock_funcs->asocket != NULL) {
    482     return channel->legacy_sock_funcs->asocket(
    483       domain, type, protocol, channel->legacy_sock_funcs_cb_data);
    484   }
    485 
    486   return default_asocket(domain, type, protocol, NULL);
    487 }
    488 
    489 static int legacycb_asetsockopt(ares_socket_t sock, ares_socket_opt_t opt,
    490                                 const void *val, ares_socklen_t val_size,
    491                                 void *user_data)
    492 {
    493   (void)sock;
    494   (void)opt;
    495   (void)val;
    496   (void)val_size;
    497   (void)user_data;
    498   SET_SOCKERRNO(ENOSYS);
    499   return -1;
    500 }
    501 
    502 static int legacycb_aconnect(ares_socket_t sock, const struct sockaddr *address,
    503                              ares_socklen_t address_len, unsigned int flags,
    504                              void *user_data)
    505 {
    506   ares_channel_t *channel = user_data;
    507 
    508   if (channel->legacy_sock_funcs != NULL &&
    509       channel->legacy_sock_funcs->aconnect != NULL) {
    510     return channel->legacy_sock_funcs->aconnect(
    511       sock, address, address_len, channel->legacy_sock_funcs_cb_data);
    512   }
    513 
    514   return default_aconnect(sock, address, address_len, flags, NULL);
    515 }
    516 
    517 static ares_ssize_t legacycb_arecvfrom(ares_socket_t sock, void *buffer,
    518                                        size_t length, int flags,
    519                                        struct sockaddr *address,
    520                                        ares_socklen_t  *address_len,
    521                                        void            *user_data)
    522 {
    523   ares_channel_t *channel = user_data;
    524 
    525   if (channel->legacy_sock_funcs != NULL &&
    526       channel->legacy_sock_funcs->arecvfrom != NULL) {
    527     if (address != NULL && address_len != NULL) {
    528       memset(address, 0, (size_t)*address_len);
    529       address->sa_family = AF_UNSPEC;
    530     }
    531     return channel->legacy_sock_funcs->arecvfrom(
    532       sock, buffer, length, flags, address, address_len,
    533       channel->legacy_sock_funcs_cb_data);
    534   }
    535 
    536   return default_arecvfrom(sock, buffer, length, flags, address, address_len,
    537                            NULL);
    538 }
    539 
    540 static ares_ssize_t legacycb_asendto(ares_socket_t sock, const void *buffer,
    541                                      size_t length, int flags,
    542                                      const struct sockaddr *address,
    543                                      ares_socklen_t         address_len,
    544                                      void                  *user_data)
    545 {
    546   ares_channel_t *channel = user_data;
    547 
    548   if (channel->legacy_sock_funcs != NULL &&
    549       channel->legacy_sock_funcs->asendv != NULL) {
    550     struct iovec vec;
    551     vec.iov_base = (void *)((size_t)buffer); /* Cast off const */
    552     vec.iov_len  = length;
    553     return channel->legacy_sock_funcs->asendv(
    554       sock, &vec, 1, channel->legacy_sock_funcs_cb_data);
    555   }
    556 
    557   return default_asendto(sock, buffer, length, flags, address, address_len,
    558                          NULL);
    559 }
    560 
    561 
    562 static const struct ares_socket_functions_ex legacy_socket_functions = {
    563   1,
    564   0,
    565   legacycb_asocket,
    566   legacycb_aclose,
    567   legacycb_asetsockopt,
    568   legacycb_aconnect,
    569   legacycb_arecvfrom,
    570   legacycb_asendto,
    571   NULL, /* agetsockname */
    572   NULL, /* abind */
    573   NULL, /* aif_nametoindex */
    574   NULL  /* aif_indextoname */
    575 };
    576 
    577 void ares_set_socket_functions(ares_channel_t                     *channel,
    578                                const struct ares_socket_functions *funcs,
    579                                void                               *data)
    580 {
    581   if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
    582     return;
    583   }
    584 
    585   channel->legacy_sock_funcs         = funcs;
    586   channel->legacy_sock_funcs_cb_data = data;
    587   ares_set_socket_functions_ex(channel, &legacy_socket_functions, channel);
    588 }