]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Handle exceptions when dealing with asynchronous objects
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 18 May 2026 10:34:21 +0000 (12:34 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 18 May 2026 10:34:21 +0000 (12:34 +0200)
Signed-off-by: Remi Gacogne <remi.gacogne@powerdns.com>
pdns/dnsdistdist/dnsdist-async.cc

index 8bd0caa46e66bfc16bf2c67a5a3a0db3460f3554..0d0ba896e4417e43c74cdb4b333fb36f1eb8067b 100644 (file)
@@ -94,60 +94,70 @@ void AsynchronousHolder::mainThread(std::shared_ptr<Data> data)
   std::vector<int> readyFDs;
 
   while (true) {
-    bool shouldWait = true;
-    int timeout = -1;
-    dnsdist::configuration::refreshLocalRuntimeConfiguration();
-
-    {
-      auto content = data->d_content.lock();
-      if (data->d_done) {
-        return;
-      }
+    try {
+      bool shouldWait = true;
+      int timeout = -1;
+      dnsdist::configuration::refreshLocalRuntimeConfiguration();
 
-      if (!content->empty()) {
-        gettimeofday(&now, nullptr);
-        struct timeval next = getNextTTD(*content);
-        if (next <= now) {
-          pickupExpired(*content, now, expiredEvents);
-          shouldWait = false;
+      {
+        auto content = data->d_content.lock();
+        if (data->d_done) {
+          return;
         }
-        else {
-          auto remainingUsec = uSec(next - now);
-          timeout = static_cast<int>(std::round(static_cast<double>(remainingUsec) / 1000.0));
-          if (timeout == 0 && remainingUsec > 0) {
-            /* if we have less than 1 ms, let's wait at least 1 ms */
-            timeout = 1;
+
+        if (!content->empty()) {
+          gettimeofday(&now, nullptr);
+          struct timeval next = getNextTTD(*content);
+          if (next <= now) {
+            pickupExpired(*content, now, expiredEvents);
+            shouldWait = false;
+          }
+          else {
+            auto remainingUsec = uSec(next - now);
+            timeout = static_cast<int>(std::round(static_cast<double>(remainingUsec) / 1000.0));
+            if (timeout == 0 && remainingUsec > 0) {
+              /* if we have less than 1 ms, let's wait at least 1 ms */
+              timeout = 1;
+            }
           }
         }
       }
-    }
 
-    if (shouldWait) {
-      auto timedOut = wait(*data, *mplexer, readyFDs, timeout);
-      if (timedOut) {
-        auto content = data->d_content.lock();
-        gettimeofday(&now, nullptr);
-        pickupExpired(*content, now, expiredEvents);
+      if (shouldWait) {
+        auto timedOut = wait(*data, *mplexer, readyFDs, timeout);
+        if (timedOut) {
+          auto content = data->d_content.lock();
+          gettimeofday(&now, nullptr);
+          pickupExpired(*content, now, expiredEvents);
+        }
       }
-    }
 
-    while (!expiredEvents.empty()) {
-      auto [queryID, query] = std::move(expiredEvents.front());
-      expiredEvents.pop_front();
-      if (!data->d_failOpen) {
-        VERBOSESLOG(infolog("Asynchronous query %d has expired at %d.%d, notifying the sender", queryID, now.tv_sec, now.tv_usec),
-                    dnsdist::logging::getTopLogger("async-thread")->info(Logr::Info, "Asynchronous query has expired, notifying the sender", "dns.question.id", Logging::Loggable(queryID)));
-        auto sender = query->getTCPQuerySender();
-        if (sender) {
-          TCPResponse tresponse(std::move(query->query));
-          sender->notifyIOError(now, std::move(tresponse));
+      while (!expiredEvents.empty()) {
+        auto [queryID, query] = std::move(expiredEvents.front());
+        expiredEvents.pop_front();
+        if (!data->d_failOpen) {
+          VERBOSESLOG(infolog("Asynchronous query %d has expired at %d.%d, notifying the sender", queryID, now.tv_sec, now.tv_usec),
+                      dnsdist::logging::getTopLogger("async-thread")->info(Logr::Info, "Asynchronous query has expired, notifying the sender", "dns.question.id", Logging::Loggable(queryID)));
+          auto sender = query->getTCPQuerySender();
+          if (sender) {
+            TCPResponse tresponse(std::move(query->query));
+            sender->notifyIOError(now, std::move(tresponse));
+          }
+        }
+        else {
+          VERBOSESLOG(infolog("Asynchronous query %d has expired at %d.%d, resuming", queryID, now.tv_sec, now.tv_usec),
+                      dnsdist::logging::getTopLogger("async-thread")->info(Logr::Info, "Asynchronous query has expired, resuming", "dns.question.id", Logging::Loggable(queryID)));
+          resumeQuery(std::move(query));
         }
       }
-      else {
-        VERBOSESLOG(infolog("Asynchronous query %d has expired at %d.%d, resuming", queryID, now.tv_sec, now.tv_usec),
-                    dnsdist::logging::getTopLogger("async-thread")->info(Logr::Info, "Asynchronous query has expired, resuming", "dns.question.id", Logging::Loggable(queryID)));
-        resumeQuery(std::move(query));
-      }
+    }
+    catch (const std::exception& exp) {
+      VERBOSESLOG(infolog("Got exception in the main asynchronous handler thread: %s", exp.what()),
+                  dnsdist::logging::getTopLogger("async-thread")->error(Logr::Info, exp.what(), "Got exception in the main asynchronous handler thread"));
+    }
+    catch (...) {
+      VERBOSESLOG(infolog("Got exception in the main asynchronous handler thread"),
+                  dnsdist::logging::getTopLogger("async-thread")->info(Logr::Info, "Got exception in the main asynchronous handler thread"));
     }
   }
 }