From: Otto Moerbeek Date: Tue, 7 Jul 2026 09:11:55 +0000 (+0200) Subject: Add a poor man's "std:expected" and use it in sendMsgwithOptions X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=17296ecdd36633fd5d6ab07509d3b0ff76d9679d;p=thirdparty%2Fpdns.git Add a poor man's "std:expected" and use it in sendMsgwithOptions Signed-off-by: Otto Moerbeek --- diff --git a/pdns/auth-primarycommunicator.cc b/pdns/auth-primarycommunicator.cc index 3de7cad7ac..9335de53ee 100644 --- a/pdns/auth-primarycommunicator.cc +++ b/pdns/auth-primarycommunicator.cc @@ -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; diff --git a/pdns/auth-secondarycommunicator.cc b/pdns/auth-secondarycommunicator.cc index 726134a4eb..556f7981d8 100644 --- a/pdns/auth-secondarycommunicator.cc +++ b/pdns/auth-secondarycommunicator.cc @@ -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; diff --git a/pdns/dnsdistdist/dnsdist-udp.cc b/pdns/dnsdistdist/dnsdist-udp.cc index 47e5a84d2b..5547451529 100644 --- a/pdns/dnsdistdist/dnsdist-udp.cc +++ b/pdns/dnsdistdist/dnsdist-udp.cc @@ -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))); } } diff --git a/pdns/dnsdistdist/doq-common.cc b/pdns/dnsdistdist/doq-common.cc index f3c58bc55d..2347e551b7 100644 --- a/pdns/dnsdistdist/doq-common.cc +++ b/pdns/dnsdistdist/doq-common.cc @@ -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))); } } diff --git a/pdns/iputils.cc b/pdns/iputils.cc index 9181c8b666..44d458790c 100644 --- a/pdns/iputils.cc +++ b/pdns/iputils.cc @@ -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 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(reinterpret_cast(iov.iov_base) + written); } else if (res == 0) { - return res; + return static_cast(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); diff --git a/pdns/iputils.hh b/pdns/iputils.hh index 6a00d04c8c..4afcc9ac9e 100644 --- a/pdns/iputils.hh +++ b/pdns/iputils.hh @@ -32,6 +32,7 @@ #include #include #include +#include #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 unexpected +{ +public: + unexpected(const E& arg) : + err(arg) {} + const E& error() const + { + return err; + } + +private: + E err; +}; + +template +class expected : private std::variant +{ +public: + expected(const T& arg) : + std::variant(arg) {} + + expected(const unexpected& arg) : + std::variant(arg.error()) {} + + [[nodiscard]] bool has_value() const + { + return std::holds_alternative(*this); + } + + const T& value() const + { + return std::get(*this); + } + const E& error() const + { + return std::get(*this); + } +}; +} + +[[nodiscard]] pdns::expected 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); diff --git a/pdns/ixfrdist.cc b/pdns/ixfrdist.cc index 9eab14178d..2a57f958df 100644 --- a/pdns/ixfrdist.cc +++ b/pdns/ixfrdist.cc @@ -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"); diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index ba7dd4193e..2662b7b2d8 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -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(sendRet.value()); + } + else { + sent = sendRet.error(); + } } if (sent < 0) { int tmp = errno; diff --git a/pdns/rfc2136handler.cc b/pdns/rfc2136handler.cc index fb231cced9..eaa35598bb 100644 --- a/pdns/rfc2136handler.cc +++ b/pdns/rfc2136handler.cc @@ -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, diff --git a/pdns/tcpiohandler.hh b/pdns/tcpiohandler.hh index b9e6f71fb9..3e5e9818ba 100644 --- a/pdns/tcpiohandler.hh +++ b/pdns/tcpiohandler.hh @@ -439,10 +439,13 @@ public: #ifdef MSG_FASTOPEN if (d_fastOpen) { int socketFlags = MSG_FASTOPEN; - size_t sent = sendMsgWithOptions(d_socket, reinterpret_cast(&buffer.at(pos)), toWrite - pos, &d_remote, nullptr, 0, socketFlags); - if (sent > 0) { + auto sendRet = sendMsgWithOptions(d_socket, reinterpret_cast(&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(buffer), bufferSize, &d_remote, nullptr, 0, socketFlags); - if (sent > 0) { + auto sendRet = sendMsgWithOptions(d_socket, reinterpret_cast(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 */ diff --git a/pdns/test-iputils_hh.cc b/pdns/test-iputils_hh.cc index a21e826cc6..dc67cc2eeb 100644 --- a/pdns/test-iputils_hh.cc +++ b/pdns/test-iputils_hh.cc @@ -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 test(0); + + test = static_cast(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()