feat: add `preferred-transport` to settings.json (#5939)

This commit is contained in:
Yat Ho 2023-09-16 09:23:34 +08:00 committed by GitHub
parent 9a82372e95
commit 85a120faea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 161 additions and 21 deletions

View File

@ -78,7 +78,7 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri
* **encryption:** Number (0 = Prefer unencrypted connections, 1 = Prefer encrypted connections, 2 = Require encrypted connections; default = 1) [Encryption](https://wiki.vuze.com/w/Message_Stream_Encryption) preference. Encryption may help get around some ISP filtering, but at the cost of slightly higher CPU use.
* **lazy-bitfield-enabled:** Boolean (default = true) May help get around some ISP filtering. [Vuze specification](https://wiki.vuze.com/w/Commandline_options#Network_Options).
* **lpd-enabled:** Boolean (default = false) Enable [Local Peer Discovery (LPD)](https://en.wikipedia.org/wiki/Local_Peer_Discovery).
* **message-level:** Number (0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace, default = 2) Set verbosity of Transmission's log messages.
* **message-level:** Number (0 = None, 1 = Critical, 2 = Error, 3 = Warn, 4 = Info, 5 = Debug, 6 = Trace; default = 2) Set verbosity of Transmission's log messages.
* **pex-enabled:** Boolean (default = true) Enable [Peer Exchange (PEX)](https://en.wikipedia.org/wiki/Peer_exchange).
* **pidfile:** String Path to file in which daemon PID will be stored (transmission-daemon only)
* **prefetch-enabled:** Boolean (default = true). When enabled, Transmission will hint to the OS which piece data it's about to read from disk in order to satisfy requests from peers. On Linux, this is done by passing `POSIX_FADV_WILLNEED` to [posix_fadvise()](https://www.kernel.org/doc/man-pages/online/pages/man2/posix_fadvise.2.html). On macOS, this is done by passing `F_RDADVISE` to [fcntl()](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/fcntl.2.html).
@ -89,9 +89,10 @@ Here is a sample of the three basic types: respectively Boolean, Number and Stri
* **script-torrent-done-filename:** String (default = "") Path to script.
* **script-torrent-done-seeding-enabled:** Boolean (default = false) Run a script when a torrent is done seeding. Environmental variables are passed in as detailed on the [Scripts](./Scripts.md) page
* **script-torrent-done-seeding-filename:** String (default = "") Path to script.
* **tcp-enabled:** Boolean (default = true) Optionally disable TCP connection to other peers. Never disable TCP when you also disable UTP, because then your client would not be able to communicate. Disabling TCP might also break webseeds. Unless you have a good reason, you should not set this to false.
* **tcp-enabled:** Boolean (default = true) Optionally disable TCP connection to other peers. Never disable TCP when you also disable µTP, because then your client would not be able to communicate. Disabling TCP might also break webseeds. Unless you have a good reason, you should not set this to false.
* **torrent-added-verify-mode:** String ("fast", "full", default: "fast") Whether newly-added torrents' local data should be fully verified when added, or wait and verify them on-demand later. See [#2626](https://github.com/transmission/transmission/pull/2626) for more discussion.
* **utp-enabled:** Boolean (default = true) Enable [Micro Transport Protocol (µTP)](https://en.wikipedia.org/wiki/Micro_Transport_Protocol)
* **preferred-transport:** String ("utp" = Prefer µTP, "tcp" = Prefer TCP; default = "utp") Choose your preferred transport protocol (has no effect if one of them is disabled).
#### Peers
* **bind-address-ipv4:** String (default = "0.0.0.0") Where to listen for peer connections. When no valid IPv4 address is provided, Transmission will bind to "0.0.0.0".

View File

@ -6,6 +6,7 @@
#include <array>
#include <cerrno>
#include <cstdint>
#include <type_traits>
#ifdef _WIN32
#include <ws2tcpip.h>
@ -19,6 +20,8 @@
#include <fmt/core.h>
#include <small/map.hpp>
#include "libtransmission/transmission.h"
#include "libtransmission/bandwidth.h"
@ -124,11 +127,12 @@ std::shared_ptr<tr_peerIo> tr_peerIo::new_outgoing(
bool is_seed,
bool utp)
{
auto const& [addr, port] = socket_address;
using preferred_key_t = std::underlying_type_t<tr_preferred_transport>;
auto const preferred = session->preferred_transport();
TR_ASSERT(!tr_peer_socket::limit_reached(session));
TR_ASSERT(session != nullptr);
TR_ASSERT(addr.is_valid());
TR_ASSERT(socket_address.is_valid());
TR_ASSERT(utp || session->allowsTCP());
if (!socket_address.is_valid_for_peers())
@ -137,27 +141,49 @@ std::shared_ptr<tr_peerIo> tr_peerIo::new_outgoing(
}
auto peer_io = tr_peerIo::create(session, parent, &info_hash, false, is_seed);
auto const func = small::max_size_map<preferred_key_t, std::function<bool()>, TR_NUM_PREFERRED_TRANSPORT>{
{ TR_PREFER_UTP,
[&]()
{
#ifdef WITH_UTP
if (utp)
{
auto* const sock = utp_create_socket(session->utp_context);
utp_set_userdata(sock, peer_io.get());
peer_io->set_socket(tr_peer_socket{ socket_address, sock });
if (utp)
{
auto* const sock = utp_create_socket(session->utp_context);
utp_set_userdata(sock, peer_io.get());
peer_io->set_socket(tr_peer_socket{ socket_address, sock });
auto const [ss, sslen] = socket_address.to_sockaddr();
if (utp_connect(sock, reinterpret_cast<sockaddr const*>(&ss), sslen) == 0)
{
return peer_io;
}
}
auto const [ss, sslen] = socket_address.to_sockaddr();
if (utp_connect(sock, reinterpret_cast<sockaddr const*>(&ss), sslen) == 0)
{
return true;
}
}
#endif
return false;
} },
{ TR_PREFER_TCP,
[&]()
{
if (!peer_io->socket_.is_valid())
{
if (auto sock = tr_netOpenPeerSocket(session, socket_address, is_seed); sock.is_valid())
{
peer_io->set_socket(std::move(sock));
return true;
}
}
return false;
} }
};
if (!peer_io->socket_.is_valid())
if (func.at(preferred)())
{
if (auto sock = tr_netOpenPeerSocket(session, socket_address, is_seed); sock.is_valid())
return peer_io;
}
for (preferred_key_t i = 0U; i < TR_NUM_PREFERRED_TRANSPORT; ++i)
{
if (i != preferred && func.at(i)())
{
peer_io->set_socket(std::move(sock));
return peer_io;
}
}

View File

@ -45,6 +45,14 @@ enum ReadState
READ_ERR
};
enum tr_preferred_transport : uint8_t
{
// More preferred transports goes on top
TR_PREFER_UTP,
TR_PREFER_TCP,
TR_NUM_PREFERRED_TRANSPORT
};
class tr_peerIo final : public std::enable_shared_from_this<tr_peerIo>
{
using DH = tr_message_stream_encryption::DH;

View File

@ -1349,7 +1349,7 @@ std::vector<tr_pex> tr_peerMgrGetPeers(tr_torrent const* tor, uint8_t address_ty
for (auto const* const info : infos)
{
auto const& socket_address = info->listen_socket_address();
auto const& addr = socket_address.address();
[[maybe_unused]] auto const& addr = socket_address.address();
TR_ASSERT(addr.is_valid());
TR_ASSERT(addr.type == address_type);

View File

@ -16,7 +16,7 @@ using namespace std::literals;
namespace
{
auto constexpr MyStatic = std::array<std::string_view, 404>{ ""sv,
auto constexpr MyStatic = std::array<std::string_view, 405>{ ""sv,
"activeTorrentCount"sv,
"activity-date"sv,
"activityDate"sv,
@ -247,6 +247,7 @@ auto constexpr MyStatic = std::array<std::string_view, 404>{ ""sv,
"port-forwarding-enabled"sv,
"port-is-open"sv,
"preallocation"sv,
"preferred-transport"sv,
"prefetch-enabled"sv,
"primary-mime-type"sv,
"priorities"sv,

View File

@ -252,6 +252,7 @@ enum
TR_KEY_port_forwarding_enabled,
TR_KEY_port_is_open,
TR_KEY_preallocation,
TR_KEY_preferred_transport,
TR_KEY_prefetch_enabled,
TR_KEY_primary_mime_type,
TR_KEY_priorities,

View File

@ -12,6 +12,7 @@
#include "libtransmission/log.h" // for tr_log_level
#include "libtransmission/net.h" // for tr_port, tr_tos_t
#include "libtransmission/peer-io.h" // tr_preferred_transport
#include "libtransmission/quark.h"
struct tr_variant;
@ -76,6 +77,7 @@ struct tr_variant;
V(TR_KEY_umask, umask, tr_mode_t, 022, "") \
V(TR_KEY_upload_slots_per_torrent, upload_slots_per_torrent, size_t, 8U, "") \
V(TR_KEY_utp_enabled, utp_enabled, bool, true, "") \
V(TR_KEY_preferred_transport, preferred_transport, tr_preferred_transport, TR_PREFER_UTP, "") \
V(TR_KEY_torrent_added_verify_mode, torrent_added_verify_mode, tr_verify_added_mode, TR_VERIFY_ADDED_FAST, "")
struct tr_session_settings

View File

@ -783,6 +783,11 @@ public:
[[nodiscard]] bool allowsUTP() const noexcept;
[[nodiscard]] constexpr auto preferred_transport() const noexcept
{
return settings_.preferred_transport;
}
[[nodiscard]] constexpr auto allowsPrefetch() const noexcept
{
return settings_.is_prefetch_enabled;

View File

@ -17,6 +17,7 @@
#include "libtransmission/log.h" // for tr_log_level
#include "libtransmission/net.h" // for tr_port
#include "libtransmission/peer-io.h" // tr_preferred_transport
#include "libtransmission/utils.h" // for tr_strv_strip(), tr_strlower()
#include "libtransmission/variant.h"
@ -52,6 +53,12 @@ auto constexpr VerifyModeKeys = std::array<std::pair<std::string_view, tr_verify
{ "fast", TR_VERIFY_ADDED_FAST },
{ "full", TR_VERIFY_ADDED_FULL },
} };
auto constexpr PreferredTransportKeys = std::
array<std::pair<std::string_view, tr_preferred_transport>, TR_NUM_PREFERRED_TRANSPORT>{ {
{ "utp", TR_PREFER_UTP },
{ "tcp", TR_PREFER_TCP },
} };
} // namespace
namespace libtransmission
@ -260,6 +267,54 @@ tr_variant VariantConverter::save<tr_preallocation_mode>(tr_preallocation_mode c
// ---
template<>
std::optional<tr_preferred_transport> VariantConverter::load<tr_preferred_transport>(tr_variant const& src)
{
static constexpr auto Keys = PreferredTransportKeys;
if (auto const* val = src.get_if<std::string_view>(); val != nullptr)
{
auto const needle = tr_strlower(tr_strv_strip(*val));
for (auto const& [name, value] : Keys)
{
if (name == needle)
{
return value;
}
}
}
if (auto const* val = src.get_if<int64_t>(); val != nullptr)
{
for (auto const& [name, value] : Keys)
{
if (value == *val)
{
return value;
}
}
}
return {};
}
template<>
tr_variant VariantConverter::save<tr_preferred_transport>(tr_preferred_transport const& val)
{
for (auto const& [key, value] : PreferredTransportKeys)
{
if (value == val)
{
return key;
}
}
return static_cast<int64_t>(val);
}
// ---
template<>
std::optional<size_t> VariantConverter::load<size_t>(tr_variant const& src)
{

View File

@ -411,3 +411,44 @@ TEST_F(SettingsTest, canSaveVerify)
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ("full", val);
}
TEST_F(SettingsTest, canLoadPreferredTransport)
{
static auto constexpr Key = TR_KEY_preferred_transport;
auto constexpr ExpectedValue = TR_PREFER_TCP;
auto settings = std::make_unique<tr_session_settings>();
auto const default_value = settings->preferred_transport;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 1);
tr_variantDictAddInt(&var, Key, ExpectedValue);
settings->load(var);
EXPECT_EQ(ExpectedValue, settings->preferred_transport);
var.clear();
settings = std::make_unique<tr_session_settings>();
tr_variantInitDict(&var, 1);
tr_variantDictAddStrView(&var, Key, "tcp");
settings->load(var);
EXPECT_EQ(ExpectedValue, settings->preferred_transport);
}
TEST_F(SettingsTest, canSavePreferredTransport)
{
static auto constexpr Key = TR_KEY_preferred_transport;
static auto constexpr ExpectedValue = TR_PREFER_TCP;
auto settings = tr_session_settings{};
auto const default_value = settings.preferred_transport;
ASSERT_NE(ExpectedValue, default_value);
auto var = tr_variant{};
tr_variantInitDict(&var, 100);
settings.preferred_transport = ExpectedValue;
var = settings.settings();
auto val = std::string_view{};
EXPECT_TRUE(tr_variantDictFindStrView(&var, Key, &val));
EXPECT_EQ("tcp", val);
}