Allow DSCP tagging and local traffic prioritization to be enabled separately on Mac and Linux
This commit is contained in:
+10
-1
@@ -608,8 +608,17 @@ namespace platf {
|
|||||||
audio,
|
audio,
|
||||||
video
|
video
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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>
|
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);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Open a url in the default web browser.
|
* @brief Open a url in the default web browser.
|
||||||
|
|||||||
+70
-37
@@ -586,59 +586,92 @@ namespace platf {
|
|||||||
|
|
||||||
class qos_t: public deinit_t {
|
class qos_t: public deinit_t {
|
||||||
public:
|
public:
|
||||||
qos_t(int sockfd, int level, int option):
|
qos_t(int sockfd, std::vector<std::tuple<int, int, int>> options):
|
||||||
sockfd(sockfd), level(level), option(option) {}
|
sockfd(sockfd), options(options) {}
|
||||||
|
|
||||||
virtual ~qos_t() {
|
virtual ~qos_t() {
|
||||||
int reset_val = -1;
|
for (const auto &tuple : options) {
|
||||||
if (setsockopt(sockfd, level, option, &reset_val, sizeof(reset_val)) < 0) {
|
auto reset_val = std::get<2>(tuple);
|
||||||
BOOST_LOG(warning) << "Failed to reset IP TOS: "sv << errno;
|
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:
|
private:
|
||||||
int sockfd;
|
int sockfd;
|
||||||
int level;
|
std::vector<std::tuple<int, int, int>> options;
|
||||||
int option;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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>
|
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;
|
int sockfd = (int) native_socket;
|
||||||
|
std::vector<std::tuple<int, int, int>> reset_options;
|
||||||
|
|
||||||
int level;
|
if (dscp_tagging) {
|
||||||
int option;
|
int level;
|
||||||
if (address.is_v6()) {
|
int option;
|
||||||
level = SOL_IPV6;
|
if (address.is_v6()) {
|
||||||
option = IPV6_TCLASS;
|
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 {
|
else {
|
||||||
level = SOL_IP;
|
BOOST_LOG(error) << "Failed to set SO_PRIORITY: "sv << errno;
|
||||||
option = IP_TOS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The specific DSCP values here are chosen to be consistent with Windows
|
return std::make_unique<qos_t>(sockfd, reset_options);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace source {
|
namespace source {
|
||||||
|
|||||||
@@ -407,12 +407,103 @@ namespace platf {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class qos_t: public deinit_t {
|
||||||
|
public:
|
||||||
|
qos_t(int sockfd, std::vector<std::tuple<int, int, int>> options):
|
||||||
|
sockfd(sockfd), options(options) {}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int sockfd;
|
||||||
|
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>
|
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) {
|
||||||
// Unimplemented
|
int sockfd = (int) native_socket;
|
||||||
//
|
std::vector<std::tuple<int, int, int>> reset_options;
|
||||||
// NB: When implementing, remember to consider that some routes can drop DSCP-tagged packets completely!
|
|
||||||
return nullptr;
|
// We can use SO_NET_SERVICE_TYPE to set link-layer prioritization without DSCP tagging
|
||||||
|
int service_type = 0;
|
||||||
|
switch (data_type) {
|
||||||
|
case qos_data_type_e::video:
|
||||||
|
service_type = NET_SERVICE_TYPE_VI;
|
||||||
|
break;
|
||||||
|
case qos_data_type_e::audio:
|
||||||
|
service_type = NET_SERVICE_TYPE_VO;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
BOOST_LOG(error) << "Unknown traffic type: "sv << (int) data_type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (service_type) {
|
||||||
|
if (setsockopt(sockfd, SOL_SOCKET, SO_NET_SERVICE_TYPE, &service_type, sizeof(service_type)) == 0) {
|
||||||
|
// Reset SO_NET_SERVICE_TYPE to best-effort when QoS is disabled
|
||||||
|
reset_options.emplace_back(std::make_tuple(SOL_SOCKET, SO_NET_SERVICE_TYPE, NET_SERVICE_TYPE_BE));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_LOG(error) << "Failed to set SO_NET_SERVICE_TYPE: "sv << errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dscp_tagging) {
|
||||||
|
int level;
|
||||||
|
int option;
|
||||||
|
if (address.is_v6()) {
|
||||||
|
level = IPPROTO_IPV6;
|
||||||
|
option = IPV6_TCLASS;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
level = IPPROTO_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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_unique<qos_t>(sockfd, reset_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace platf
|
} // namespace platf
|
||||||
|
|||||||
@@ -1209,13 +1209,26 @@ namespace platf {
|
|||||||
QOS_FLOWID flow_id;
|
QOS_FLOWID flow_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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>
|
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) {
|
||||||
SOCKADDR_IN saddr_v4;
|
SOCKADDR_IN saddr_v4;
|
||||||
SOCKADDR_IN6 saddr_v6;
|
SOCKADDR_IN6 saddr_v6;
|
||||||
PSOCKADDR dest_addr;
|
PSOCKADDR dest_addr;
|
||||||
bool using_connect_hack = false;
|
bool using_connect_hack = false;
|
||||||
|
|
||||||
|
// Windows doesn't support any concept of traffic priority without DSCP tagging
|
||||||
|
if (!dscp_tagging) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
static std::once_flag load_qwave_once_flag;
|
static std::once_flag load_qwave_once_flag;
|
||||||
std::call_once(load_qwave_once_flag, []() {
|
std::call_once(load_qwave_once_flag, []() {
|
||||||
// qWAVE is not installed by default on Windows Server, so we load it dynamically
|
// qWAVE is not installed by default on Windows Server, so we load it dynamically
|
||||||
|
|||||||
+8
-12
@@ -1740,12 +1740,10 @@ namespace stream {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable QoS tagging on video traffic if requested by the client
|
// Enable local prioritization and QoS tagging on video traffic if requested by the client
|
||||||
if (session->config.videoQosType) {
|
auto address = session->video.peer.address();
|
||||||
auto address = session->video.peer.address();
|
session->video.qos = platf::enable_socket_qos(ref->video_sock.native_handle(), address,
|
||||||
session->video.qos = platf::enable_socket_qos(ref->video_sock.native_handle(), address,
|
session->video.peer.port(), platf::qos_data_type_e::video, session->config.videoQosType != 0);
|
||||||
session->video.peer.port(), platf::qos_data_type_e::video);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Start capturing Video"sv;
|
BOOST_LOG(debug) << "Start capturing Video"sv;
|
||||||
video::capture(session->mail, session->config.monitor, session);
|
video::capture(session->mail, session->config.monitor, session);
|
||||||
@@ -1765,12 +1763,10 @@ namespace stream {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enable QoS tagging on audio traffic if requested by the client
|
// Enable local prioritization and QoS tagging on audio traffic if requested by the client
|
||||||
if (session->config.audioQosType) {
|
auto address = session->audio.peer.address();
|
||||||
auto address = session->audio.peer.address();
|
session->audio.qos = platf::enable_socket_qos(ref->audio_sock.native_handle(), address,
|
||||||
session->audio.qos = platf::enable_socket_qos(ref->audio_sock.native_handle(), address,
|
session->audio.peer.port(), platf::qos_data_type_e::audio, session->config.audioQosType != 0);
|
||||||
session->audio.peer.port(), platf::qos_data_type_e::audio);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_LOG(debug) << "Start capturing Audio"sv;
|
BOOST_LOG(debug) << "Start capturing Audio"sv;
|
||||||
audio::capture(session->mail, session->config.audio, session);
|
audio::capture(session->mail, session->config.audio, session);
|
||||||
|
|||||||
Reference in New Issue
Block a user