deps: update c-ares to v1.32.3

PR-URL: https://github.com/nodejs/node/pull/54020
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Richard Lau <rlau@redhat.com>
This commit is contained in:
Node.js GitHub Bot 2024-07-26 10:26:53 -04:00 committed by GitHub
parent 449529df02
commit 9272f02b4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 293 additions and 259 deletions

View File

@ -12,7 +12,7 @@ INCLUDE (CheckCSourceCompiles)
INCLUDE (CheckStructHasMember)
INCLUDE (CheckLibraryExists)
PROJECT (c-ares LANGUAGES C VERSION "1.32.2" )
PROJECT (c-ares LANGUAGES C VERSION "1.32.3" )
# Set this version before release
SET (CARES_VERSION "${PROJECT_VERSION}")
@ -30,7 +30,7 @@ INCLUDE (GNUInstallDirs) # include this *AFTER* PROJECT(), otherwise paths are w
# For example, a version of 4:0:2 would generate output such as:
# libname.so -> libname.so.2
# libname.so.2 -> libname.so.2.2.0
SET (CARES_LIB_VERSIONINFO "19:2:17")
SET (CARES_LIB_VERSIONINFO "19:3:17")
OPTION (CARES_STATIC "Build as a static library" OFF)

View File

@ -1,3 +1,29 @@
## c-ares version 1.32.3 - July 24 2024
This is a bugfix release.
Changes:
* Prevent complex recursion during query requeuing and connection cleanup for
stability. [e8b32b8](https://github.com/c-ares/c-ares/commit/e8b32b8)
* Better propagate error codes on requeue situations.
[a9bc0a2](https://github.com/c-ares/c-ares/commit/a9bc0a2)
* Try to prevent SIGPIPE from being generated and delivered to integrations.
[de01baa](https://github.com/c-ares/c-ares/commit/de01baa)
Bugfixes:
* Missing manpage for `ares_dns_record_set_id()`
[aa462b3](https://github.com/c-ares/c-ares/commit/aa462b3)
* Memory leak in `ares__hosts_entry_to_hostent()` due to allocation strategy.
[PR #824](https://github.com/c-ares/c-ares/pull/824)
* UDP write failure detected via ICMP unreachable should trigger faster
failover. [PR #821](https://github.com/c-ares/c-ares/pull/821)
* Fix pycares test case regression due to wrong error code being returned.
Regression from 1.31.0. [PR #820](https://github.com/c-ares/c-ares/pull/820)
* Fix possible Windows crash during `ares_destroy()` when using event threads.
[5609bd4](https://github.com/c-ares/c-ares/commit/5609bd4)
* `ARES_OPT_MAXTIMEOUTMS` wasn't being honored in all cases.
[a649c60](https://github.com/c-ares/c-ares/commit/a649c60)
## c-ares version 1.32.2 - July 15 2024
This is a bugfix release.

View File

@ -1,6 +1,6 @@
# aminclude_static.am generated automatically by Autoconf
# from AX_AM_MACROS_STATIC on Mon Jul 15 09:00:09 EDT 2024
# from AX_AM_MACROS_STATIC on Wed Jul 24 05:40:58 EDT 2024
# Code coverage

22
deps/cares/configure vendored
View File

@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.72 for c-ares 1.32.2.
# Generated by GNU Autoconf 2.72 for c-ares 1.32.3.
#
# Report bugs to <c-ares mailing list: http://lists.haxx.se/listinfo/c-ares>.
#
@ -614,8 +614,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='c-ares'
PACKAGE_TARNAME='c-ares'
PACKAGE_VERSION='1.32.2'
PACKAGE_STRING='c-ares 1.32.2'
PACKAGE_VERSION='1.32.3'
PACKAGE_STRING='c-ares 1.32.3'
PACKAGE_BUGREPORT='c-ares mailing list: http://lists.haxx.se/listinfo/c-ares'
PACKAGE_URL=''
@ -1415,7 +1415,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
'configure' configures c-ares 1.32.2 to adapt to many kinds of systems.
'configure' configures c-ares 1.32.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@ -1486,7 +1486,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of c-ares 1.32.2:";;
short | recursive ) echo "Configuration of c-ares 1.32.3:";;
esac
cat <<\_ACEOF
@ -1623,7 +1623,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
c-ares configure 1.32.2
c-ares configure 1.32.3
generated by GNU Autoconf 2.72
Copyright (C) 2023 Free Software Foundation, Inc.
@ -2267,7 +2267,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by c-ares $as_me 1.32.2, which was
It was created by c-ares $as_me 1.32.3, which was
generated by GNU Autoconf 2.72. Invocation command line was
$ $0$ac_configure_args_raw
@ -3259,7 +3259,7 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
CARES_VERSION_INFO="19:2:17"
CARES_VERSION_INFO="19:3:17"
@ -5999,7 +5999,7 @@ fi
# Define the identity of the package.
PACKAGE='c-ares'
VERSION='1.32.2'
VERSION='1.32.3'
printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@ -26339,7 +26339,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by c-ares $as_me 1.32.2, which was
This file was extended by c-ares $as_me 1.32.3, which was
generated by GNU Autoconf 2.72. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@ -26407,7 +26407,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
c-ares config.status 1.32.2
c-ares config.status 1.32.3
configured by $0, generated by GNU Autoconf 2.72,
with options \\"\$ac_cs_config\\"

View File

@ -2,10 +2,10 @@ dnl Copyright (C) The c-ares project and its contributors
dnl SPDX-License-Identifier: MIT
AC_PREREQ([2.69])
AC_INIT([c-ares], [1.32.2],
AC_INIT([c-ares], [1.32.3],
[c-ares mailing list: http://lists.haxx.se/listinfo/c-ares])
CARES_VERSION_INFO="19:2:17"
CARES_VERSION_INFO="19:3:17"
dnl This flag accepts an argument of the form current[:revision[:age]]. So,
dnl passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
dnl 1.

View File

@ -374,6 +374,7 @@ MANPAGES = ares_cancel.3 \
ares_dns_record_rr_del.3 \
ares_dns_record_rr_get.3 \
ares_dns_record_rr_get_const.3 \
ares_dns_record_set_id.3 \
ares_dns_rec_type_fromstr.3 \
ares_dns_rec_type_tostr.3 \
ares_dns_rec_type_t.3 \

View File

@ -36,6 +36,7 @@ MANPAGES = ares_cancel.3 \
ares_dns_record_rr_del.3 \
ares_dns_record_rr_get.3 \
ares_dns_record_rr_get_const.3 \
ares_dns_record_set_id.3 \
ares_dns_rec_type_fromstr.3 \
ares_dns_rec_type_tostr.3 \
ares_dns_rec_type_t.3 \

View File

@ -32,6 +32,9 @@ ares_dns_record_t *ares_dns_record_duplicate(const ares_dns_record_t *dnsrec);
unsigned short ares_dns_record_get_id(const ares_dns_record_t *dnsrec);
ares_bool_t ares_dns_record_set_id(ares_dns_record_t *dnsrec,
unsigned short id);
unsigned short ares_dns_record_get_flags(const ares_dns_record_t *dnsrec);
ares_dns_opcode_t ares_dns_record_get_opcode(const ares_dns_record_t *dnsrec);
@ -343,6 +346,14 @@ message id from the DNS record provided in the
.IR dnsrec
parameter.
The \fIares_dns_record_set_id(3)\fP function is used to set the DNS
message id in the
.IR id
parameter from the DNS record provided in the
.IR dnsrec
parameter. This id will be overwritten when passing the record to c-ares,
so mostly exists for external purposes.
The \fIares_dns_record_get_flags(3)\fP function is used to retrieve the DNS
message flags from the DNS record provided in the
.IR dnsrec
@ -428,12 +439,12 @@ is returned on out of memory,
.B ARES_EFORMERR
is returned on misuse.
\fIares_dns_record_get_id(3)\fP, \fIares_dns_record_get_flags(3)\fP,
\fIares_dns_record_get_opcode(3)\fP, \fIares_dns_record_get_rcode(3)\fP, and
\fIares_dns_record_query_cnt(3)\fP all returned their prescribed datatype
values and in general can't fail except for misuse cases, in which a 0 may
be returned, however 0 can also be a valid return value for most of these
functions.
\fIares_dns_record_get_id(3)\fP, \fIares_dns_record_set_id(3)\fP,
\fIares_dns_record_get_flags(3)\fP, \fIares_dns_record_get_opcode(3)\fP,
\fIares_dns_record_get_rcode(3)\fP, and \fIares_dns_record_query_cnt(3)\fP
all returned their prescribed datatype values and in general can't fail except
for misuse cases, in which a 0 may be returned, however 0 can also be a valid
return value for most of these functions.
.SH AVAILABILITY

View File

@ -0,0 +1,3 @@
.\" Copyright (C) 2023 The c-ares project and its contributors.
.\" SPDX-License-Identifier: MIT
.so man3/ares_dns_record.3

View File

@ -32,11 +32,11 @@
#define ARES_VERSION_MAJOR 1
#define ARES_VERSION_MINOR 32
#define ARES_VERSION_PATCH 2
#define ARES_VERSION_PATCH 3
#define ARES_VERSION \
((ARES_VERSION_MAJOR << 16) | (ARES_VERSION_MINOR << 8) | \
(ARES_VERSION_PATCH))
#define ARES_VERSION_STR "1.32.2"
#define ARES_VERSION_STR "1.32.3"
#define CARES_HAVE_ARES_LIBRARY_INIT 1
#define CARES_HAVE_ARES_LIBRARY_CLEANUP 1

View File

@ -15,7 +15,7 @@
@SET_MAKE@
# aminclude_static.am generated automatically by Autoconf
# from AX_AM_MACROS_STATIC on Mon Jul 15 09:00:09 EDT 2024
# from AX_AM_MACROS_STATIC on Wed Jul 24 05:40:58 EDT 2024
# Copyright (C) The c-ares project and its contributors
# SPDX-License-Identifier: MIT

View File

@ -28,7 +28,8 @@
#include "ares_private.h"
#include <assert.h>
static void ares__requeue_queries(struct server_connection *conn)
static void ares__requeue_queries(struct server_connection *conn,
ares_status_t requeue_status)
{
struct query *query;
ares_timeval_t now;
@ -36,11 +37,12 @@ static void ares__requeue_queries(struct server_connection *conn)
ares__tvnow(&now);
while ((query = ares__llist_first_val(conn->queries_to_conn)) != NULL) {
ares__requeue_query(query, &now);
ares__requeue_query(query, &now, requeue_status);
}
}
void ares__close_connection(struct server_connection *conn)
void ares__close_connection(struct server_connection *conn,
ares_status_t requeue_status)
{
struct server_state *server = conn->server;
ares_channel_t *channel = server->channel;
@ -58,7 +60,7 @@ void ares__close_connection(struct server_connection *conn)
}
/* Requeue queries to other connections */
ares__requeue_queries(conn);
ares__requeue_queries(conn, requeue_status);
ares__llist_destroy(conn->queries_to_conn);
@ -74,45 +76,63 @@ void ares__close_sockets(struct server_state *server)
while ((node = ares__llist_node_first(server->connections)) != NULL) {
struct server_connection *conn = ares__llist_node_val(node);
ares__close_connection(conn);
ares__close_connection(conn, ARES_SUCCESS);
}
}
void ares__check_cleanup_conn(const ares_channel_t *channel,
struct server_connection *conn)
void ares__check_cleanup_conns(const ares_channel_t *channel)
{
ares_bool_t do_cleanup = ARES_FALSE;
ares__slist_node_t *snode;
if (channel == NULL || conn == NULL) {
if (channel == NULL) {
return; /* LCOV_EXCL_LINE: DefensiveCoding */
}
if (ares__llist_len(conn->queries_to_conn)) {
return;
}
/* Iterate across each server */
for (snode = ares__slist_node_first(channel->servers); snode != NULL;
snode = ares__slist_node_next(snode)) {
/* If we are configured not to stay open, close it out */
if (!(channel->flags & ARES_FLAG_STAYOPEN)) {
do_cleanup = ARES_TRUE;
}
struct server_state *server = ares__slist_node_val(snode);
ares__llist_node_t *cnode;
/* If the associated server has failures, close it out. Resetting the
* connection (and specifically the source port number) can help resolve
* situations where packets are being dropped.
*/
if (conn->server->consec_failures > 0) {
do_cleanup = ARES_TRUE;
}
/* Iterate across each connection */
cnode = ares__llist_node_first(server->connections);
while (cnode != NULL) {
ares__llist_node_t *next = ares__llist_node_next(cnode);
struct server_connection *conn = ares__llist_node_val(cnode);
ares_bool_t do_cleanup = ARES_FALSE;
cnode = next;
/* If the udp connection hit its max queries, always close it */
if (!conn->is_tcp && channel->udp_max_queries > 0 &&
conn->total_queries >= channel->udp_max_queries) {
do_cleanup = ARES_TRUE;
}
/* Has connections, not eligible */
if (ares__llist_len(conn->queries_to_conn)) {
continue;
}
if (!do_cleanup) {
return;
}
/* If we are configured not to stay open, close it out */
if (!(channel->flags & ARES_FLAG_STAYOPEN)) {
do_cleanup = ARES_TRUE;
}
ares__close_connection(conn);
/* If the associated server has failures, close it out. Resetting the
* connection (and specifically the source port number) can help resolve
* situations where packets are being dropped.
*/
if (conn->server->consec_failures > 0) {
do_cleanup = ARES_TRUE;
}
/* If the udp connection hit its max queries, always close it */
if (!conn->is_tcp && channel->udp_max_queries > 0 &&
conn->total_queries >= channel->udp_max_queries) {
do_cleanup = ARES_TRUE;
}
if (!do_cleanup) {
continue;
}
/* Clean it up */
ares__close_connection(conn, ARES_SUCCESS);
}
}
}

View File

@ -767,126 +767,6 @@ ares_status_t ares__hosts_search_host(ares_channel_t *channel,
return ARES_SUCCESS;
}
ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry,
int family, struct hostent **hostent)
{
ares_status_t status;
size_t naliases;
ares__llist_node_t *node;
size_t idx;
*hostent = ares_malloc_zero(sizeof(**hostent));
if (*hostent == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
(*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)family;
/* Copy IP addresses that match the address family */
idx = 0;
for (node = ares__llist_node_first(entry->ips); node != NULL;
node = ares__llist_node_next(node)) {
struct ares_addr addr;
const void *ptr = NULL;
size_t ptr_len = 0;
const char *ipaddr = ares__llist_node_val(node);
char **temp = NULL;
memset(&addr, 0, sizeof(addr));
addr.family = family;
ptr = ares_dns_pton(ipaddr, &addr, &ptr_len);
if (ptr == NULL) {
continue;
}
/* If family == AF_UNSPEC, then we want to inherit this for future
* conversions as we can only support a single address class */
if (family == AF_UNSPEC) {
family = addr.family;
(*hostent)->h_addrtype = (HOSTENT_ADDRTYPE_TYPE)addr.family;
}
temp = ares_realloc_zero((*hostent)->h_addr_list,
(idx + 1) * sizeof(*(*hostent)->h_addr_list),
(idx + 2) * sizeof(*(*hostent)->h_addr_list));
if (temp == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
(*hostent)->h_addr_list = temp;
(*hostent)->h_addr_list[idx] = ares_malloc(ptr_len);
if ((*hostent)->h_addr_list[idx] == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
memcpy((*hostent)->h_addr_list[idx], ptr, ptr_len);
idx++;
(*hostent)->h_length = (HOSTENT_LENGTH_TYPE)ptr_len;
}
/* entry didn't match address class */
if (idx == 0) {
status = ARES_ENOTFOUND;
goto fail;
}
/* Copy main hostname */
(*hostent)->h_name = ares_strdup(ares__llist_first_val(entry->hosts));
if ((*hostent)->h_name == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
/* Copy aliases */
naliases = ares__llist_len(entry->hosts) - 1;
/* Cap at 100, some people use https://github.com/StevenBlack/hosts and we
* don't need 200k+ aliases */
if (naliases > 100) {
naliases = 100; /* LCOV_EXCL_LINE: DefensiveCoding */
}
(*hostent)->h_aliases =
ares_malloc_zero((naliases + 1) * sizeof(*(*hostent)->h_aliases));
if ((*hostent)->h_aliases == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
/* Copy all entries to the alias except the first */
idx = 0;
node = ares__llist_node_first(entry->hosts);
node = ares__llist_node_next(node);
while (node != NULL) {
(*hostent)->h_aliases[idx] = ares_strdup(ares__llist_node_val(node));
if ((*hostent)->h_aliases[idx] == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto fail; /* LCOV_EXCL_LINE: OutOfMemory */
}
idx++;
/* Break out if artificially capped */
if (idx == naliases) {
break;
}
node = ares__llist_node_next(node);
}
return ARES_SUCCESS;
/* LCOV_EXCL_START: defensive coding */
fail:
ares_free_hostent(*hostent);
*hostent = NULL;
return status;
/* LCOV_EXCL_STOP */
}
static ares_status_t
ares__hosts_ai_append_cnames(const ares_hosts_entry_t *entry,
struct ares_addrinfo_cname **cnames_out)
@ -980,10 +860,12 @@ ares_status_t ares__hosts_entry_to_addrinfo(const ares_hosts_entry_t *entry,
return ARES_EBADFAMILY; /* LCOV_EXCL_LINE: DefensiveCoding */
}
ai->name = ares_strdup(name);
if (ai->name == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto done; /* LCOV_EXCL_LINE: OutOfMemory */
if (name != NULL) {
ai->name = ares_strdup(name);
if (ai->name == NULL) {
status = ARES_ENOMEM; /* LCOV_EXCL_LINE: OutOfMemory */
goto done; /* LCOV_EXCL_LINE: OutOfMemory */
}
}
for (node = ares__llist_node_first(entry->ips); node != NULL;
@ -1031,3 +913,35 @@ done:
return status;
}
ares_status_t ares__hosts_entry_to_hostent(const ares_hosts_entry_t *entry,
int family, struct hostent **hostent)
{
ares_status_t status;
struct ares_addrinfo *ai = ares_malloc_zero(sizeof(*ai));
*hostent = NULL;
if (ai == NULL) {
return ARES_ENOMEM;
}
status = ares__hosts_entry_to_addrinfo(entry, NULL, family, 0, ARES_TRUE, ai);
if (status != ARES_SUCCESS) {
goto done;
}
status = ares__addrinfo2hostent(ai, family, hostent);
if (status != ARES_SUCCESS) {
goto done;
}
done:
ares_freeaddrinfo(ai);
if (status != ARES_SUCCESS) {
ares_free_hostent(*hostent);
*hostent = NULL;
}
return status;
}

View File

@ -184,6 +184,14 @@ static int configure_socket(ares_socket_t s, struct server_state *server)
}
#endif
/* No need to emit SIGPIPE on socket errors */
#if defined(SO_NOSIGPIPE)
{
int opt = 1;
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&opt, sizeof(opt));
}
#endif
/* Set the socket's send and receive buffer sizes. */
if ((channel->socket_send_buffer_size > 0) &&
setsockopt(s, SOL_SOCKET, SO_SNDBUF,

View File

@ -60,28 +60,26 @@ void ares_cancel(ares_channel_t *channel)
node = ares__llist_node_first(list_copy);
while (node != NULL) {
struct query *query;
struct server_connection *conn;
/* Cache next since this node is being deleted */
next = ares__llist_node_next(node);
query = ares__llist_node_claim(node);
conn = query->conn;
query->node_all_queries = NULL;
/* NOTE: its possible this may enqueue new queries */
query->callback(query->arg, ARES_ECANCELLED, 0, NULL);
ares__free_query(query);
/* See if the connection should be cleaned up */
ares__check_cleanup_conn(channel, conn);
node = next;
}
ares__llist_destroy(list_copy);
}
/* See if the connections should be cleaned up */
ares__check_cleanup_conns(channel);
ares_queue_notify_empty(channel);
done:

View File

@ -26,6 +26,8 @@
#ifndef __ARES_DNS_PRIVATE_H
#define __ARES_DNS_PRIVATE_H
ares_status_t ares_dns_record_duplicate_ex(ares_dns_record_t **dest,
const ares_dns_record_t *src);
ares_bool_t ares_dns_rec_type_allow_name_compression(ares_dns_rec_type_t type);
ares_bool_t ares_dns_opcode_isvalid(ares_dns_opcode_t opcode);
ares_bool_t ares_dns_rcode_isvalid(ares_dns_rcode_t rcode);

View File

@ -296,6 +296,7 @@ ares_status_t ares_dns_record_query_set_name(ares_dns_record_t *dnsrec,
if (dnsrec == NULL || idx >= dnsrec->qdcount || name == NULL) {
return ARES_EFORMERR;
}
orig_name = dnsrec->qd[idx].name;
dnsrec->qd[idx].name = ares_strdup(name);
if (dnsrec->qd[idx].name == NULL) {
@ -1622,26 +1623,34 @@ done:
return status;
}
ares_dns_record_t *ares_dns_record_duplicate(const ares_dns_record_t *dnsrec)
ares_status_t ares_dns_record_duplicate_ex(ares_dns_record_t **dest,
const ares_dns_record_t *src)
{
unsigned char *data = NULL;
size_t data_len = 0;
ares_dns_record_t *out = NULL;
ares_status_t status;
if (dnsrec == NULL) {
return NULL;
if (dest == NULL || src == NULL) {
return ARES_EFORMERR;
}
status = ares_dns_write(dnsrec, &data, &data_len);
*dest = NULL;
status = ares_dns_write(src, &data, &data_len);
if (status != ARES_SUCCESS) {
return NULL;
return status;
}
status = ares_dns_parse(data, data_len, 0, &out);
status = ares_dns_parse(data, data_len, 0, dest);
ares_free(data);
if (status != ARES_SUCCESS) {
return NULL;
}
return out;
return status;
}
ares_dns_record_t *ares_dns_record_duplicate(const ares_dns_record_t *dnsrec)
{
ares_dns_record_t *dest = NULL;
ares_dns_record_duplicate_ex(&dest, dnsrec);
return dest;
}

View File

@ -81,12 +81,14 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e,
size_t i;
fd_set read_fds;
fd_set write_fds;
fd_set except_fds;
int nfds = 0;
struct timeval tv;
struct timeval *tout = NULL;
FD_ZERO(&read_fds);
FD_ZERO(&write_fds);
FD_ZERO(&except_fds);
for (i = 0; i < num_fds; i++) {
const ares_event_t *ev =
@ -97,6 +99,7 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e,
if (ev->flags & ARES_EVENT_FLAG_WRITE) {
FD_SET(ev->fd, &write_fds);
}
FD_SET(ev->fd, &except_fds);
if (ev->fd + 1 > nfds) {
nfds = ev->fd + 1;
}
@ -108,7 +111,7 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e,
tout = &tv;
}
rv = select(nfds, &read_fds, &write_fds, NULL, tout);
rv = select(nfds, &read_fds, &write_fds, &except_fds, tout);
if (rv > 0) {
for (i = 0; i < num_fds; i++) {
ares_event_t *ev;
@ -119,7 +122,7 @@ static size_t ares_evsys_select_wait(ares_event_thread_t *e,
continue; /* LCOV_EXCL_LINE: DefensiveCoding */
}
if (FD_ISSET(fdlist[i], &read_fds)) {
if (FD_ISSET(fdlist[i], &read_fds) || FD_ISSET(fdlist[i], &except_fds)) {
flags |= ARES_EVENT_FLAG_READ;
}

View File

@ -337,7 +337,9 @@ typedef struct {
static void ares_afd_handle_destroy(void *arg)
{
ares_afd_handle_t *hnd = arg;
CloseHandle(hnd->afd_handle);
if (hnd != NULL && hnd->afd_handle != NULL) {
CloseHandle(hnd->afd_handle);
}
ares_free(hnd);
}
@ -791,7 +793,11 @@ static void ares_evsys_win32_event_mod(ares_event_t *event,
static ares_bool_t ares_evsys_win32_process_other_event(
ares_evsys_win32_t *ew, ares_evsys_win32_eventdata_t *ed, size_t i)
{
ares_event_t *event = ed->event;
ares_event_t *event;
/* NOTE: do NOT dereference 'ed' if during shutdown as this could be an
* invalid pointer if the signal handle was cleaned up, but there was still a
* pending event! */
if (ew->is_shutdown) {
CARES_DEBUG_LOG("\t\t** i=%lu, skip non-socket handle during shutdown\n",
@ -799,6 +805,7 @@ static ares_bool_t ares_evsys_win32_process_other_event(
return ARES_FALSE;
}
event = ed->event;
CARES_DEBUG_LOG("\t\t** i=%lu, ed=%p (data)\n", (unsigned long)i, (void *)ed);
event->cb(event->e, event->fd, event->data, ARES_EVENT_FLAG_OTHER);

View File

@ -211,7 +211,7 @@ size_t ares_metrics_server_timeout(const struct server_state *server,
const ares_channel_t *channel = server->channel;
ares_server_bucket_t i;
size_t timeout_ms = 0;
size_t max_timeout_ms;
for (i = 0; i < ARES_METRIC_COUNT; i++) {
time_t ts = ares_metric_timestamp(i, now, ARES_FALSE);
@ -252,10 +252,9 @@ size_t ares_metrics_server_timeout(const struct server_state *server,
}
/* don't go above upper bounds */
if (channel->maxtimeout && timeout_ms > channel->maxtimeout) {
timeout_ms = channel->maxtimeout;
} else if (timeout_ms > MAX_TIMEOUT_MS) {
timeout_ms = MAX_TIMEOUT_MS;
max_timeout_ms = channel->maxtimeout?channel->maxtimeout:MAX_TIMEOUT_MS;
if (timeout_ms > max_timeout_ms) {
timeout_ms = max_timeout_ms;
}
return timeout_ms;

View File

@ -410,7 +410,8 @@ ares_bool_t ares__timedout(const ares_timeval_t *now,
/* Returns one of the normal ares status codes like ARES_SUCCESS */
ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now);
ares_status_t ares__requeue_query(struct query *query,
const ares_timeval_t *now);
const ares_timeval_t *now,
ares_status_t status);
/*! Retrieve a list of names to use for searching. The first successful
* query in the list wins. This function also uses the HOSTSALIASES file
@ -438,10 +439,10 @@ void *ares__dnsrec_convert_arg(ares_callback callback, void *arg);
void ares__dnsrec_convert_cb(void *arg, ares_status_t status, size_t timeouts,
const ares_dns_record_t *dnsrec);
void ares__close_connection(struct server_connection *conn);
void ares__close_connection(struct server_connection *conn,
ares_status_t requeue_status);
void ares__close_sockets(struct server_state *server);
void ares__check_cleanup_conn(const ares_channel_t *channel,
struct server_connection *conn);
void ares__check_cleanup_conns(const ares_channel_t *channel);
void ares__free_query(struct query *query);
ares_rand_state *ares__init_rand_state(void);

View File

@ -58,7 +58,8 @@ static ares_status_t process_answer(ares_channel_t *channel,
struct server_connection *conn,
ares_bool_t tcp, const ares_timeval_t *now);
static void handle_conn_error(struct server_connection *conn,
ares_bool_t critical_failure);
ares_bool_t critical_failure,
ares_status_t failure_status);
static ares_bool_t same_questions(const struct query *query,
const ares_dns_record_t *arec);
@ -68,6 +69,17 @@ static void end_query(ares_channel_t *channel, struct server_state *server,
struct query *query, ares_status_t status,
const ares_dns_record_t *dnsrec);
static void ares__query_disassociate_from_conn(struct query *query)
{
/* If its not part of a connection, it can't be tracked for timeouts either */
ares__slist_node_destroy(query->node_queries_by_timeout);
ares__llist_node_destroy(query->node_queries_to_conn);
query->node_queries_by_timeout = NULL;
query->node_queries_to_conn = NULL;
query->conn = NULL;
}
/* Invoke the server state callback after a success or failure */
static void invoke_server_state_cb(const struct server_state *server,
ares_bool_t success, int flags)
@ -202,6 +214,8 @@ static void processfds(ares_channel_t *channel, fd_set *read_fds,
/* Write last as the other 2 operations might have triggered writes */
write_tcp_data(channel, write_fds, write_fd);
/* See if any connections should be cleaned up */
ares__check_cleanup_conns(channel);
ares__channel_unlock(channel);
}
@ -301,7 +315,7 @@ static void write_tcp_data(ares_channel_t *channel, fd_set *write_fds,
count = ares__socket_write(channel, server->tcp_conn->fd, data, data_len);
if (count <= 0) {
if (!try_again(SOCKERRNO)) {
handle_conn_error(server->tcp_conn, ARES_TRUE);
handle_conn_error(server->tcp_conn, ARES_TRUE, ARES_ECONNREFUSED);
}
continue;
}
@ -334,7 +348,7 @@ static void read_tcp_data(ares_channel_t *channel,
ptr = ares__buf_append_start(server->tcp_parser, &ptr_len);
if (ptr == NULL) {
handle_conn_error(conn, ARES_FALSE /* not critical to connection */);
handle_conn_error(conn, ARES_FALSE /* not critical to connection */, ARES_SUCCESS);
return; /* bail out on malloc failure. TODO: make this
function return error codes */
}
@ -344,7 +358,7 @@ static void read_tcp_data(ares_channel_t *channel,
if (count <= 0) {
ares__buf_append_finish(server->tcp_parser, 0);
if (!(count == -1 && try_again(SOCKERRNO))) {
handle_conn_error(conn, ARES_TRUE);
handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED);
}
return;
}
@ -388,15 +402,13 @@ static void read_tcp_data(ares_channel_t *channel,
/* We finished reading this answer; process it */
status = process_answer(channel, data, data_len, conn, ARES_TRUE, now);
if (status != ARES_SUCCESS) {
handle_conn_error(conn, ARES_TRUE);
handle_conn_error(conn, ARES_TRUE, status);
return;
}
/* Since we processed the answer, clear the tag so space can be reclaimed */
ares__buf_tag_clear(server->tcp_parser);
}
ares__check_cleanup_conn(channel, conn);
}
static int socket_list_append(ares_socket_t **socketlist, ares_socket_t fd,
@ -503,7 +515,7 @@ static void read_udp_packets_fd(ares_channel_t *channel,
break;
}
handle_conn_error(conn, ARES_TRUE);
handle_conn_error(conn, ARES_TRUE, ARES_ECONNREFUSED);
return;
#ifdef HAVE_RECVFROM
} else if (!same_address(&from.sa, &conn->server->addr)) {
@ -520,8 +532,6 @@ static void read_udp_packets_fd(ares_channel_t *channel,
/* Try to read again only if *we* set up the socket, otherwise it may be
* a blocking socket and would cause recvfrom to hang. */
} while (read_len >= 0 && channel->sock_funcs == NULL);
ares__check_cleanup_conn(channel, conn);
}
static void read_packets(ares_channel_t *channel, fd_set *read_fds,
@ -594,28 +604,26 @@ static void read_packets(ares_channel_t *channel, fd_set *read_fds,
/* If any queries have timed out, note the timeout and move them on. */
static void process_timeouts(ares_channel_t *channel, const ares_timeval_t *now)
{
ares__slist_node_t *node =
ares__slist_node_first(channel->queries_by_timeout);
while (node != NULL) {
ares__slist_node_t *node;
/* Just keep popping off the first as this list will re-sort as things come
* and go. We don't want to try to rely on 'next' as some operation might
* cause a cleanup of that pointer and would become invalid */
while ((node = ares__slist_node_first(channel->queries_by_timeout)) != NULL) {
struct query *query = ares__slist_node_val(node);
/* Node might be removed, cache next */
ares__slist_node_t *next = ares__slist_node_next(node);
struct server_connection *conn;
/* Since this is sorted, as soon as we hit a query that isn't timed out,
* break */
if (!ares__timedout(now, &query->timeout)) {
break;
}
query->error_status = ARES_ETIMEOUT;
query->timeouts++;
conn = query->conn;
server_increment_failures(conn->server, query->using_tcp);
ares__requeue_query(query, now);
ares__check_cleanup_conn(channel, conn);
node = next;
ares__requeue_query(query, now, ARES_ETIMEOUT);
}
}
@ -733,20 +741,20 @@ static ares_status_t process_answer(ares_channel_t *channel,
rcode == ARES_RCODE_REFUSED) {
switch (rcode) {
case ARES_RCODE_SERVFAIL:
query->error_status = ARES_ESERVFAIL;
status = ARES_ESERVFAIL;
break;
case ARES_RCODE_NOTIMP:
query->error_status = ARES_ENOTIMP;
status = ARES_ENOTIMP;
break;
case ARES_RCODE_REFUSED:
query->error_status = ARES_EREFUSED;
status = ARES_EREFUSED;
break;
default:
break;
}
server_increment_failures(server, query->using_tcp);
ares__requeue_query(query, now);
ares__requeue_query(query, now, status);
/* Should any of these cause a connection termination?
* Maybe SERVER_FAILURE? */
@ -776,7 +784,8 @@ cleanup:
}
static void handle_conn_error(struct server_connection *conn,
ares_bool_t critical_failure)
ares_bool_t critical_failure,
ares_status_t failure_status)
{
struct server_state *server = conn->server;
@ -787,17 +796,23 @@ static void handle_conn_error(struct server_connection *conn,
}
/* This will requeue any connections automatically */
ares__close_connection(conn);
ares__close_connection(conn, failure_status);
}
ares_status_t ares__requeue_query(struct query *query,
const ares_timeval_t *now)
const ares_timeval_t *now,
ares_status_t status)
{
ares_channel_t *channel = query->channel;
size_t max_tries = ares__slist_len(channel->servers) * channel->tries;
query->try_count++;
ares__query_disassociate_from_conn(query);
if (status != ARES_SUCCESS) {
query->error_status = status;
}
query->try_count++;
if (query->try_count < max_tries && !query->no_retries) {
return ares__send_query(query, now);
}
@ -947,7 +962,14 @@ static ares_status_t ares__write_udpbuf(ares_channel_t *channel,
}
if (ares__socket_write(channel, fd, qbuf, qbuf_len) == -1) {
status = ARES_ESERVFAIL;
if (try_again(SOCKERRNO)) {
status = ARES_ESERVFAIL;
} else {
/* UDP is connection-less, but we might receive an ICMP unreachable which
* means we can't talk to the remote host at all and that will be
* reflected here */
status = ARES_ECONNREFUSED;
}
} else {
status = ARES_SUCCESS;
}
@ -1018,8 +1040,6 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
ares_status_t status;
ares_bool_t new_connection = ARES_FALSE;
query->conn = NULL;
/* Choose the server to send the query to */
if (channel->rotate) {
/* Pull random server */
@ -1052,8 +1072,7 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
case ARES_ECONNREFUSED:
case ARES_EBADFAMILY:
server_increment_failures(server, query->using_tcp);
query->error_status = status;
return ares__requeue_query(query, now);
return ares__requeue_query(query, now, status);
/* Anything else is not retryable, likely ENOMEM */
default:
@ -1073,7 +1092,7 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
/* Only safe to kill connection if it was new, otherwise it should be
* cleaned up by another process later */
if (new_connection) {
ares__close_connection(conn);
ares__close_connection(conn, status);
}
return status;
}
@ -1111,8 +1130,7 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
case ARES_ECONNREFUSED:
case ARES_EBADFAMILY:
server_increment_failures(server, query->using_tcp);
query->error_status = status;
return ares__requeue_query(query, now);
return ares__requeue_query(query, now, status);
/* Anything else is not retryable, likely ENOMEM */
default:
@ -1132,14 +1150,27 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
return status;
}
/* FIXME: Handle EAGAIN here since it likely can happen. */
if (status == ARES_ECONNREFUSED) {
handle_conn_error(conn, ARES_TRUE, status);
/* This query wasn't yet bound to the connection, need to manually
* requeue it and return an appropriate error */
status = ares__requeue_query(query, now, status);
if (status == ARES_ETIMEOUT) {
status = ARES_ECONNREFUSED;
}
return status;
}
/* FIXME: Handle EAGAIN here since it likely can happen. Right now we
* just requeue to a different server/connection. */
server_increment_failures(server, query->using_tcp);
status = ares__requeue_query(query, now);
status = ares__requeue_query(query, now, status);
/* Only safe to kill connection if it was new, otherwise it should be
* cleaned up by another process later */
if (new_connection) {
ares__close_connection(conn);
ares__close_connection(conn, status);
}
return status;
@ -1162,7 +1193,7 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
/* Only safe to kill connection if it was new, otherwise it should be
* cleaned up by another process later */
if (new_connection) {
ares__close_connection(conn);
ares__close_connection(conn, ARES_SUCCESS);
}
return ARES_ENOMEM;
/* LCOV_EXCL_STOP */
@ -1180,7 +1211,7 @@ ares_status_t ares__send_query(struct query *query, const ares_timeval_t *now)
/* Only safe to kill connection if it was new, otherwise it should be
* cleaned up by another process later */
if (new_connection) {
ares__close_connection(conn);
ares__close_connection(conn, ARES_SUCCESS);
}
return ARES_ENOMEM;
/* LCOV_EXCL_STOP */
@ -1283,12 +1314,9 @@ static ares_bool_t same_address(const struct sockaddr *sa,
static void ares_detach_query(struct query *query)
{
/* Remove the query from all the lists in which it is linked */
ares__query_disassociate_from_conn(query);
ares__htable_szvp_remove(query->channel->queries_by_qid, query->qid);
ares__slist_node_destroy(query->node_queries_by_timeout);
ares__llist_node_destroy(query->node_queries_to_conn);
ares__llist_node_destroy(query->node_all_queries);
query->node_queries_by_timeout = NULL;
query->node_queries_to_conn = NULL;
query->node_all_queries = NULL;
}

View File

@ -145,11 +145,11 @@ ares_status_t ares_send_nolock(ares_channel_t *channel,
query->using_tcp = (channel->flags & ARES_FLAG_USEVC)?ARES_TRUE:ARES_FALSE;
/* Duplicate Query */
query->query = ares_dns_record_duplicate(dnsrec);
if (query->query == NULL) {
status = ares_dns_record_duplicate_ex(&query->query, dnsrec);
if (status != ARES_SUCCESS) {
ares_free(query);
callback(arg, ARES_ENOMEM, 0, NULL);
return ARES_ENOMEM;
callback(arg, status, 0, NULL);
return status;
}
ares_dns_record_set_id(query->query, id);

View File

@ -32,6 +32,9 @@ IF (CARES_BUILD_TOOLS)
# Build adig
ADD_EXECUTABLE (adig adig.c ${SAMPLESOURCES})
# Don't build adig and ahost in parallel. This is to prevent a Windows MSVC
# build error due to them both using the same source files.
ADD_DEPENDENCIES(adig ahost)
TARGET_INCLUDE_DIRECTORIES (adig
PUBLIC "$<BUILD_INTERFACE:${PROJECT_BINARY_DIR}>"
"$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}>"