feat: support dscp classes in socket iptos (#2594)
* refactor: Replace ToS with DSCP IP TOS was superseded by DSCP in RFC 2474. Co-authored-by: dgcampea <dgcampea@outlook.com>
This commit is contained in:
parent
ec6a92d761
commit
6383e2ff5f
10
cli/cli.cc
10
cli/cli.cc
|
@ -76,7 +76,13 @@ static auto constexpr Options = std::array<tr_option, 19>{
|
|||
{ 'm', "portmap", "Enable portmapping via NAT-PMP or UPnP", "m", false, nullptr },
|
||||
{ 'M', "no-portmap", "Disable portmapping", "M", false, nullptr },
|
||||
{ 'p', "port", "Port for incoming peers (Default: " TR_DEFAULT_PEER_PORT_STR ")", "p", true, "<port>" },
|
||||
{ 't', "tos", "Peer socket TOS (0 to 255, default=" TR_DEFAULT_PEER_SOCKET_TOS_STR ")", "t", true, "<tos>" },
|
||||
{ 't',
|
||||
"tos",
|
||||
"Peer socket DSCP / ToS setting (number, or a DSCP string, e.g. 'af11' or 'cs0', default=" TR_DEFAULT_PEER_SOCKET_TOS_STR
|
||||
")",
|
||||
"t",
|
||||
true,
|
||||
"<dscp-or-tos>" },
|
||||
{ 'u', "uplimit", "Set max upload speed in " SPEED_K_STR, "u", true, "<speed>" },
|
||||
{ 'U', "no-uplimit", "Don't limit the upload speed", "U", false, nullptr },
|
||||
{ 'v', "verify", "Verify the specified torrent", "v", false, nullptr },
|
||||
|
@ -434,7 +440,7 @@ static int parseCommandLine(tr_variant* d, int argc, char const** argv)
|
|||
break;
|
||||
|
||||
case 't':
|
||||
tr_variantDictAddInt(d, TR_KEY_peer_socket_tos, atoi(my_optarg));
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, my_optarg);
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
.Op Fl h
|
||||
.Op Fl m | M
|
||||
.Op Fl p Ar port
|
||||
.Op Fl t Ar tos
|
||||
.Op Fl -tos Ar tos
|
||||
.Op Fl u Ar number | Fl U
|
||||
.Op Fl v
|
||||
.Op Fl w Ar directory
|
||||
|
@ -74,17 +74,43 @@ Enable portmapping via NAT-PMP or UPnP
|
|||
Disable portmapping
|
||||
.It Fl p -port Ar port
|
||||
Set the port to listen for incoming peers. (Default: 51413)
|
||||
.It Fl t -tos Ar tos
|
||||
Set the peer socket TOS for local router-based traffic shaping.
|
||||
Valid values are
|
||||
.It Fl -tos Ar tos
|
||||
.nf
|
||||
Use a ToS or DSCP name to set the peer socket service type for
|
||||
local router-based traffic shaping. Valid values are a decimal
|
||||
value 0-255, or any of these DSCP strings:
|
||||
.fi
|
||||
.Pp
|
||||
.Dq af11 ,
|
||||
.Dq af12 ,
|
||||
.Dq af13 ,
|
||||
.Dq af21 ,
|
||||
.Dq af22 ,
|
||||
.Dq af23 ,
|
||||
.Dq af31 ,
|
||||
.Dq af32 ,
|
||||
.Dq af33 ,
|
||||
.Dq af41 ,
|
||||
.Dq af42 ,
|
||||
.Dq af43 ,
|
||||
.Dq cs0 ,
|
||||
.Dq cs1 ,
|
||||
.Dq cs2 ,
|
||||
.Dq cs3 ,
|
||||
.Dq cs4 ,
|
||||
.Dq cs5 ,
|
||||
.Dq cs6 ,
|
||||
.Dq cs7 ,
|
||||
.Dq ef ,
|
||||
.Dq le
|
||||
|
||||
These ToS keys are deprecated and will be removed in the future:
|
||||
.Dq default ,
|
||||
.Dq lowcost ,
|
||||
.Dq throughput ,
|
||||
.Dq lowdelay,
|
||||
.Dq reliability ,
|
||||
.Dq lowdelay ,
|
||||
.Dq throughput
|
||||
.Pp
|
||||
a decimal value 0-255 or a hexidecimal value 0x00-0xff)
|
||||
.It Fl u -uplimit Ar number
|
||||
Set the maximum upload speed in KB/s
|
||||
.It Fl U -no-uplimit
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// This file Copyright © 2010 Transmission authors and contributors.
|
||||
// This file Copyright © 2010-2022 Transmission authors and contributors.
|
||||
// It may be used under the MIT (SPDX: MIT) license.
|
||||
// License text can be found in the licenses/ folder.
|
||||
|
||||
|
@ -9,6 +9,7 @@
|
|||
#include <cstring>
|
||||
#include <ctime>
|
||||
#include <string_view>
|
||||
#include <utility> // std::pair
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
|
@ -149,8 +150,70 @@ int tr_address_compare(tr_address const* a, tr_address const* b)
|
|||
* TCP sockets
|
||||
**********************************************************************/
|
||||
|
||||
// RFCs 2474, 3246, 4594 & 8622
|
||||
// Service class names are defined in RFC 4594, RFC 5865, and RFC 8622.
|
||||
// Not all platforms have these IPTOS_ definitions, so hardcode them here
|
||||
static auto constexpr IpTosNames = std::array<std::pair<int, std::string_view>, 28>{ {
|
||||
{ 0x00, "cs0" }, // IPTOS_CLASS_CS0
|
||||
{ 0x04, "le" },
|
||||
{ 0x20, "cs1" }, // IPTOS_CLASS_CS1
|
||||
{ 0x28, "af11" }, // IPTOS_DSCP_AF11
|
||||
{ 0x30, "af12" }, // IPTOS_DSCP_AF12
|
||||
{ 0x38, "af13" }, // IPTOS_DSCP_AF13
|
||||
{ 0x40, "cs2" }, // IPTOS_CLASS_CS2
|
||||
{ 0x48, "af21" }, // IPTOS_DSCP_AF21
|
||||
{ 0x50, "af22" }, // IPTOS_DSCP_AF22
|
||||
{ 0x58, "af23" }, // IPTOS_DSCP_AF23
|
||||
{ 0x60, "cs3" }, // IPTOS_CLASS_CS3
|
||||
{ 0x68, "af31" }, // IPTOS_DSCP_AF31
|
||||
{ 0x70, "af32" }, // IPTOS_DSCP_AF32
|
||||
{ 0x78, "af33" }, // IPTOS_DSCP_AF33
|
||||
{ 0x80, "cs4" }, // IPTOS_CLASS_CS4
|
||||
{ 0x88, "af41" }, // IPTOS_DSCP_AF41
|
||||
{ 0x90, "af42" }, // IPTOS_DSCP_AF42
|
||||
{ 0x98, "af43" }, // IPTOS_DSCP_AF43
|
||||
{ 0xa0, "cs5" }, // IPTOS_CLASS_CS5
|
||||
{ 0xb8, "ef" }, // IPTOS_DSCP_EF
|
||||
{ 0xc0, "cs6" }, // IPTOS_CLASS_CS6
|
||||
{ 0xe0, "cs7" }, // IPTOS_CLASS_CS7
|
||||
|
||||
// <netinet/ip.h> lists these TOS names as deprecated,
|
||||
// but keep them defined here for backward compatibility
|
||||
{ 0x00, "routine" }, // IPTOS_PREC_ROUTINE
|
||||
{ 0x02, "lowcost" }, // IPTOS_LOWCOST
|
||||
{ 0x02, "mincost" }, // IPTOS_MINCOST
|
||||
{ 0x04, "reliable" }, // IPTOS_RELIABILITY
|
||||
{ 0x08, "throughput" }, // IPTOS_THROUGHPUT
|
||||
{ 0x10, "lowdelay" }, // IPTOS_LOWDELAY
|
||||
} };
|
||||
|
||||
std::string tr_netTosToName(int tos)
|
||||
{
|
||||
auto const test = [tos](auto const& pair)
|
||||
{
|
||||
return pair.first == tos;
|
||||
};
|
||||
auto const it = std::find_if(std::begin(IpTosNames), std::end(IpTosNames), test);
|
||||
return it == std::end(IpTosNames) ? std::to_string(tos) : std::string{ it->second };
|
||||
}
|
||||
|
||||
std::optional<int> tr_netTosFromName(std::string_view name)
|
||||
{
|
||||
auto const test = [&name](auto const& pair)
|
||||
{
|
||||
return pair.second == name;
|
||||
};
|
||||
auto const it = std::find_if(std::begin(IpTosNames), std::end(IpTosNames), test);
|
||||
return it != std::end(IpTosNames) ? it->first : tr_parseNum<int>(name);
|
||||
}
|
||||
|
||||
void tr_netSetTOS([[maybe_unused]] tr_socket_t s, [[maybe_unused]] int tos, tr_address_type type)
|
||||
{
|
||||
if (s == TR_BAD_SOCKET)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == TR_AF_INET)
|
||||
{
|
||||
#if defined(IP_TOS) && !defined(_WIN32)
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#endif
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -104,23 +106,12 @@ constexpr bool tr_address_is_valid(tr_address const* a)
|
|||
* Sockets
|
||||
**********************************************************************/
|
||||
|
||||
/* https://en.wikipedia.org/wiki/Differentiated_services#Class_Selector */
|
||||
enum
|
||||
{
|
||||
TR_IPTOS_LOWCOST = 0x38, /* AF13: low prio, high drop */
|
||||
TR_IPTOS_LOWDELAY = 0x70, /* AF32: high prio, mid drop */
|
||||
TR_IPTOS_THRUPUT = 0x20, /* CS1: low prio, undef drop */
|
||||
TR_IPTOS_RELIABLE = 0x28 /* AF11: low prio, low drop */
|
||||
};
|
||||
|
||||
struct tr_session;
|
||||
|
||||
tr_socket_t tr_netBindTCP(tr_address const* addr, tr_port port, bool suppressMsgs);
|
||||
|
||||
tr_socket_t tr_netAccept(tr_session* session, tr_socket_t bound, tr_address* setme_addr, tr_port* setme_port);
|
||||
|
||||
void tr_netSetTOS(tr_socket_t s, int tos, tr_address_type type);
|
||||
|
||||
void tr_netSetCongestionControl(tr_socket_t s, char const* algorithm);
|
||||
|
||||
void tr_netClose(tr_session* session, tr_socket_t s);
|
||||
|
@ -129,6 +120,17 @@ void tr_netCloseSocket(tr_socket_t fd);
|
|||
|
||||
bool tr_net_hasIPv6(tr_port);
|
||||
|
||||
/// TOS / DSCP
|
||||
|
||||
// get a string of one of <netinet/ip.h>'s IPTOS_ values, e.g. "cs0"
|
||||
std::string tr_netTosToName(int tos);
|
||||
|
||||
// get the number that corresponds to the specified IPTOS_ name, e.g. "cs0" returns 0x00
|
||||
std::optional<int> tr_netTosFromName(std::string_view name);
|
||||
|
||||
// set the IPTOS_ value for the specified socket
|
||||
void tr_netSetTOS(tr_socket_t sock, int tos, tr_address_type type);
|
||||
|
||||
/**
|
||||
* @brief get a human-representable string representing the network error.
|
||||
* @param err an errno on Unix/Linux and an WSAError on win32)
|
||||
|
|
|
@ -624,7 +624,7 @@ static tr_peerIo* tr_peerIoNew(
|
|||
|
||||
if (socket.type == TR_PEER_SOCKET_TYPE_TCP)
|
||||
{
|
||||
tr_netSetTOS(socket.handle.tcp, session->peerSocketTos(), addr->type);
|
||||
session->setSocketTOS(socket.handle.tcp, addr->type);
|
||||
maybeSetCongestionAlgorithm(socket.handle.tcp, session->peerCongestionAlgorithm());
|
||||
}
|
||||
|
||||
|
@ -979,7 +979,7 @@ int tr_peerIoReconnect(tr_peerIo* io)
|
|||
io->event_write = event_new(session->event_base, io->socket.handle.tcp, EV_WRITE, event_write_cb, io);
|
||||
|
||||
event_enable(io, pendingEvents);
|
||||
tr_netSetTOS(io->socket.handle.tcp, session->peerSocketTos(), io->addr.type);
|
||||
io->session->setSocketTOS(io->socket.handle.tcp, io->addr.type);
|
||||
maybeSetCongestionAlgorithm(io->socket.handle.tcp, session->peerCongestionAlgorithm());
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -250,62 +250,6 @@ tr_address const* tr_sessionGetPublicAddress(tr_session const* session, int tr_a
|
|||
****
|
||||
***/
|
||||
|
||||
static int parseTos(std::string_view tos_in)
|
||||
{
|
||||
auto tos = tr_strlower(tr_strvStrip(tos_in));
|
||||
|
||||
if (tos == ""sv || tos == "default"sv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (tos == "lowcost"sv || tos == "mincost"sv)
|
||||
{
|
||||
return TR_IPTOS_LOWCOST;
|
||||
}
|
||||
|
||||
if (tos == "throughput"sv)
|
||||
{
|
||||
return TR_IPTOS_THRUPUT;
|
||||
}
|
||||
|
||||
if (tos == "reliability"sv)
|
||||
{
|
||||
return TR_IPTOS_RELIABLE;
|
||||
}
|
||||
|
||||
if (tos == "lowdelay"sv)
|
||||
{
|
||||
return TR_IPTOS_LOWDELAY;
|
||||
}
|
||||
|
||||
return std::stoi(tos);
|
||||
}
|
||||
|
||||
static std::string format_tos(int value)
|
||||
{
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
return "default";
|
||||
|
||||
case TR_IPTOS_LOWCOST:
|
||||
return "lowcost";
|
||||
|
||||
case TR_IPTOS_THRUPUT:
|
||||
return "throughput";
|
||||
|
||||
case TR_IPTOS_RELIABLE:
|
||||
return "reliability";
|
||||
|
||||
case TR_IPTOS_LOWDELAY:
|
||||
return "lowdelay";
|
||||
|
||||
default:
|
||||
return std::to_string(value);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TR_LIGHTWEIGHT
|
||||
#define TR_DEFAULT_ENCRYPTION TR_CLEAR_PREFERRED
|
||||
#else
|
||||
|
@ -416,7 +360,7 @@ void tr_sessionGetSettings(tr_session const* s, tr_variant* d)
|
|||
tr_variantDictAddBool(d, TR_KEY_peer_port_random_on_start, s->isPortRandom);
|
||||
tr_variantDictAddInt(d, TR_KEY_peer_port_random_low, s->randomPortLow);
|
||||
tr_variantDictAddInt(d, TR_KEY_peer_port_random_high, s->randomPortHigh);
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, format_tos(s->peerSocketTos()));
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_socket_tos, tr_netTosToName(s->peer_socket_tos_));
|
||||
tr_variantDictAddStr(d, TR_KEY_peer_congestion_algorithm, s->peerCongestionAlgorithm());
|
||||
tr_variantDictAddBool(d, TR_KEY_pex_enabled, s->isPexEnabled);
|
||||
tr_variantDictAddBool(d, TR_KEY_port_forwarding_enabled, tr_sessionIsPortForwardingEnabled(s));
|
||||
|
@ -827,9 +771,16 @@ static void sessionSetImpl(void* vdata)
|
|||
tr_sessionSetEncryption(session, tr_encryption_mode(i));
|
||||
}
|
||||
|
||||
if (tr_variantDictFindStrView(settings, TR_KEY_peer_socket_tos, &sv))
|
||||
if (tr_variantDictFindInt(settings, TR_KEY_peer_socket_tos, &i))
|
||||
{
|
||||
session->setPeerSocketTos(parseTos(sv));
|
||||
session->peer_socket_tos_ = i;
|
||||
}
|
||||
else if (tr_variantDictFindStrView(settings, TR_KEY_peer_socket_tos, &sv))
|
||||
{
|
||||
if (auto ip_tos = tr_netTosFromName(sv); ip_tos)
|
||||
{
|
||||
session->peer_socket_tos_ = *ip_tos;
|
||||
}
|
||||
}
|
||||
|
||||
sv = ""sv;
|
||||
|
|
|
@ -231,14 +231,9 @@ public:
|
|||
peer_congestion_algorithm_ = algorithm;
|
||||
}
|
||||
|
||||
int peerSocketTos() const
|
||||
void setSocketTOS(tr_socket_t sock, tr_address_type type)
|
||||
{
|
||||
return peer_socket_tos_;
|
||||
}
|
||||
|
||||
void setPeerSocketTos(int tos)
|
||||
{
|
||||
peer_socket_tos_ = tos;
|
||||
tr_netSetTOS(sock, peer_socket_tos_, type);
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -358,6 +353,11 @@ public:
|
|||
|
||||
std::unique_ptr<tr_rpc_server> rpc_server_;
|
||||
|
||||
// One of <netinet/ip.h>'s IPTOS_ values.
|
||||
// See tr_netTos*() in libtransmission/net.h for more info
|
||||
// Only session.cc should use this.
|
||||
int peer_socket_tos_ = *tr_netTosFromName(TR_DEFAULT_PEER_SOCKET_TOS_STR);
|
||||
|
||||
private:
|
||||
static std::recursive_mutex session_mutex_;
|
||||
|
||||
|
@ -367,8 +367,6 @@ private:
|
|||
std::string incomplete_dir_;
|
||||
std::string peer_congestion_algorithm_;
|
||||
|
||||
int peer_socket_tos_ = 0;
|
||||
|
||||
std::array<bool, TR_SCRIPT_N_TYPES> scripts_enabled_;
|
||||
bool blocklist_enabled_ = false;
|
||||
bool incomplete_dir_enabled_ = false;
|
||||
|
|
|
@ -107,22 +107,8 @@ void tr_udpSetSocketBuffers(tr_session* session)
|
|||
|
||||
void tr_udpSetSocketTOS(tr_session* session)
|
||||
{
|
||||
auto const tos = session->peerSocketTos();
|
||||
|
||||
if (tos != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (session->udp_socket != TR_BAD_SOCKET)
|
||||
{
|
||||
tr_netSetTOS(session->udp_socket, tos, TR_AF_INET);
|
||||
}
|
||||
|
||||
if (session->udp6_socket != TR_BAD_SOCKET)
|
||||
{
|
||||
tr_netSetTOS(session->udp6_socket, tos, TR_AF_INET6);
|
||||
}
|
||||
session->setSocketTOS(session->udp_socket, TR_AF_INET);
|
||||
session->setSocketTOS(session->udp6_socket, TR_AF_INET6);
|
||||
}
|
||||
|
||||
/* BEP-32 has a rather nice explanation of why we need to bind to one
|
||||
|
|
|
@ -126,7 +126,7 @@ char const* tr_getDefaultDownloadDir(void);
|
|||
#define TR_DEFAULT_RPC_PORT 9091
|
||||
#define TR_DEFAULT_RPC_URL_STR "/transmission/"
|
||||
#define TR_DEFAULT_PEER_PORT_STR "51413"
|
||||
#define TR_DEFAULT_PEER_SOCKET_TOS_STR "default"
|
||||
#define TR_DEFAULT_PEER_SOCKET_TOS_STR "le"
|
||||
#define TR_DEFAULT_PEER_LIMIT_GLOBAL_STR "200"
|
||||
#define TR_DEFAULT_PEER_LIMIT_TORRENT_STR "50"
|
||||
#define TR_DEFAULT_PEER_LIMIT_TORRENT 50
|
||||
|
|
|
@ -129,7 +129,7 @@ std::array<Prefs::PrefItem, Prefs::PREFS_COUNT> const Prefs::Items{
|
|||
{ QUEUE_STALLED_MINUTES, TR_KEY_queue_stalled_minutes, QVariant::Int },
|
||||
{ SCRIPT_TORRENT_DONE_ENABLED, TR_KEY_script_torrent_done_enabled, QVariant::Bool },
|
||||
{ SCRIPT_TORRENT_DONE_FILENAME, TR_KEY_script_torrent_done_filename, QVariant::String },
|
||||
{ SOCKET_TOS, TR_KEY_peer_socket_tos, QVariant::Int },
|
||||
{ SOCKET_TOS, TR_KEY_peer_socket_tos, QVariant::String },
|
||||
{ START, TR_KEY_start_added_torrents, QVariant::Bool },
|
||||
{ TRASH_ORIGINAL, TR_KEY_trash_original_torrent_files, QVariant::Bool },
|
||||
{ PEX_ENABLED, TR_KEY_pex_enabled, QVariant::Bool },
|
||||
|
|
Loading…
Reference in New Issue