]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add a poor man's "std:expected" and use it in sendMsgwithOptions
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Tue, 7 Jul 2026 09:11:55 +0000 (11:11 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Wed, 8 Jul 2026 09:24:28 +0000 (11:24 +0200)
Signed-off-by: Otto Moerbeek <otto.moerbeek@open-xchange.com>
pdns/auth-primarycommunicator.cc
pdns/auth-secondarycommunicator.cc
pdns/dnsdistdist/dnsdist-udp.cc
pdns/dnsdistdist/doq-common.cc
pdns/iputils.cc
pdns/iputils.hh
pdns/ixfrdist.cc
pdns/recursordist/pdns_recursor.cc
pdns/rfc2136handler.cc
pdns/tcpiohandler.hh
pdns/test-iputils_hh.cc

index 3de7cad7acb8d0911e569277a2b899f206711872..9335de53ee35ce08fd88ff5f7c47843c21e8a3bf 100644 (file)
@@ -389,13 +389,13 @@ bool CommunicatorClass::justNotified(const ZoneName& domain, const string& ipAdd
 void CommunicatorClass::makeNotifySockets()
 {
   if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET)) {
-    d_nsock4 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0), true, ::arg().mustDo("non-local-bind"));
+    d_nsock4 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0).d_address, true, ::arg().mustDo("non-local-bind"));
   }
   else {
     d_nsock4 = -1;
   }
   if (pdns::isQueryLocalAddressFamilyEnabled(AF_INET6)) {
-    d_nsock6 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0), true, ::arg().mustDo("non-local-bind"));
+    d_nsock6 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0).d_address, true, ::arg().mustDo("non-local-bind"));
   }
   else {
     d_nsock6 = -1;
index 726134a4eb1f597af8aa6521cdfd7d1c78a2853f..556f7981d80a14aee09d946b4e4bf29aebcb079f 100644 (file)
@@ -851,7 +851,7 @@ void CommunicatorClass::suck(const ZoneName& domain, const ComboAddress& remote,
              ctx.slog->info(Logr::Warning, "XFR: unable to xfr, address family is not enabled for outgoing traffic (query-local-address)", "address family", Logging::Loggable(isV6 ? "IPv6" : "IPv4")));
         return;
       }
-      laddr = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
+      laddr = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0).d_address;
     }
 
     bool hadDnssecZone = false;
index 47e5a84d2b97e75b480f4096b726137f16664ef8..5547451529e983ed61f575def8beaf633086a671 100644 (file)
@@ -118,12 +118,10 @@ void sendfromto(int sock, const PacketBuffer& buffer, const ComboAddress& from,
     return;
   }
 
-  try {
-    sendMsgWithOptions(sock, buffer.data(), buffer.size(), &dest, &from, 0, 0);
-  }
-  catch (const std::exception& exp) {
-    VERBOSESLOG(infolog("Error sending UDP response from %s to %s: %s", from.toStringWithPort(), dest.toStringWithPort(), exp.what()),
-                dnsdist::logging::getTopLogger("sendfromto")->error(Logr::Info, exp.what(), "Error sending UDP response", "source.address", Logging::Loggable(from), "client.address", Logging::Loggable(dest)));
+  auto ret = sendMsgWithOptions(sock, buffer.data(), buffer.size(), &dest, &from, 0, 0);
+  if (!ret.has_value()) {
+    VERBOSESLOG(infolog("Error sending UDP response from %s to %s: %s", from.toStringWithPort(), dest.toStringWithPort(), stringerror(ret.error())),
+                dnsdist::logging::getTopLogger("sendfromto")->error(Logr::Info, ret.error(), "Error sending UDP response", "source.address", Logging::Loggable(from), "client.address", Logging::Loggable(dest)));
   }
 }
 
index f3c58bc55da7a04c8d3ecd24364654caed429705..2347e551b7e9526add95b7b06ab5504f419bc5f4 100644 (file)
@@ -154,12 +154,11 @@ static void sendFromTo(Socket& sock, const ComboAddress& peer, const ComboAddres
     return;
   }
 
