Allow DSCP tagging and local traffic prioritization to be enabled separately on Mac and Linux
This commit is contained in:
parent
c7700f96fc
commit
5c9533f6d7
5 changed files with 198 additions and 56 deletions
|
|
@ -586,59 +586,92 @@ namespace platf {
|
|||
|
||||
class qos_t: public deinit_t {
|
||||
public:
|
||||
qos_t(int sockfd, int level, int option):
|
||||
sockfd(sockfd), level(level), option(option) {}
|
||||
qos_t(int sockfd, std::vector<std::tuple<int, int, int>> options):
|
||||
sockfd(sockfd), options(options) {}
|
||||
|
||||
virtual ~qos_t() {
|
||||
int reset_val = -1;
|
||||
if (setsockopt(sockfd, level, option, &reset_val, sizeof(reset_val)) < 0) {
|
||||
BOOST_LOG(warning) << "Failed to reset IP TOS: "sv << errno;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int sockfd;
|
||||
int level;
|
||||
int option;
|
||||
std::vector<std::tuple<int, int, int>> options;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Enables QoS on the given socket for traffic to the specified destination.
|
||||
* @param native_socket The native socket handle.
|
||||
* @param address The destination address for traffic sent on this socket.
|
||||
* @param port The destination port for traffic sent on this socket.
|
||||
* @param data_type The type of traffic sent on this socket.
|
||||
* @param dscp_tagging Specifies whether to enable DSCP tagging on outgoing traffic.
|
||||
*/
|
||||
std::unique_ptr<deinit_t>
|
||||
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type) {
|
||||
enable_socket_qos(uintptr_t native_socket, boost::asio::ip::address &address, uint16_t port, qos_data_type_e data_type, bool dscp_tagging) {
|
||||
int sockfd = (int) native_socket;
|
||||
std::vector<std::tuple<int, int, int>> reset_options;
|
||||
|
||||
int level;
|
||||
int option;
|
||||
if (address.is_v6()) {
|
||||
level = SOL_IPV6;
|
||||
option = IPV6_TCLASS;
|
||||
if (dscp_tagging) {
|
||||
int level;
|
||||
int option;
|
||||
if (address.is_v6()) {
|
||||
level = SOL_IPV6;
|
||||
option = IPV6_TCLASS;
|
||||
}
|
||||
else {
|
||||
level = SOL_IP;
|
||||
option = IP_TOS;
|
||||
}
|
||||
|
||||
// The specific DSCP values here are chosen to be consistent with Windows
|
||||
int dscp = 0;
|
||||
switch (data_type) {
|
||||
case qos_data_type_e::video:
|
||||
dscp = 40;
|
||||
break;
|
||||
case qos_data_type_e::audio:
|
||||
dscp = 56;
|
||||
break;
|
||||
default:
|
||||
BOOST_LOG(error) << "Unknown traffic type: "sv << (int) data_type;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dscp) {
|
||||
// Shift to put the DSCP value in the correct position in the TOS field
|
||||
dscp <<= 2;
|
||||
|
||||
if (setsockopt(sockfd, level, option, &dscp, sizeof(dscp)) == 0) {
|
||||
// Reset TOS to -1 when QoS is disabled
|
||||
reset_options.emplace_back(std::make_tuple(level, option, -1));
|
||||
}
|
||||
else {
|
||||
BOOST_LOG(error) << "Failed to set TOS/TCLASS: "sv << errno;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We can use SO_PRIORITY to set outgoing traffic priority without DSCP tagging.
|
||||
//
|
||||
// NB: We set this after IP_TOS/IPV6_TCLASS since setting TOS value seems to
|
||||
// reset SO_PRIORITY back to 0.
|
||||
//
|
||||
// 6 is the highest priority that can be used without SYS_CAP_ADMIN.
|
||||
int priority = data_type == qos_data_type_e::audio ? 6 : 5;
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_PRIORITY, &priority, sizeof(priority)) == 0) {
|
||||
// Reset SO_PRIORITY to 0 when QoS is disabled
|
||||
reset_options.emplace_back(std::make_tuple(SOL_SOCKET, SO_PRIORITY, 0));
|
||||
}
|
||||
else {
|
||||
level = SOL_IP;
|
||||
option = IP_TOS;
|
||||
BOOST_LOG(error) << "Failed to set SO_PRIORITY: "sv << errno;
|
||||
}
|
||||
|
||||
// The specific DSCP values here are chosen to be consistent with Windows
|
||||
int dscp;
|
||||
switch (data_type) {
|
||||
case qos_data_type_e::video:
|
||||
dscp = 40;
|
||||
break;
|
||||
case qos_data_type_e::audio:
|
||||
dscp = 56;
|
||||
break;
|
||||
default:
|
||||
BOOST_LOG(error) << "Unknown traffic type: "sv << (int) data_type;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Shift to put the DSCP value in the correct position in the TOS field
|
||||
dscp <<= 2;
|
||||
|
||||
if (setsockopt(sockfd, level, option, &dscp, sizeof(dscp)) < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::make_unique<qos_t>(sockfd, level, option);
|
||||
return std::make_unique<qos_t>(sockfd, reset_options);
|
||||
}
|
||||
|
||||
namespace source {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue