Skip to content

Commit

Permalink
feat: add preferred-transport to settings.json (transmission#5939)
Browse files Browse the repository at this point in the history
  • Loading branch information
tearfur authored Sep 16, 2023
1 parent 9a82372 commit 85a120f
Show file tree
Hide file tree
Showing 10 changed files with 164 additions and 24 deletions.
5 changes: 3 additions & 2 deletions docs/Editing-Configuration-Files.md
Original file line number Diff line number Diff line change
Expand Up @@ -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).
Expand All @@ -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".
Expand Down
66 changes: 46 additions & 20 deletions libtransmission/peer-io.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <array>
#include <cerrno>
#include <cstdint>
#include <type_traits>

#ifdef _WIN32
#include <ws2tcpip.h>
Expand All @@ -19,6 +20,8 @@

#include <fmt/core.h>

#include <small/map.hpp>

#include "libtransmission/transmission.h"

#include "libtransmission/bandwidth.h"
Expand Down Expand Up @@ -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())
Expand All @@ -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 });

auto const [ss, sslen] = socket_address.to_sockaddr();
if (utp_connect(sock, reinterpret_cast<sockaddr const*>(&ss), sslen) == 0)
{
return peer_io;
}
}
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 true;
}
}
#endif

if (!peer_io->socket_.is_valid())
{
if (auto sock = tr_netOpenPeerSocket(session, socket_address, is_seed); sock.is_valid())
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 (func.at(preferred)())
{
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;
}
}
Expand Down
8 changes: 8 additions & 0 deletions libtransmission/peer-io.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion libtransmission/peer-mgr.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion libtransmission/quark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
1 change: 1 addition & 0 deletions libtransmission/quark.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions libtransmission/session-settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down
5 changes: 5 additions & 0 deletions libtransmission/session.h
Original file line number Diff line number Diff line change
Expand Up @@ -783,6 +783,11 @@ struct tr_session

[[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;
Expand Down
55 changes: 55 additions & 0 deletions libtransmission/variant-converters.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
{
Expand Down
41 changes: 41 additions & 0 deletions tests/libtransmission/settings-test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 85a120f

Please sign in to comment.