-  try {
-    sendMsgWithOptions(sock.getHandle(), buffer.data(), buffer.size(), &peer, &local, 0, 0);
-  }
-  catch (const std::exception& exp) {
-    VERBOSESLOG(infolog("Error while sending QUIC datagram of size %d from %s to %s: %s", buffer.size(), local.toStringWithPort(), peer.toStringWithPort(), exp.what()),
-                dnsdist::logging::getTopLogger("quic-send-from-to")->error(Logr::Info, exp.what(), "Error while sending QUIC datagram", "datagram_size", Logging::Loggable(buffer.size()), "source.address", Logging::Loggable(local), "client.address", Logging::Loggable(peer)));
+  auto ret = sendMsgWithOptions(sock.getHandle(), buffer.data(), buffer.size(), &peer, &local, 0, 0);
+
+  if (!ret.has_value()) {
+    VERBOSESLOG(infolog("Error while sending QUIC datagram of size %d from %s to %s: %s", buffer.size(), local.toStringWithPort(), peer.toStringWithPort(), stringerror(ret.error())),
+                dnsdist::logging::getTopLogger("quic-send-from-to")->error(Logr::Info, ret.error(), "Error while sending QUIC datagram", "datagram_size", Logging::Loggable(buffer.size()), "source.address", Logging::Loggable(local), "client.address", Logging::Loggable(peer)));
   }
 }
 
index 9181c8b66685f73f82c557db66f7d862a730cc91..44d458790c66432a8bb54811c3ea4c3d610a705b 100644 (file)
@@ -392,7 +392,7 @@ void ComboAddress::truncate(unsigned int bits) noexcept
   *place &= (~((1 << bitsleft) - 1));
 }
 
-size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags)
+pdns::expected<size_t, int> sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags)
 {
   msghdr msgh{};
   iovec iov{};
@@ -457,7 +457,7 @@ size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const
       iov.iov_base = reinterpret_cast<void*>(reinterpret_cast<char*>(iov.iov_base) + written);
     }
     else if (res == 0) {
-      return res;
+      return static_cast<size_t>(0);
     }
     else if (res == -1) {
       int err = errno;
@@ -469,7 +469,7 @@ size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const
            especially with TCP Fast Open */
         return sent;
       }
-      unixDie("failed in sendMsgWithOptions");
+      return pdns::unexpected{err};
     }
   } while (true);
 
index 6a00d04c8caa02aa149c2672085e5968a4d23d21..4afcc9ac9e6009bad67d0f28dca74a23d5c9bad2 100644 (file)
@@ -32,6 +32,7 @@
 #include <netdb.h>
 #include <sstream>
 #include <sys/un.h>
+#include <variant>
 
 #include "namespaces.hh"
 
