11cb0ef41Sopenharmony_ci/* MIT License
21cb0ef41Sopenharmony_ci *
31cb0ef41Sopenharmony_ci * Copyright (c) Massachusetts Institute of Technology
41cb0ef41Sopenharmony_ci * Copyright (c) The c-ares project and its contributors
51cb0ef41Sopenharmony_ci *
61cb0ef41Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a copy
71cb0ef41Sopenharmony_ci * of this software and associated documentation files (the "Software"), to deal
81cb0ef41Sopenharmony_ci * in the Software without restriction, including without limitation the rights
91cb0ef41Sopenharmony_ci * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
101cb0ef41Sopenharmony_ci * copies of the Software, and to permit persons to whom the Software is
111cb0ef41Sopenharmony_ci * furnished to do so, subject to the following conditions:
121cb0ef41Sopenharmony_ci *
131cb0ef41Sopenharmony_ci * The above copyright notice and this permission notice (including the next
141cb0ef41Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
151cb0ef41Sopenharmony_ci * Software.
161cb0ef41Sopenharmony_ci *
171cb0ef41Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
181cb0ef41Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
191cb0ef41Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
201cb0ef41Sopenharmony_ci * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
211cb0ef41Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
221cb0ef41Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
231cb0ef41Sopenharmony_ci * SOFTWARE.
241cb0ef41Sopenharmony_ci *
251cb0ef41Sopenharmony_ci * SPDX-License-Identifier: MIT
261cb0ef41Sopenharmony_ci */
271cb0ef41Sopenharmony_ci#include "ares_setup.h"
281cb0ef41Sopenharmony_ci
291cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_UIO_H
301cb0ef41Sopenharmony_ci#  include <sys/uio.h>
311cb0ef41Sopenharmony_ci#endif
321cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_IN_H
331cb0ef41Sopenharmony_ci#  include <netinet/in.h>
341cb0ef41Sopenharmony_ci#endif
351cb0ef41Sopenharmony_ci#ifdef HAVE_NETINET_TCP_H
361cb0ef41Sopenharmony_ci#  include <netinet/tcp.h>
371cb0ef41Sopenharmony_ci#endif
381cb0ef41Sopenharmony_ci#ifdef HAVE_NETDB_H
391cb0ef41Sopenharmony_ci#  include <netdb.h>
401cb0ef41Sopenharmony_ci#endif
411cb0ef41Sopenharmony_ci#ifdef HAVE_ARPA_INET_H
421cb0ef41Sopenharmony_ci#  include <arpa/inet.h>
431cb0ef41Sopenharmony_ci#endif
441cb0ef41Sopenharmony_ci
451cb0ef41Sopenharmony_ci#ifdef HAVE_STRINGS_H
461cb0ef41Sopenharmony_ci#  include <strings.h>
471cb0ef41Sopenharmony_ci#endif
481cb0ef41Sopenharmony_ci#ifdef HAVE_SYS_IOCTL_H
491cb0ef41Sopenharmony_ci#  include <sys/ioctl.h>
501cb0ef41Sopenharmony_ci#endif
511cb0ef41Sopenharmony_ci#ifdef NETWARE
521cb0ef41Sopenharmony_ci#  include <sys/filio.h>
531cb0ef41Sopenharmony_ci#endif
541cb0ef41Sopenharmony_ci
551cb0ef41Sopenharmony_ci#include <assert.h>
561cb0ef41Sopenharmony_ci#include <fcntl.h>
571cb0ef41Sopenharmony_ci#include <limits.h>
581cb0ef41Sopenharmony_ci
591cb0ef41Sopenharmony_ci#include "ares.h"
601cb0ef41Sopenharmony_ci#include "ares_private.h"
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ciares_ssize_t ares__socket_recvfrom(ares_channel_t *channel, ares_socket_t s,
631cb0ef41Sopenharmony_ci                                   void *data, size_t data_len, int flags,
641cb0ef41Sopenharmony_ci                                   struct sockaddr *from,
651cb0ef41Sopenharmony_ci                                   ares_socklen_t  *from_len)
661cb0ef41Sopenharmony_ci{
671cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->arecvfrom) {
681cb0ef41Sopenharmony_ci    return channel->sock_funcs->arecvfrom(s, data, data_len, flags, from,
691cb0ef41Sopenharmony_ci                                          from_len, channel->sock_func_cb_data);
701cb0ef41Sopenharmony_ci  }
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci#ifdef HAVE_RECVFROM
731cb0ef41Sopenharmony_ci  return (ares_ssize_t)recvfrom(s, data, (RECVFROM_TYPE_ARG3)data_len, flags,
741cb0ef41Sopenharmony_ci                                from, from_len);
751cb0ef41Sopenharmony_ci#else
761cb0ef41Sopenharmony_ci  return sread(s, data, data_len);
771cb0ef41Sopenharmony_ci#endif
781cb0ef41Sopenharmony_ci}
791cb0ef41Sopenharmony_ci
801cb0ef41Sopenharmony_ciares_ssize_t ares__socket_recv(ares_channel_t *channel, ares_socket_t s,
811cb0ef41Sopenharmony_ci                               void *data, size_t data_len)
821cb0ef41Sopenharmony_ci{
831cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->arecvfrom) {
841cb0ef41Sopenharmony_ci    return channel->sock_funcs->arecvfrom(s, data, data_len, 0, 0, 0,
851cb0ef41Sopenharmony_ci                                          channel->sock_func_cb_data);
861cb0ef41Sopenharmony_ci  }
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  /* sread() is a wrapper for read() or recv() depending on the system */
891cb0ef41Sopenharmony_ci  return sread(s, data, data_len);
901cb0ef41Sopenharmony_ci}
911cb0ef41Sopenharmony_ci
921cb0ef41Sopenharmony_ci/*
931cb0ef41Sopenharmony_ci * setsocknonblock sets the given socket to either blocking or non-blocking
941cb0ef41Sopenharmony_ci * mode based on the 'nonblock' boolean argument. This function is highly
951cb0ef41Sopenharmony_ci * portable.
961cb0ef41Sopenharmony_ci */
971cb0ef41Sopenharmony_cistatic int setsocknonblock(ares_socket_t sockfd, /* operate on this */
981cb0ef41Sopenharmony_ci                           int           nonblock /* TRUE or FALSE */)
991cb0ef41Sopenharmony_ci{
1001cb0ef41Sopenharmony_ci#if defined(USE_BLOCKING_SOCKETS)
1011cb0ef41Sopenharmony_ci
1021cb0ef41Sopenharmony_ci  return 0; /* returns success */
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci#elif defined(HAVE_FCNTL_O_NONBLOCK)
1051cb0ef41Sopenharmony_ci
1061cb0ef41Sopenharmony_ci  /* most recent unix versions */
1071cb0ef41Sopenharmony_ci  int flags;
1081cb0ef41Sopenharmony_ci  flags = fcntl(sockfd, F_GETFL, 0);
1091cb0ef41Sopenharmony_ci  if (nonblock) {
1101cb0ef41Sopenharmony_ci    return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
1111cb0ef41Sopenharmony_ci  } else {
1121cb0ef41Sopenharmony_ci    return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); /* LCOV_EXCL_LINE */
1131cb0ef41Sopenharmony_ci  }
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ci#elif defined(HAVE_IOCTL_FIONBIO)
1161cb0ef41Sopenharmony_ci
1171cb0ef41Sopenharmony_ci  /* older unix versions */
1181cb0ef41Sopenharmony_ci  int flags = nonblock ? 1 : 0;
1191cb0ef41Sopenharmony_ci  return ioctl(sockfd, FIONBIO, &flags);
1201cb0ef41Sopenharmony_ci
1211cb0ef41Sopenharmony_ci#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci#  ifdef WATT32
1241cb0ef41Sopenharmony_ci  char flags = nonblock ? 1 : 0;
1251cb0ef41Sopenharmony_ci#  else
1261cb0ef41Sopenharmony_ci  /* Windows */
1271cb0ef41Sopenharmony_ci  unsigned long flags = nonblock ? 1UL : 0UL;
1281cb0ef41Sopenharmony_ci#  endif
1291cb0ef41Sopenharmony_ci  return ioctlsocket(sockfd, (long)FIONBIO, &flags);
1301cb0ef41Sopenharmony_ci
1311cb0ef41Sopenharmony_ci#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
1321cb0ef41Sopenharmony_ci
1331cb0ef41Sopenharmony_ci  /* Amiga */
1341cb0ef41Sopenharmony_ci  long flags = nonblock ? 1L : 0L;
1351cb0ef41Sopenharmony_ci  return IoctlSocket(sockfd, FIONBIO, flags);
1361cb0ef41Sopenharmony_ci
1371cb0ef41Sopenharmony_ci#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
1381cb0ef41Sopenharmony_ci
1391cb0ef41Sopenharmony_ci  /* BeOS */
1401cb0ef41Sopenharmony_ci  long b = nonblock ? 1L : 0L;
1411cb0ef41Sopenharmony_ci  return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
1421cb0ef41Sopenharmony_ci
1431cb0ef41Sopenharmony_ci#else
1441cb0ef41Sopenharmony_ci#  error "no non-blocking method was found/used/set"
1451cb0ef41Sopenharmony_ci#endif
1461cb0ef41Sopenharmony_ci}
1471cb0ef41Sopenharmony_ci
1481cb0ef41Sopenharmony_ci#if defined(IPV6_V6ONLY) && defined(WIN32)
1491cb0ef41Sopenharmony_ci/* It makes support for IPv4-mapped IPv6 addresses.
1501cb0ef41Sopenharmony_ci * Linux kernel, NetBSD, FreeBSD and Darwin: default is off;
1511cb0ef41Sopenharmony_ci * Windows Vista and later: default is on;
1521cb0ef41Sopenharmony_ci * DragonFly BSD: acts like off, and dummy setting;
1531cb0ef41Sopenharmony_ci * OpenBSD and earlier Windows: unsupported.
1541cb0ef41Sopenharmony_ci * Linux: controlled by /proc/sys/net/ipv6/bindv6only.
1551cb0ef41Sopenharmony_ci */
1561cb0ef41Sopenharmony_cistatic void set_ipv6_v6only(ares_socket_t sockfd, int on)
1571cb0ef41Sopenharmony_ci{
1581cb0ef41Sopenharmony_ci  (void)setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (void *)&on, sizeof(on));
1591cb0ef41Sopenharmony_ci}
1601cb0ef41Sopenharmony_ci#else
1611cb0ef41Sopenharmony_ci#  define set_ipv6_v6only(s, v)
1621cb0ef41Sopenharmony_ci#endif
1631cb0ef41Sopenharmony_ci
1641cb0ef41Sopenharmony_cistatic int configure_socket(ares_socket_t s, struct server_state *server)
1651cb0ef41Sopenharmony_ci{
1661cb0ef41Sopenharmony_ci  union {
1671cb0ef41Sopenharmony_ci    struct sockaddr     sa;
1681cb0ef41Sopenharmony_ci    struct sockaddr_in  sa4;
1691cb0ef41Sopenharmony_ci    struct sockaddr_in6 sa6;
1701cb0ef41Sopenharmony_ci  } local;
1711cb0ef41Sopenharmony_ci
1721cb0ef41Sopenharmony_ci  ares_socklen_t  bindlen = 0;
1731cb0ef41Sopenharmony_ci  ares_channel_t *channel = server->channel;
1741cb0ef41Sopenharmony_ci
1751cb0ef41Sopenharmony_ci  /* do not set options for user-managed sockets */
1761cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->asocket) {
1771cb0ef41Sopenharmony_ci    return 0;
1781cb0ef41Sopenharmony_ci  }
1791cb0ef41Sopenharmony_ci
1801cb0ef41Sopenharmony_ci  (void)setsocknonblock(s, 1);
1811cb0ef41Sopenharmony_ci
1821cb0ef41Sopenharmony_ci#if defined(FD_CLOEXEC) && !defined(MSDOS)
1831cb0ef41Sopenharmony_ci  /* Configure the socket fd as close-on-exec. */
1841cb0ef41Sopenharmony_ci  if (fcntl(s, F_SETFD, FD_CLOEXEC) == -1) {
1851cb0ef41Sopenharmony_ci    return -1; /* LCOV_EXCL_LINE */
1861cb0ef41Sopenharmony_ci  }
1871cb0ef41Sopenharmony_ci#endif
1881cb0ef41Sopenharmony_ci
1891cb0ef41Sopenharmony_ci  /* Set the socket's send and receive buffer sizes. */
1901cb0ef41Sopenharmony_ci  if ((channel->socket_send_buffer_size > 0) &&
1911cb0ef41Sopenharmony_ci      setsockopt(s, SOL_SOCKET, SO_SNDBUF,
1921cb0ef41Sopenharmony_ci                 (void *)&channel->socket_send_buffer_size,
1931cb0ef41Sopenharmony_ci                 sizeof(channel->socket_send_buffer_size)) == -1) {
1941cb0ef41Sopenharmony_ci    return -1;
1951cb0ef41Sopenharmony_ci  }
1961cb0ef41Sopenharmony_ci
1971cb0ef41Sopenharmony_ci  if ((channel->socket_receive_buffer_size > 0) &&
1981cb0ef41Sopenharmony_ci      setsockopt(s, SOL_SOCKET, SO_RCVBUF,
1991cb0ef41Sopenharmony_ci                 (void *)&channel->socket_receive_buffer_size,
2001cb0ef41Sopenharmony_ci                 sizeof(channel->socket_receive_buffer_size)) == -1) {
2011cb0ef41Sopenharmony_ci    return -1;
2021cb0ef41Sopenharmony_ci  }
2031cb0ef41Sopenharmony_ci
2041cb0ef41Sopenharmony_ci#ifdef SO_BINDTODEVICE
2051cb0ef41Sopenharmony_ci  if (channel->local_dev_name[0] &&
2061cb0ef41Sopenharmony_ci      setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, channel->local_dev_name,
2071cb0ef41Sopenharmony_ci                 sizeof(channel->local_dev_name))) {
2081cb0ef41Sopenharmony_ci    /* Only root can do this, and usually not fatal if it doesn't work, so */
2091cb0ef41Sopenharmony_ci    /* just continue on. */
2101cb0ef41Sopenharmony_ci  }
2111cb0ef41Sopenharmony_ci#endif
2121cb0ef41Sopenharmony_ci
2131cb0ef41Sopenharmony_ci  if (server->addr.family == AF_INET && channel->local_ip4) {
2141cb0ef41Sopenharmony_ci    memset(&local.sa4, 0, sizeof(local.sa4));
2151cb0ef41Sopenharmony_ci    local.sa4.sin_family      = AF_INET;
2161cb0ef41Sopenharmony_ci    local.sa4.sin_addr.s_addr = htonl(channel->local_ip4);
2171cb0ef41Sopenharmony_ci    bindlen                   = sizeof(local.sa4);
2181cb0ef41Sopenharmony_ci  } else if (server->addr.family == AF_INET6 && server->ll_scope == 0 &&
2191cb0ef41Sopenharmony_ci             memcmp(channel->local_ip6, ares_in6addr_any._S6_un._S6_u8,
2201cb0ef41Sopenharmony_ci                    sizeof(channel->local_ip6)) != 0) {
2211cb0ef41Sopenharmony_ci    /* Only if not link-local and an ip other than "::" is specified */
2221cb0ef41Sopenharmony_ci    memset(&local.sa6, 0, sizeof(local.sa6));
2231cb0ef41Sopenharmony_ci    local.sa6.sin6_family = AF_INET6;
2241cb0ef41Sopenharmony_ci    memcpy(&local.sa6.sin6_addr, channel->local_ip6,
2251cb0ef41Sopenharmony_ci           sizeof(channel->local_ip6));
2261cb0ef41Sopenharmony_ci    bindlen = sizeof(local.sa6);
2271cb0ef41Sopenharmony_ci  }
2281cb0ef41Sopenharmony_ci
2291cb0ef41Sopenharmony_ci  if (bindlen && bind(s, &local.sa, bindlen) < 0) {
2301cb0ef41Sopenharmony_ci    return -1;
2311cb0ef41Sopenharmony_ci  }
2321cb0ef41Sopenharmony_ci
2331cb0ef41Sopenharmony_ci  if (server->addr.family == AF_INET6) {
2341cb0ef41Sopenharmony_ci    set_ipv6_v6only(s, 0);
2351cb0ef41Sopenharmony_ci  }
2361cb0ef41Sopenharmony_ci
2371cb0ef41Sopenharmony_ci  return 0;
2381cb0ef41Sopenharmony_ci}
2391cb0ef41Sopenharmony_ci
2401cb0ef41Sopenharmony_ciares_status_t ares__open_connection(ares_channel_t      *channel,
2411cb0ef41Sopenharmony_ci                                    struct server_state *server,
2421cb0ef41Sopenharmony_ci                                    ares_bool_t          is_tcp)
2431cb0ef41Sopenharmony_ci{
2441cb0ef41Sopenharmony_ci  ares_socket_t  s;
2451cb0ef41Sopenharmony_ci  int            opt;
2461cb0ef41Sopenharmony_ci  ares_socklen_t salen;
2471cb0ef41Sopenharmony_ci
2481cb0ef41Sopenharmony_ci  union {
2491cb0ef41Sopenharmony_ci    struct sockaddr_in  sa4;
2501cb0ef41Sopenharmony_ci    struct sockaddr_in6 sa6;
2511cb0ef41Sopenharmony_ci  } saddr;
2521cb0ef41Sopenharmony_ci  struct sockaddr          *sa;
2531cb0ef41Sopenharmony_ci  struct server_connection *conn;
2541cb0ef41Sopenharmony_ci  ares__llist_node_t       *node;
2551cb0ef41Sopenharmony_ci  int                       type = is_tcp ? SOCK_STREAM : SOCK_DGRAM;
2561cb0ef41Sopenharmony_ci#ifdef __OpenBSD__
2571cb0ef41Sopenharmony_ci  if ((is_tcp && server->tcp_port == 53) ||
2581cb0ef41Sopenharmony_ci      (!is_tcp && server->udp_port == 53)) {
2591cb0ef41Sopenharmony_ci    type |= SOCK_DNS;
2601cb0ef41Sopenharmony_ci  }
2611cb0ef41Sopenharmony_ci#endif
2621cb0ef41Sopenharmony_ci
2631cb0ef41Sopenharmony_ci  switch (server->addr.family) {
2641cb0ef41Sopenharmony_ci    case AF_INET:
2651cb0ef41Sopenharmony_ci      sa    = (void *)&saddr.sa4;
2661cb0ef41Sopenharmony_ci      salen = sizeof(saddr.sa4);
2671cb0ef41Sopenharmony_ci      memset(sa, 0, (size_t)salen);
2681cb0ef41Sopenharmony_ci      saddr.sa4.sin_family = AF_INET;
2691cb0ef41Sopenharmony_ci      saddr.sa4.sin_port = htons(is_tcp ? server->tcp_port : server->udp_port);
2701cb0ef41Sopenharmony_ci      memcpy(&saddr.sa4.sin_addr, &server->addr.addr.addr4,
2711cb0ef41Sopenharmony_ci             sizeof(saddr.sa4.sin_addr));
2721cb0ef41Sopenharmony_ci      break;
2731cb0ef41Sopenharmony_ci    case AF_INET6:
2741cb0ef41Sopenharmony_ci      sa    = (void *)&saddr.sa6;
2751cb0ef41Sopenharmony_ci      salen = sizeof(saddr.sa6);
2761cb0ef41Sopenharmony_ci      memset(sa, 0, (size_t)salen);
2771cb0ef41Sopenharmony_ci      saddr.sa6.sin6_family = AF_INET6;
2781cb0ef41Sopenharmony_ci      saddr.sa6.sin6_port = htons(is_tcp ? server->tcp_port : server->udp_port);
2791cb0ef41Sopenharmony_ci      memcpy(&saddr.sa6.sin6_addr, &server->addr.addr.addr6,
2801cb0ef41Sopenharmony_ci             sizeof(saddr.sa6.sin6_addr));
2811cb0ef41Sopenharmony_ci#ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_SCOPE_ID
2821cb0ef41Sopenharmony_ci      saddr.sa6.sin6_scope_id = server->ll_scope;
2831cb0ef41Sopenharmony_ci#endif
2841cb0ef41Sopenharmony_ci      break;
2851cb0ef41Sopenharmony_ci    default:
2861cb0ef41Sopenharmony_ci      return ARES_EBADFAMILY; /* LCOV_EXCL_LINE */
2871cb0ef41Sopenharmony_ci  }
2881cb0ef41Sopenharmony_ci
2891cb0ef41Sopenharmony_ci  /* Acquire a socket. */
2901cb0ef41Sopenharmony_ci  s = ares__open_socket(channel, server->addr.family, type, 0);
2911cb0ef41Sopenharmony_ci  if (s == ARES_SOCKET_BAD) {
2921cb0ef41Sopenharmony_ci    return ARES_ECONNREFUSED;
2931cb0ef41Sopenharmony_ci  }
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci  /* Configure it. */
2961cb0ef41Sopenharmony_ci  if (configure_socket(s, server) < 0) {
2971cb0ef41Sopenharmony_ci    ares__close_socket(channel, s);
2981cb0ef41Sopenharmony_ci    return ARES_ECONNREFUSED;
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci#ifdef TCP_NODELAY
3021cb0ef41Sopenharmony_ci  if (is_tcp) {
3031cb0ef41Sopenharmony_ci    /*
3041cb0ef41Sopenharmony_ci     * Disable the Nagle algorithm (only relevant for TCP sockets, and thus not
3051cb0ef41Sopenharmony_ci     * in configure_socket). In general, in DNS lookups we're pretty much
3061cb0ef41Sopenharmony_ci     * interested in firing off a single request and then waiting for a reply,
3071cb0ef41Sopenharmony_ci     * so batching isn't very interesting.
3081cb0ef41Sopenharmony_ci     */
3091cb0ef41Sopenharmony_ci    opt = 1;
3101cb0ef41Sopenharmony_ci    if ((!channel->sock_funcs || !channel->sock_funcs->asocket) &&
3111cb0ef41Sopenharmony_ci        setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *)&opt, sizeof(opt)) ==
3121cb0ef41Sopenharmony_ci          -1) {
3131cb0ef41Sopenharmony_ci      ares__close_socket(channel, s);
3141cb0ef41Sopenharmony_ci      return ARES_ECONNREFUSED;
3151cb0ef41Sopenharmony_ci    }
3161cb0ef41Sopenharmony_ci  }
3171cb0ef41Sopenharmony_ci#endif
3181cb0ef41Sopenharmony_ci
3191cb0ef41Sopenharmony_ci  if (channel->sock_config_cb) {
3201cb0ef41Sopenharmony_ci    int err = channel->sock_config_cb(s, type, channel->sock_config_cb_data);
3211cb0ef41Sopenharmony_ci    if (err < 0) {
3221cb0ef41Sopenharmony_ci      ares__close_socket(channel, s);
3231cb0ef41Sopenharmony_ci      return ARES_ECONNREFUSED;
3241cb0ef41Sopenharmony_ci    }
3251cb0ef41Sopenharmony_ci  }
3261cb0ef41Sopenharmony_ci
3271cb0ef41Sopenharmony_ci  /* Connect to the server. */
3281cb0ef41Sopenharmony_ci  if (ares__connect_socket(channel, s, sa, salen) == -1) {
3291cb0ef41Sopenharmony_ci    int err = SOCKERRNO;
3301cb0ef41Sopenharmony_ci
3311cb0ef41Sopenharmony_ci    if (err != EINPROGRESS && err != EWOULDBLOCK) {
3321cb0ef41Sopenharmony_ci      ares__close_socket(channel, s);
3331cb0ef41Sopenharmony_ci      return ARES_ECONNREFUSED;
3341cb0ef41Sopenharmony_ci    }
3351cb0ef41Sopenharmony_ci  }
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci  if (channel->sock_create_cb) {
3381cb0ef41Sopenharmony_ci    int err = channel->sock_create_cb(s, type, channel->sock_create_cb_data);
3391cb0ef41Sopenharmony_ci    if (err < 0) {
3401cb0ef41Sopenharmony_ci      ares__close_socket(channel, s);
3411cb0ef41Sopenharmony_ci      return ARES_ECONNREFUSED;
3421cb0ef41Sopenharmony_ci    }
3431cb0ef41Sopenharmony_ci  }
3441cb0ef41Sopenharmony_ci
3451cb0ef41Sopenharmony_ci  conn = ares_malloc(sizeof(*conn));
3461cb0ef41Sopenharmony_ci  if (conn == NULL) {
3471cb0ef41Sopenharmony_ci    ares__close_socket(channel, s);
3481cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3491cb0ef41Sopenharmony_ci  }
3501cb0ef41Sopenharmony_ci  memset(conn, 0, sizeof(*conn));
3511cb0ef41Sopenharmony_ci  conn->fd              = s;
3521cb0ef41Sopenharmony_ci  conn->server          = server;
3531cb0ef41Sopenharmony_ci  conn->queries_to_conn = ares__llist_create(NULL);
3541cb0ef41Sopenharmony_ci  conn->is_tcp          = is_tcp;
3551cb0ef41Sopenharmony_ci  if (conn->queries_to_conn == NULL) {
3561cb0ef41Sopenharmony_ci    ares__close_socket(channel, s);
3571cb0ef41Sopenharmony_ci    ares_free(conn);
3581cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3591cb0ef41Sopenharmony_ci  }
3601cb0ef41Sopenharmony_ci
3611cb0ef41Sopenharmony_ci  /* TCP connections are thrown to the end as we don't spawn multiple TCP
3621cb0ef41Sopenharmony_ci   * connections. UDP connections are put on front where the newest connection
3631cb0ef41Sopenharmony_ci   * can be quickly pulled */
3641cb0ef41Sopenharmony_ci  if (is_tcp) {
3651cb0ef41Sopenharmony_ci    node = ares__llist_insert_last(server->connections, conn);
3661cb0ef41Sopenharmony_ci  } else {
3671cb0ef41Sopenharmony_ci    node = ares__llist_insert_first(server->connections, conn);
3681cb0ef41Sopenharmony_ci  }
3691cb0ef41Sopenharmony_ci  if (node == NULL) {
3701cb0ef41Sopenharmony_ci    ares__close_socket(channel, s);
3711cb0ef41Sopenharmony_ci    ares__llist_destroy(conn->queries_to_conn);
3721cb0ef41Sopenharmony_ci    ares_free(conn);
3731cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3741cb0ef41Sopenharmony_ci  }
3751cb0ef41Sopenharmony_ci
3761cb0ef41Sopenharmony_ci  /* Register globally to quickly map event on file descriptor to connection
3771cb0ef41Sopenharmony_ci   * node object */
3781cb0ef41Sopenharmony_ci  if (!ares__htable_asvp_insert(channel->connnode_by_socket, s, node)) {
3791cb0ef41Sopenharmony_ci    ares__close_socket(channel, s);
3801cb0ef41Sopenharmony_ci    ares__llist_destroy(conn->queries_to_conn);
3811cb0ef41Sopenharmony_ci    ares__llist_node_claim(node);
3821cb0ef41Sopenharmony_ci    ares_free(conn);
3831cb0ef41Sopenharmony_ci    return ARES_ENOMEM;
3841cb0ef41Sopenharmony_ci  }
3851cb0ef41Sopenharmony_ci
3861cb0ef41Sopenharmony_ci  SOCK_STATE_CALLBACK(channel, s, 1, 0);
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  if (is_tcp) {
3891cb0ef41Sopenharmony_ci    server->tcp_conn = conn;
3901cb0ef41Sopenharmony_ci  }
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci  return ARES_SUCCESS;
3931cb0ef41Sopenharmony_ci}
3941cb0ef41Sopenharmony_ci
3951cb0ef41Sopenharmony_ciares_socket_t ares__open_socket(ares_channel_t *channel, int af, int type,
3961cb0ef41Sopenharmony_ci                                int protocol)
3971cb0ef41Sopenharmony_ci{
3981cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->asocket) {
3991cb0ef41Sopenharmony_ci    return channel->sock_funcs->asocket(af, type, protocol,
4001cb0ef41Sopenharmony_ci                                        channel->sock_func_cb_data);
4011cb0ef41Sopenharmony_ci  }
4021cb0ef41Sopenharmony_ci
4031cb0ef41Sopenharmony_ci  return socket(af, type, protocol);
4041cb0ef41Sopenharmony_ci}
4051cb0ef41Sopenharmony_ci
4061cb0ef41Sopenharmony_ciint ares__connect_socket(ares_channel_t *channel, ares_socket_t sockfd,
4071cb0ef41Sopenharmony_ci                         const struct sockaddr *addr, ares_socklen_t addrlen)
4081cb0ef41Sopenharmony_ci{
4091cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->aconnect) {
4101cb0ef41Sopenharmony_ci    return channel->sock_funcs->aconnect(sockfd, addr, addrlen,
4111cb0ef41Sopenharmony_ci                                         channel->sock_func_cb_data);
4121cb0ef41Sopenharmony_ci  }
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  return connect(sockfd, addr, addrlen);
4151cb0ef41Sopenharmony_ci}
4161cb0ef41Sopenharmony_ci
4171cb0ef41Sopenharmony_civoid ares__close_socket(ares_channel_t *channel, ares_socket_t s)
4181cb0ef41Sopenharmony_ci{
4191cb0ef41Sopenharmony_ci  if (s == ARES_SOCKET_BAD) {
4201cb0ef41Sopenharmony_ci    return;
4211cb0ef41Sopenharmony_ci  }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->aclose) {
4241cb0ef41Sopenharmony_ci    channel->sock_funcs->aclose(s, channel->sock_func_cb_data);
4251cb0ef41Sopenharmony_ci  } else {
4261cb0ef41Sopenharmony_ci    sclose(s);
4271cb0ef41Sopenharmony_ci  }
4281cb0ef41Sopenharmony_ci}
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci#ifndef HAVE_WRITEV
4311cb0ef41Sopenharmony_ci/* Structure for scatter/gather I/O. */
4321cb0ef41Sopenharmony_cistruct iovec {
4331cb0ef41Sopenharmony_ci  void  *iov_base; /* Pointer to data. */
4341cb0ef41Sopenharmony_ci  size_t iov_len;  /* Length of data.  */
4351cb0ef41Sopenharmony_ci};
4361cb0ef41Sopenharmony_ci#endif
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ciares_ssize_t ares__socket_write(ares_channel_t *channel, ares_socket_t s,
4391cb0ef41Sopenharmony_ci                                const void *data, size_t len)
4401cb0ef41Sopenharmony_ci{
4411cb0ef41Sopenharmony_ci  if (channel->sock_funcs && channel->sock_funcs->asendv) {
4421cb0ef41Sopenharmony_ci    struct iovec vec;
4431cb0ef41Sopenharmony_ci    vec.iov_base = (void *)((size_t)data); /* Cast off const */
4441cb0ef41Sopenharmony_ci    vec.iov_len  = len;
4451cb0ef41Sopenharmony_ci    return channel->sock_funcs->asendv(s, &vec, 1, channel->sock_func_cb_data);
4461cb0ef41Sopenharmony_ci  }
4471cb0ef41Sopenharmony_ci  return swrite(s, data, len);
4481cb0ef41Sopenharmony_ci}
4491cb0ef41Sopenharmony_ci
4501cb0ef41Sopenharmony_civoid ares_set_socket_callback(ares_channel_t           *channel,
4511cb0ef41Sopenharmony_ci                              ares_sock_create_callback cb, void *data)
4521cb0ef41Sopenharmony_ci{
4531cb0ef41Sopenharmony_ci  if (channel == NULL) {
4541cb0ef41Sopenharmony_ci    return;
4551cb0ef41Sopenharmony_ci  }
4561cb0ef41Sopenharmony_ci  channel->sock_create_cb      = cb;
4571cb0ef41Sopenharmony_ci  channel->sock_create_cb_data = data;
4581cb0ef41Sopenharmony_ci}
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_civoid ares_set_socket_configure_callback(ares_channel_t           *channel,
4611cb0ef41Sopenharmony_ci                                        ares_sock_config_callback cb,
4621cb0ef41Sopenharmony_ci                                        void                     *data)
4631cb0ef41Sopenharmony_ci{
4641cb0ef41Sopenharmony_ci  if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
4651cb0ef41Sopenharmony_ci    return;
4661cb0ef41Sopenharmony_ci  }
4671cb0ef41Sopenharmony_ci  channel->sock_config_cb      = cb;
4681cb0ef41Sopenharmony_ci  channel->sock_config_cb_data = data;
4691cb0ef41Sopenharmony_ci}
4701cb0ef41Sopenharmony_ci
4711cb0ef41Sopenharmony_civoid ares_set_socket_functions(ares_channel_t                     *channel,
4721cb0ef41Sopenharmony_ci                               const struct ares_socket_functions *funcs,
4731cb0ef41Sopenharmony_ci                               void                               *data)
4741cb0ef41Sopenharmony_ci{
4751cb0ef41Sopenharmony_ci  if (channel == NULL || channel->optmask & ARES_OPT_EVENT_THREAD) {
4761cb0ef41Sopenharmony_ci    return;
4771cb0ef41Sopenharmony_ci  }
4781cb0ef41Sopenharmony_ci  channel->sock_funcs        = funcs;
4791cb0ef41Sopenharmony_ci  channel->sock_func_cb_data = data;
4801cb0ef41Sopenharmony_ci}
481