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