From bb3b7984f32f7206a63ba54ff5c3b01729ac6ea4 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Thu, 1 Feb 2024 18:17:12 -0600 Subject: [PATCH] Add refcounting to Mac and Linux QoS state to ensure it works properly with multiple clients This means we can't control DSCP tagging per-client, but it shouldn't pose a big problem as routers that blackhole DSCP tagged traffic are pretty rare. --- src/platform/linux/misc.cpp | 19 ++++++++++++++----- src/platform/macos/misc.mm | 19 ++++++++++++++----- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/platform/linux/misc.cpp b/src/platform/linux/misc.cpp index 2d82d387..bf2f6169 100644 --- a/src/platform/linux/misc.cpp +++ b/src/platform/linux/misc.cpp @@ -584,16 +584,25 @@ namespace platf { return true; } + // We can't track QoS state separately for each destination on this OS, + // so we keep a ref count to only disable QoS options when all clients + // are disconnected. + static std::atomic qos_ref_count = 0; + class qos_t: public deinit_t { public: qos_t(int sockfd, std::vector> options): - sockfd(sockfd), options(options) {} + sockfd(sockfd), options(options) { + qos_ref_count++; + } virtual ~qos_t() { - for (const auto &tuple : options) { - auto reset_val = std::get<2>(tuple); - if (setsockopt(sockfd, std::get<0>(tuple), std::get<1>(tuple), &reset_val, sizeof(reset_val)) < 0) { - BOOST_LOG(warning) << "Failed to reset option: "sv << errno; + if (--qos_ref_count == 0) { + for (const auto &tuple : options) { + auto reset_val = std::get<2>(tuple); + if (setsockopt(sockfd, std::get<0>(tuple), std::get<1>(tuple), &reset_val, sizeof(reset_val)) < 0) { + BOOST_LOG(warning) << "Failed to reset option: "sv << errno; + } } } } diff --git a/src/platform/macos/misc.mm b/src/platform/macos/misc.mm index 5c7fca98..0a36e33f 100644 --- a/src/platform/macos/misc.mm +++ b/src/platform/macos/misc.mm @@ -407,16 +407,25 @@ namespace platf { return true; } + // We can't track QoS state separately for each destination on this OS, + // so we keep a ref count to only disable QoS options when all clients + // are disconnected. + static std::atomic qos_ref_count = 0; + class qos_t: public deinit_t { public: qos_t(int sockfd, std::vector> options): - sockfd(sockfd), options(options) {} + sockfd(sockfd), options(options) { + qos_ref_count++; + } virtual ~qos_t() { - for (const auto &tuple : options) { - auto reset_val = std::get<2>(tuple); - if (setsockopt(sockfd, std::get<0>(tuple), std::get<1>(tuple), &reset_val, sizeof(reset_val)) < 0) { - BOOST_LOG(warning) << "Failed to reset option: "sv << errno; + if (--qos_ref_count == 0) { + for (const auto &tuple : options) { + auto reset_val = std::get<2>(tuple); + if (setsockopt(sockfd, std::get<0>(tuple), std::get<1>(tuple), &reset_val, sizeof(reset_val)) < 0) { + BOOST_LOG(warning) << "Failed to reset option: "sv << errno; + } } } }