@@ -2077,7 +2078,52 @@ bool HarvestDestinationAddress(const struct msghdr* msgh, ComboAddress* destinat
 bool HarvestTimestamp(struct msghdr* msgh, struct timeval* timeval);
 void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, cmsgbuf_aligned* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
 int sendOnNBSocket(int fileDesc, const struct msghdr* msgh);
-size_t sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
+
+// A poor man's std::expected, which only becomes available for real with C++23
+namespace pdns
+{
+template <class E>
+class unexpected
+{
+public:
+  unexpected(const E& arg) :
+    err(arg) {}
+  const E& error() const
+  {
+    return err;
+  }
+
+private:
+  E err;
+};
+
+template <class T, class E>
+class expected : private std::variant<T, E>
+{
+public:
+  expected(const T& arg) :
+    std::variant<T, E>(arg) {}
+
+  expected(const unexpected<E>& arg) :
+    std::variant<T, E>(arg.error()) {}
+
+  [[nodiscard]] bool has_value() const
+  {
+    return std::holds_alternative<T>(*this);
+  }
+
+  const T& value() const
+  {
+    return std::get<T>(*this);
+  }
+  const E& error() const
+  {
+    return std::get<E>(*this);
+  }
+};
+}
+
+[[nodiscard]] pdns::expected<size_t, int> sendMsgWithOptions(int socketDesc, const void* buffer, size_t len, const ComboAddress* dest, const ComboAddress* local, unsigned int localItf, int flags);
 
 /* requires a non-blocking, connected TCP socket */
 bool isTCPSocketUsable(int sock);
index 9eab14178dd9c1557ab71ec9d8f4c5970c542284..2a57f958df33a4d661dd7482ed670e1c8a33fc46 100644 (file)
@@ -378,8 +378,8 @@ static void communicatorSendNotifications(const int sock4, const int sock6)
 static void communicatorThread()
 {
   setThreadName("ixfrdist/communicator");
-  auto sock4 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0), true);
-  auto sock6 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0), true);
+  auto sock4 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET, 0).d_address, true);
+  auto sock6 = makeQuerySocket(pdns::getQueryLocalAddress(AF_INET6, 0).d_address, true);
 
   if (sock4 < 0) {
     throw std::runtime_error("Unable to create local query socket");
index ba7dd4193e9a5f418fff350382334af16caf3b4e..2662b7b2d8b7859dde6d9534328fefeebc12282a 100644 (file)
@@ -360,7 +360,14 @@ LWResult::Result asendto(const void* data, size_t len,
     // fatals (with calling exit!) on some error conditions.  This all looks fragile, but there are
     // existing callers, changing sendMsgWithOption() to return ssize_t to mkae it more sned(2) like
     // needs to be done with extra care.
-    sent = sendMsgWithOptions(*fileDesc, data, len, nullptr, &local, interface->d_index, 0);
+
+    auto sendRet = sendMsgWithOptions(*fileDesc, data, len, nullptr, &local, interface->d_index, 0);
+    if (sendRet.has_value()) {
+      sent = static_cast<ssize_t>(sendRet.value());
+    }
+    else {
+      sent = sendRet.error();
+    }
   }
   if (sent < 0) {
     int tmp = errno;
index fb231cced9992d25617b355d522198694686759a..eaa35598bbda1a7aaec0772ce915022232849896 100644 (file)
@@ -690,7 +690,7 @@ static int forwardPacket(UeberBackend& B, const updateContext& ctx, const DNSPac
     if (!pdns::isQueryLocalAddressFamilyEnabled(remote.sin4.sin_family)) {
       continue;
     }
-    auto local = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0);
+    auto local = pdns::getQueryLocalAddress(remote.sin4.sin_family, 0).d_address;
     ctx.sock = makeQuerySocket(local, false); // create TCP socket. RFC2136 section 6.2 seems to be ok with this.
     if (ctx.sock < 0) {
       SLOG(g_log << Logger::Error << ctx.msgPrefix << "Error creating socket: " << stringerror() << endl,
index b9e6f71fb9d836d281150e9e957e2320be5ae52a..3e5e9818baf1dc8a9abcd794dda2417cb24971ff 100644 (file)
@@ -439,10 +439,13 @@ public:
 #ifdef MSG_FASTOPEN
     if (d_fastOpen) {
       int socketFlags = MSG_FASTOPEN;
-      size_t sent = sendMsgWithOptions(d_socket, reinterpret_cast<const char *>(&buffer.at(pos)), toWrite - pos, &d_remote, nullptr, 0, socketFlags);
-      if (sent > 0) {
+      auto sendRet = sendMsgWithOptions(d_socket, reinterpret_cast<const char*>(&buffer.at(pos)), toWrite - pos, &d_remote, nullptr, 0, socketFlags);
+      if (!sendRet.has_value()) {
+        throw std::runtime_error("sendMsgWithOptions: " + stringerror(sendRet.error()));
+      }
+      if (sendRet.value() > 0) {
         d_fastOpen = false;
-        pos += sent;
+        pos += sendRet.value();
       }
 
       if (pos < toWrite) {
@@ -484,12 +487,15 @@ public:
 #ifdef MSG_FASTOPEN
     if (d_fastOpen) {
       int socketFlags = MSG_FASTOPEN;
-      size_t sent = sendMsgWithOptions(d_socket, reinterpret_cast<const char *>(buffer), bufferSize, &d_remote, nullptr, 0, socketFlags);
-      if (sent > 0) {
+      auto sendRet = sendMsgWithOptions(d_socket, reinterpret_cast<const char*>(buffer), bufferSize, &d_remote, nullptr, 0, socketFlags);
+      if (!sendRet.has_value()) {
+        throw std::runtime_error("sendMsgWithOptions: " + stringerror(sendRet.error()));
+      }
+      if (sendRet.value() > 0) {
         d_fastOpen = false;
       }
 
-      return sent;
+      return sendRet.value();
     }
 #endif /* MSG_FASTOPEN */
 
index a21e826cc6b3b260ea6df06be75fa3bca6ef01dd..dc67cc2eeb6bb306e784e58602e7ccf2c8150b0d 100644 (file)
@@ -968,4 +968,22 @@ BOOST_AUTO_TEST_CASE(test_unspecified)
   }
 }
 
+// Check the tricky case: two somewhat compatibe types
+BOOST_AUTO_TEST_CASE(test_expected)
+{
+  pdns::expected<size_t, int> test(0);
+
+  test = static_cast<size_t>(1);
+  BOOST_ASSERT(test.has_value());
+  BOOST_CHECK_EQUAL(test.value(), 1U);
+
+  test = 2;
+  BOOST_ASSERT(test.has_value());
+  BOOST_CHECK_EQUAL(test.value(), 2U);
+
+  test = pdns::unexpected(3);
+  BOOST_ASSERT(!test.has_value());
+  BOOST_CHECK_EQUAL(test.error(), 3);
+}
+
 BOOST_AUTO_TEST_SUITE_END()