]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
dnsdist: Better handling of spurious wake-ups, interrupted calls
authorRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 10 Jul 2023 15:49:51 +0000 (17:49 +0200)
committerRemi Gacogne <remi.gacogne@powerdns.com>
Mon, 17 Jul 2023 08:32:21 +0000 (10:32 +0200)
If we were woken up by the multiplexer but have actually nothing to read,
or the call to `recv()` is interrupted, we do not want to stop listening
for the health-check response event. It is also not useful to log about
it, even at "verbose health-check" level.
Note that we would have logged previously, so this kind of event would
not have gone unnoticed anyway.

pdns/dnsdistdist/dnsdist-healthchecks.cc

index 4df42302f3bc19c0fa79abde65c2d72df076abe5..e04ef5a56e341e2c8e081620e23d1c8131eb35e6 100644 (file)
@@ -169,22 +169,37 @@ private:
 static void healthCheckUDPCallback(int fd, FDMultiplexer::funcparam_t& param)
 {
   auto data = boost::any_cast<std::shared_ptr<HealthCheckData>>(param);
-  data->d_mplexer.removeReadFD(fd);
 
+  ssize_t got = 0;
   ComboAddress from;
-  from.sin4.sin_family = data->d_ds->d_config.remote.sin4.sin_family;
-  auto fromlen = from.getSocklen();
-  data->d_buffer.resize(512);
-  auto got = recvfrom(data->d_udpSocket.getHandle(), &data->d_buffer.at(0), data->d_buffer.size(), 0, reinterpret_cast<sockaddr *>(&from), &fromlen);
-  if (got < 0) {
-    int savederrno = errno;
-    if (g_verboseHealthChecks) {
-      infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
+  do {
+    from.sin4.sin_family = data->d_ds->d_config.remote.sin4.sin_family;
+    auto fromlen = from.getSocklen();
+    data->d_buffer.resize(512);
+
+    got = recvfrom(data->d_udpSocket.getHandle(), &data->d_buffer.at(0), data->d_buffer.size(), 0, reinterpret_cast<sockaddr *>(&from), &fromlen);
+    if (got < 0) {
+      int savederrno = errno;
+      if (savederrno == EINTR) {
+        /* interrupted, let's try again */
+        continue;
+      }
+      if (savederrno == EWOULDBLOCK || savederrno == EAGAIN) {
+        /* spurious wake-up, let's return to sleep */
+        return;
+      }
+
+      if (g_verboseHealthChecks) {
+        infolog("Error receiving health check response from %s: %s", data->d_ds->d_config.remote.toStringWithPort(), stringerror(savederrno));
+      }
+      ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
+      data->d_ds->submitHealthCheckResult(data->d_initial, false);
+      data->d_mplexer.removeReadFD(fd);
+      return;
     }
-    ++data->d_ds->d_healthCheckMetrics.d_networkErrors;
-    data->d_ds->submitHealthCheckResult(data->d_initial, false);
-    return;
   }
+  while (got < 0);
+
   data->d_buffer.resize(static_cast<size_t>(got));
 
   /* we are using a connected socket but hey.. */
@@ -197,6 +212,7 @@ static void healthCheckUDPCallback(int fd, FDMultiplexer::funcparam_t& param)
     return;
   }
 
+  data->d_mplexer.removeReadFD(fd);
   data->d_ds->submitHealthCheckResult(data->d_initial, handleResponse(data));
 }