quickjs-tart

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

ares_socket.c (12838B)


      1 /* MIT License
      2  *
      3  * Copyright (c) Massachusetts Institute of Technology
      4  * Copyright (c) The c-ares project and its contributors
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and associated documentation files (the "Software"), to deal
      8  * in the Software without restriction, including without limitation the rights
      9  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     10  * copies of the Software, and to permit persons to whom the Software is
     11  * furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice and this permission notice (including the next
     14  * paragraph) shall be included in all copies or substantial portions of the
     15  * Software.
     16  *
     17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23  * SOFTWARE.
     24  *
     25  * SPDX-License-Identifier: MIT
     26  */
     27 #include "ares_private.h"
     28 #ifdef HAVE_SYS_UIO_H
     29 #  include <sys/uio.h>
     30 #endif
     31 #ifdef HAVE_NETINET_IN_H
     32 #  include <netinet/in.h>
     33 #endif
     34 #ifdef HAVE_NETINET_TCP_H
     35 #  include <netinet/tcp.h>
     36 #endif
     37 #ifdef HAVE_NETDB_H
     38 #  include <netdb.h>
     39 #endif
     40 #ifdef HAVE_ARPA_INET_H
     41 #  include <arpa/inet.h>
     42 #endif
     43 
     44 #ifdef HAVE_STRINGS_H
     45 #  include <strings.h>
     46 #endif
     47 #ifdef HAVE_SYS_IOCTL_H
     48 #  include <sys/ioctl.h>
     49 #endif
     50 #ifdef NETWARE
     51 #  include <sys/filio.h>
     52 #endif
     53 
     54 #include <assert.h>
     55 #include <fcntl.h>
     56 #include <limits.h>
     57 
     58 static ares_conn_err_t ares_socket_deref_error(int err)
     59 {
     60   switch (err) {
     61 #if defined(EWOULDBLOCK)
     62     case EWOULDBLOCK:
     63       return ARES_CONN_ERR_WOULDBLOCK;
     64 #endif
     65 #if defined(EAGAIN) && (!defined(EWOULDBLOCK) || EAGAIN != EWOULDBLOCK)
     66     case EAGAIN:
     67       return ARES_CONN_ERR_WOULDBLOCK;
     68 #endif
     69     case EINPROGRESS:
     70       return ARES_CONN_ERR_WOULDBLOCK;
     71     case ENETDOWN:
     72       return ARES_CONN_ERR_NETDOWN;
     73     case ENETUNREACH:
     74       return ARES_CONN_ERR_NETUNREACH;
     75     case ECONNABORTED:
     76       return ARES_CONN_ERR_CONNABORTED;
     77     case ECONNRESET:
     78       return ARES_CONN_ERR_CONNRESET;
     79     case ECONNREFUSED:
     80       return ARES_CONN_ERR_CONNREFUSED;
     81     case ETIMEDOUT:
     82       return ARES_CONN_ERR_CONNTIMEDOUT;
     83     case EHOSTDOWN:
     84       return ARES_CONN_ERR_HOSTDOWN;
     85     case EHOSTUNREACH:
     86       return ARES_CONN_ERR_HOSTUNREACH;
     87     case EINTR:
     88       return ARES_CONN_ERR_INTERRUPT;
     89     case EAFNOSUPPORT:
     90       return ARES_CONN_ERR_AFNOSUPPORT;
     91     case EADDRNOTAVAIL:
     92       return ARES_CONN_ERR_BADADDR;
     93     default:
     94       break;
     95   }
     96 
     97   return ARES_CONN_ERR_FAILURE;
     98 }
     99 
    100 ares_bool_t ares_sockaddr_addr_eq(const struct sockaddr  *sa,
    101                                   const struct ares_addr *aa)
    102 {
    103   const void *addr1;
    104   const void *addr2;
    105 
    106   if (sa->sa_family == aa->family) {
    107     switch (aa->family) {
    108       case AF_INET:
    109         addr1 = &aa->addr.addr4;
    110         addr2 = &(CARES_INADDR_CAST(const struct sockaddr_in *, sa))->sin_addr;
    111         if (memcmp(addr1, addr2, sizeof(aa->addr.addr4)) == 0) {
    112           return ARES_TRUE; /* match */
    113         }
    114         break;
    115       case AF_INET6:
    116         addr1 = &aa->addr.addr6;
    117         addr2 =
    118           &(CARES_INADDR_CAST(const struct sockaddr_in6 *, sa))->sin6_addr;
    119         if (memcmp(addr1, addr2, sizeof(aa->addr.addr6)) == 0) {
    120           return ARES_TRUE; /* match */
    121         }
    122         break;
    123       default:
    124         break; /* LCOV_EXCL_LINE */
    125     }
    126   }
    127   return ARES_FALSE; /* different */
    128 }
    129 
    130 ares_conn_err_t ares_socket_write(ares_channel_t *channel, ares_socket_t fd,
    131                                   const void *data, size_t len, size_t *written,
    132                                   const struct sockaddr *sa,
    133                                   ares_socklen_t         salen)
    134 {
    135   int             flags = 0;
    136   ares_ssize_t    rv;
    137   ares_conn_err_t err = ARES_CONN_ERR_SUCCESS;
    138 
    139 #ifdef HAVE_MSG_NOSIGNAL
    140   flags |= MSG_NOSIGNAL;
    141 #endif
    142 
    143   rv = channel->sock_funcs.asendto(fd, data, len, flags, sa, salen,
    144                                    channel->sock_func_cb_data);
    145   if (rv <= 0) {
    146     err = ares_socket_deref_error(SOCKERRNO);
    147   } else {
    148     *written = (size_t)rv;
    149   }
    150   return err;
    151 }
    152 
    153 ares_conn_err_t ares_socket_recv(ares_channel_t *channel, ares_socket_t s,
    154                                  ares_bool_t is_tcp, void *data,
    155                                  size_t data_len, size_t *read_bytes)
    156 {
    157   ares_ssize_t rv;
    158 
    159   *read_bytes = 0;
    160 
    161   rv = channel->sock_funcs.arecvfrom(s, data, data_len, 0, NULL, 0,
    162                                      channel->sock_func_cb_data);
    163 
    164   if (rv > 0) {
    165     *read_bytes = (size_t)rv;
    166     return ARES_CONN_ERR_SUCCESS;
    167   }
    168 
    169   if (rv == 0) {
    170     /* UDP allows 0-byte packets and is connectionless, so this is success */
    171     if (!is_tcp) {
    172       return ARES_CONN_ERR_SUCCESS;
    173     } else {
    174       return ARES_CONN_ERR_CONNCLOSED;
    175     }
    176   }
    177 
    178   /* If we're here, rv<0 */
    179   return ares_socket_deref_error(SOCKERRNO);
    180 }
    181 
    182 ares_conn_err_t ares_socket_recvfrom(ares_channel_t *channel, ares_socket_t s,
    183                                      ares_bool_t is_tcp, void *data,
    184                                      size_t data_len, int flags,
    185                                      struct sockaddr *from,
    186                                      ares_socklen_t  *from_len,
    187                                      size_t          *read_bytes)
    188 {
    189   ares_ssize_t rv;
    190 
    191   rv = channel->sock_funcs.arecvfrom(s, data, data_len, flags, from, from_len,
    192                                      channel->sock_func_cb_data);
    193 
    194   if (rv > 0) {
    195     *read_bytes = (size_t)rv;
    196     return ARES_CONN_ERR_SUCCESS;
    197   }
    198 
    199   if (rv == 0) {
    200     /* UDP allows 0-byte packets and is connectionless, so this is success */
    201     if (!is_tcp) {
    202       return ARES_CONN_ERR_SUCCESS;
    203     } else {
    204       return ARES_CONN_ERR_CONNCLOSED;
    205     }
    206   }
    207 
    208   /* If we're here, rv<0 */
    209   return ares_socket_deref_error(SOCKERRNO);
    210 }
    211 
    212 ares_conn_err_t ares_socket_enable_tfo(const ares_channel_t *channel,
    213                                        ares_socket_t         fd)
    214 {
    215   ares_bool_t opt = ARES_TRUE;
    216 
    217   if (channel->sock_funcs.asetsockopt(fd, ARES_SOCKET_OPT_TCP_FASTOPEN,
    218                                       (void *)&opt, sizeof(opt),
    219                                       channel->sock_func_cb_data) != 0) {
    220     return ARES_CONN_ERR_NOTIMP;
    221   }
    222 
    223   return ARES_CONN_ERR_SUCCESS;
    224 }
    225 
    226 ares_status_t ares_socket_configure(ares_channel_t *channel, int family,
    227                                     ares_bool_t is_tcp, ares_socket_t fd)
    228 {
    229   union {
    230     struct sockaddr     sa;
    231     struct sockaddr_in  sa4;
    232     struct sockaddr_in6 sa6;
    233   } local;
    234 
    235   ares_socklen_t bindlen = 0;
    236   int            rv;
    237   unsigned int   bind_flags = 0;
    238 
    239   /* Set the socket's send and receive buffer sizes. */
    240   if (channel->socket_send_buffer_size > 0) {
    241     rv = channel->sock_funcs.asetsockopt(
    242       fd, ARES_SOCKET_OPT_SENDBUF_SIZE,
    243       (void *)&channel->socket_send_buffer_size,
    244       sizeof(channel->socket_send_buffer_size), channel->sock_func_cb_data);
    245     if (rv != 0 && SOCKERRNO != ENOSYS) {
    246       return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */
    247     }
    248   }
    249 
    250   if (channel->socket_receive_buffer_size > 0) {
    251     rv = channel->sock_funcs.asetsockopt(
    252       fd, ARES_SOCKET_OPT_RECVBUF_SIZE,
    253       (void *)&channel->socket_receive_buffer_size,
    254       sizeof(channel->socket_receive_buffer_size), channel->sock_func_cb_data);
    255     if (rv != 0 && SOCKERRNO != ENOSYS) {
    256       return ARES_ECONNREFUSED; /* LCOV_EXCL_LINE: UntestablePath */
    257     }
    258   }
    259 
    260   /* Bind to network interface if configured */
    261   if (ares_strlen(channel->local_dev_name)) {
    262     /* Prior versions silently ignored failure, so we need to maintain that
    263      * compatibility */
    264     (void)channel->sock_funcs.asetsockopt(
    265       fd, ARES_SOCKET_OPT_BIND_DEVICE, channel->local_dev_name,
    266       (ares_socklen_t)ares_strlen(channel->local_dev_name),
    267       channel->sock_func_cb_data);
    268   }
    269 
    270   /* Bind to ip address if configured */
    271   if (family == AF_INET && channel->local_ip4) {
    272     memset(&local.sa4, 0, sizeof(local.sa4));
    273     local.sa4.sin_family      = AF_INET;
    274     local.sa4.sin_addr.s_addr = htonl(channel->local_ip4);
    275     bindlen                   = sizeof(local.sa4);
    276   } else if (family == AF_INET6 &&
    277              memcmp(channel->local_ip6, ares_in6addr_any._S6_un._S6_u8,
    278                     sizeof(channel->local_ip6)) != 0) {
    279     /* Only if not link-local and an ip other than "::" is specified */
    280     memset(&local.sa6, 0, sizeof(local.sa6));
    281     local.sa6.sin6_family = AF_INET6;
    282     memcpy(&local.sa6.sin6_addr, channel->local_ip6,
    283            sizeof(channel->local_ip6));
    284     bindlen = sizeof(local.sa6);
    285   }
    286 
    287 
    288   if (bindlen && channel->sock_funcs.abind != NULL) {
    289     bind_flags |= ARES_SOCKET_BIND_CLIENT;
    290     if (is_tcp) {
    291       bind_flags |= ARES_SOCKET_BIND_TCP;
    292     }
    293     if (channel->sock_funcs.abind(fd, bind_flags, &local.sa, bindlen,
    294                                   channel->sock_func_cb_data) != 0) {
    295       return ARES_ECONNREFUSED;
    296     }
    297   }
    298 
    299   return ARES_SUCCESS;
    300 }
    301 
    302 ares_bool_t ares_sockaddr_to_ares_addr(struct ares_addr      *ares_addr,
    303                                        unsigned short        *port,
    304                                        const struct sockaddr *sockaddr)
    305 {
    306   if (sockaddr->sa_family == AF_INET) {
    307     /* NOTE: memcpy sockaddr_in due to alignment issues found by UBSAN due to
    308      *       dnsinfo packing on MacOS */
    309     struct sockaddr_in sockaddr_in;
    310     memcpy(&sockaddr_in, sockaddr, sizeof(sockaddr_in));
    311 
    312     ares_addr->family = AF_INET;
    313     memcpy(&ares_addr->addr.addr4, &(sockaddr_in.sin_addr),
    314            sizeof(ares_addr->addr.addr4));
    315 
    316     if (port) {
    317       *port = ntohs(sockaddr_in.sin_port);
    318     }
    319     return ARES_TRUE;
    320   }
    321 
    322   if (sockaddr->sa_family == AF_INET6) {
    323     /* NOTE: memcpy sockaddr_in6 due to alignment issues found by UBSAN due to
    324      *       dnsinfo packing on MacOS */
    325     struct sockaddr_in6 sockaddr_in6;
    326     memcpy(&sockaddr_in6, sockaddr, sizeof(sockaddr_in6));
    327 
    328     ares_addr->family = AF_INET6;
    329     memcpy(&ares_addr->addr.addr6, &(sockaddr_in6.sin6_addr),
    330            sizeof(ares_addr->addr.addr6));
    331     if (port) {
    332       *port = ntohs(sockaddr_in6.sin6_port);
    333     }
    334     return ARES_TRUE;
    335   }
    336 
    337   return ARES_FALSE;
    338 }
    339 
    340 ares_conn_err_t ares_socket_open(ares_socket_t *sock, ares_channel_t *channel,
    341                                  int af, int type, int protocol)
    342 {
    343   ares_socket_t s;
    344 
    345   *sock = ARES_SOCKET_BAD;
    346 
    347   s =
    348     channel->sock_funcs.asocket(af, type, protocol, channel->sock_func_cb_data);
    349 
    350   if (s == ARES_SOCKET_BAD) {
    351     return ares_socket_deref_error(SOCKERRNO);
    352   }
    353 
    354   *sock = s;
    355 
    356   return ARES_CONN_ERR_SUCCESS;
    357 }
    358 
    359 ares_conn_err_t ares_socket_connect(ares_channel_t *channel,
    360                                     ares_socket_t sockfd, ares_bool_t is_tfo,
    361                                     const struct sockaddr *addr,
    362                                     ares_socklen_t         addrlen)
    363 {
    364   ares_conn_err_t err   = ARES_CONN_ERR_SUCCESS;
    365   unsigned int    flags = 0;
    366 
    367   if (is_tfo) {
    368     flags |= ARES_SOCKET_CONN_TCP_FASTOPEN;
    369   }
    370 
    371   do {
    372     int rv;
    373 
    374     rv = channel->sock_funcs.aconnect(sockfd, addr, addrlen, flags,
    375                                       channel->sock_func_cb_data);
    376 
    377     if (rv < 0) {
    378       err = ares_socket_deref_error(SOCKERRNO);
    379     } else {
    380       err = ARES_CONN_ERR_SUCCESS;
    381     }
    382   } while (err == ARES_CONN_ERR_INTERRUPT);
    383 
    384   return err;
    385 }
    386 
    387 void ares_socket_close(ares_channel_t *channel, ares_socket_t s)
    388 {
    389   if (channel == NULL || s == ARES_SOCKET_BAD) {
    390     return;
    391   }
    392 
    393   channel->sock_funcs.aclose(s, channel->sock_func_cb_data);
    394 }
    395 
    396 void ares_set_socket_callback(ares_channel_t           *channel,
    397                               ares_sock_create_callback cb, void *data)
    398 {
    399   if (channel == NULL) {
    400     return;
    401   }
    402   channel->sock_create_cb      = cb;
    403   channel->sock_create_cb_data = data;
    404 }
    405 
    406 void ares_set_socket_configure_callback(ares_channel_t           *channel,
    407                                         ares_sock_config_callback cb,
    408                                         void                     *data)
    409 {
    410   if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
    411     return;
    412   }
    413   channel->sock_config_cb      = cb;
    414   channel->sock_config_cb_data = data;
    415 }
    416 
    417 void ares_set_pending_write_cb(ares_channel_t       *channel,
    418                                ares_pending_write_cb callback, void *user_data)
    419 {
    420   if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
    421     return;
    422   }
    423   channel->notify_pending_write_cb      = callback;
    424   channel->notify_pending_write_cb_data = user_data;
    425 }