File node-cares-1.21-5.patch of Package nodejs-electron

From c44fa8d0b65d3550157c2fd4b0636fb269764f3e Mon Sep 17 00:00:00 2001
From: theanarkh <theratliter@gmail.com>
Date: Thu, 10 Jul 2025 23:50:43 +0800
Subject: [PATCH] dns: support max timeout

PR-URL: https://github.com/nodejs/node/pull/58440
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
---
 doc/api/dns.md                                |  2 +
 lib/internal/dns/utils.js                     | 20 +++--
 src/cares_wrap.cc                             | 30 +++++---
 src/cares_wrap.h                              | 11 +--
 .../parallel/test-dns-resolver-max-timeout.js | 77 +++++++++++++++++++
 5 files changed, 118 insertions(+), 22 deletions(-)
 create mode 100644 test/parallel/test-dns-resolver-max-timeout.js

diff --git a/lib/internal/dns/utils.js b/lib/internal/dns/utils.js
index 55f0b5268abf9d..d036c4c7255eab 100644
--- a/third_party/electron_node/lib/internal/dns/utils.js
+++ b/third_party/electron_node/lib/internal/dns/utils.js
@@ -25,6 +25,7 @@ const {
   validateInt32,
   validateOneOf,
   validateString,
+  validateUint32,
 } = require('internal/validators');
 let binding;
 function lazyBinding() {
@@ -49,6 +50,12 @@ function validateTimeout(options) {
   return timeout;
 }
 
+function validateMaxTimeout(options) {
+  const { maxTimeout = 0 } = { ...options };
+  validateUint32(maxTimeout, 'options.maxTimeout');
+  return maxTimeout;
+}
+
 function validateTries(options) {
   const { tries = 4 } = { ...options };
   validateInt32(tries, 'options.tries', 1);
@@ -67,17 +74,18 @@ class ResolverBase {
   constructor(options = undefined) {
     const timeout = validateTimeout(options);
     const tries = validateTries(options);
+    const maxTimeout = validateMaxTimeout(options);
     // If we are building snapshot, save the states of the resolver along
     // the way.
     if (isBuildingSnapshot()) {
-      this[kSnapshotStates] = { timeout, tries };
+      this[kSnapshotStates] = { timeout, tries, maxTimeout };
     }
-    this[kInitializeHandle](timeout, tries);
+    this[kInitializeHandle](timeout, tries, maxTimeout);
   }
 
-  [kInitializeHandle](timeout, tries) {
+  [kInitializeHandle](timeout, tries, maxTimeout) {
     const { ChannelWrap } = lazyBinding();
-    this._handle = new ChannelWrap(timeout, tries);
+    this._handle = new ChannelWrap(timeout, tries, maxTimeout);
   }
 
   cancel() {
@@ -187,8 +195,8 @@ class ResolverBase {
   }
 
   [kDeserializeResolver]() {
-    const { timeout, tries, localAddress, servers } = this[kSnapshotStates];
-    this[kInitializeHandle](timeout, tries);
+    const { timeout, tries, maxTimeout, localAddress, servers } = this[kSnapshotStates];
+    this[kInitializeHandle](timeout, tries, maxTimeout);
     if (localAddress) {
       const { ipv4, ipv6 } = localAddress;
       this._handle.setLocalAddress(ipv4, ipv6);
diff --git a/src/cares_wrap.cc b/src/cares_wrap.cc
index 7773314fa53bc1..e9516b03ec8960 100644
--- a/third_party/electron_node/src/cares_wrap.cc
+++ b/third_party/electron_node/src/cares_wrap.cc
@@ -787,14 +787,15 @@ Maybe<int> ParseSoaReply(Environment* env,
 }
 }  // anonymous namespace
 
-ChannelWrap::ChannelWrap(
-      Environment* env,
-      Local<Object> object,
-      int timeout,
-      int tries)
+ChannelWrap::ChannelWrap(Environment* env,
+                         Local<Object> object,
+                         int timeout,
+                         int tries,
+                         int max_timeout)
     : AsyncWrap(env, object, PROVIDER_DNSCHANNEL),
       timeout_(timeout),
-      tries_(tries) {
+      tries_(tries),
+      max_timeout_(max_timeout) {
   MakeWeak();
 
   Setup();
@@ -808,13 +809,15 @@ void ChannelWrap::MemoryInfo(MemoryTracker* tracker) const {
 
 void ChannelWrap::New(const FunctionCallbackInfo<Value>& args) {
   CHECK(args.IsConstructCall());
-  CHECK_EQ(args.Length(), 2);
+  CHECK_EQ(args.Length(), 3);
   CHECK(args[0]->IsInt32());
   CHECK(args[1]->IsInt32());
+  CHECK(args[2]->IsInt32());
   const int timeout = args[0].As<Int32>()->Value();
   const int tries = args[1].As<Int32>()->Value();
+  const int max_timeout = args[2].As<Int32>()->Value();
   Environment* env = Environment::GetCurrent(args);
-  new ChannelWrap(env, args.This(), timeout, tries);
+  new ChannelWrap(env, args.This(), timeout, tries, max_timeout);
 }
 
 GetAddrInfoReqWrap::GetAddrInfoReqWrap(Environment* env,
@@ -879,9 +882,14 @@ void ChannelWrap::Setup() {
   }
 
   /* We do the call to ares_init_option for caller. */
-  const int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS |
-                      ARES_OPT_SOCK_STATE_CB | ARES_OPT_TRIES |
-                      ARES_OPT_QUERY_CACHE;
+  int optmask = ARES_OPT_FLAGS | ARES_OPT_TIMEOUTMS | ARES_OPT_SOCK_STATE_CB |
+                ARES_OPT_TRIES | ARES_OPT_QUERY_CACHE;
+
+  if (max_timeout_ > 0) {
+    options.maxtimeout = max_timeout_;
+    optmask |= ARES_OPT_MAXTIMEOUTMS;
+  }
+
   r = ares_init_options(&channel_, &options, optmask);
 
   if (r != ARES_SUCCESS) {
diff --git a/src/cares_wrap.h b/src/cares_wrap.h
index 876ec745d4fcc5..fd66a67164b3d3 100644
--- a/third_party/electron_node/src/cares_wrap.h
+++ b/third_party/electron_node/src/cares_wrap.h
@@ -152,11 +152,11 @@ struct NodeAresTask final : public MemoryRetainer {
 
 class ChannelWrap final : public AsyncWrap {
  public:
-  ChannelWrap(
-      Environment* env,
-      v8::Local<v8::Object> object,
-      int timeout,
-      int tries);
+  ChannelWrap(Environment* env,
+              v8::Local<v8::Object> object,
+              int timeout,
+              int tries,
+              int max_timeout);
   ~ChannelWrap() override;
 
   static void New(const v8::FunctionCallbackInfo<v8::Value>& args);
@@ -191,6 +191,7 @@ class ChannelWrap final : public AsyncWrap {
   bool library_inited_ = false;
   int timeout_;
   int tries_;
+  int max_timeout_;
   int active_query_count_ = 0;
   NodeAresTask::List task_list_;
 };
openSUSE Build Service is sponsored by