1010 lines
28 KiB
C++
1010 lines
28 KiB
C++
// This file Copyright © 2008-2022 Mnemosyne LLC.
|
|
// It may be used under GPLv2 (SPDX: GPL-2.0-only), GPLv3 (SPDX: GPL-3.0-only),
|
|
// or any future license endorsed by Mnemosyne LLC.
|
|
// License text can be found in the licenses/ folder.
|
|
|
|
#pragma once
|
|
|
|
#ifndef __TRANSMISSION__
|
|
#error only libtransmission should #include this header.
|
|
#endif
|
|
|
|
#define TR_NAME "Transmission"
|
|
|
|
#include <array>
|
|
#include <cstddef> // size_t
|
|
#include <cstdint> // uintX_t
|
|
#include <memory>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <string>
|
|
#include <string_view>
|
|
#include <tuple>
|
|
#include <utility> // std::pair
|
|
#include <vector>
|
|
|
|
#include "transmission.h"
|
|
|
|
#include "announce-list.h"
|
|
#include "bandwidth.h"
|
|
#include "bitfield.h"
|
|
#include "cache.h"
|
|
#include "interned-string.h"
|
|
#include "net.h" // tr_socket_t
|
|
#include "open-files.h"
|
|
#include "quark.h"
|
|
#include "session-id.h"
|
|
#include "stats.h"
|
|
#include "timer.h"
|
|
#include "torrents.h"
|
|
#include "tr-lpd.h"
|
|
#include "web.h"
|
|
#include "verify.h"
|
|
|
|
enum tr_auto_switch_state_t
|
|
{
|
|
TR_AUTO_SWITCH_UNUSED,
|
|
TR_AUTO_SWITCH_ON,
|
|
TR_AUTO_SWITCH_OFF,
|
|
};
|
|
|
|
tr_peer_id_t tr_peerIdInit();
|
|
|
|
struct event_base;
|
|
struct evdns_base;
|
|
|
|
class tr_rpc_server;
|
|
class tr_web;
|
|
class tr_lpd;
|
|
struct BlocklistFile;
|
|
struct struct_utp_context;
|
|
struct tr_announcer;
|
|
struct tr_announcer_udp;
|
|
|
|
namespace libtransmission::test
|
|
{
|
|
|
|
class SessionTest;
|
|
|
|
} // namespace libtransmission::test
|
|
|
|
struct tr_bindinfo
|
|
{
|
|
explicit tr_bindinfo(tr_address addr)
|
|
: addr_{ std::move(addr) }
|
|
{
|
|
}
|
|
|
|
void bindAndListenForIncomingPeers(tr_session* session);
|
|
|
|
void close();
|
|
|
|
[[nodiscard]] auto readable() const
|
|
{
|
|
return addr_.readable();
|
|
}
|
|
|
|
tr_address addr_;
|
|
struct event* ev_ = nullptr;
|
|
tr_socket_t socket_ = TR_BAD_SOCKET;
|
|
};
|
|
|
|
struct tr_turtle_info
|
|
{
|
|
/* TR_UP and TR_DOWN speed limits */
|
|
std::array<unsigned int, 2> speedLimit_Bps = {};
|
|
|
|
/* is turtle mode on right now? */
|
|
bool isEnabled = false;
|
|
|
|
/* does turtle mode turn itself on and off at given times? */
|
|
bool isClockEnabled = false;
|
|
|
|
/* when clock mode is on, minutes after midnight to turn on turtle mode */
|
|
int beginMinute = 0;
|
|
|
|
/* when clock mode is on, minutes after midnight to turn off turtle mode */
|
|
int endMinute = 0;
|
|
|
|
/* only use clock mode on these days of the week */
|
|
tr_sched_day days = {};
|
|
|
|
/* called when isEnabled changes */
|
|
tr_altSpeedFunc callback = nullptr;
|
|
|
|
/* the callback's user_data argument */
|
|
void* callbackUserData = nullptr;
|
|
|
|
/* the callback's changedByUser argument.
|
|
* indicates whether the change came from the user or from the clock. */
|
|
bool changedByUser = false;
|
|
|
|
/* bitfield of all the minutes in a week.
|
|
* Each bit's value indicates whether the scheduler wants turtle
|
|
* limits on or off at that given minute in the week. */
|
|
tr_bitfield minutes{ 10080 };
|
|
|
|
/* recent action that was done by turtle's automatic switch */
|
|
tr_auto_switch_state_t autoTurtleState = TR_AUTO_SWITCH_UNUSED;
|
|
};
|
|
|
|
/** @brief handle to an active libtransmission session */
|
|
struct tr_session
|
|
{
|
|
public:
|
|
explicit tr_session(std::string_view config_dir);
|
|
|
|
[[nodiscard]] std::string_view sessionId() const noexcept
|
|
{
|
|
return session_id_.sv();
|
|
}
|
|
|
|
[[nodiscard]] event_base* eventBase() noexcept
|
|
{
|
|
return event_base_.get();
|
|
}
|
|
|
|
[[nodiscard]] evdns_base* evdnsBase() noexcept
|
|
{
|
|
return evdns_base_.get();
|
|
}
|
|
|
|
[[nodiscard]] auto& timerMaker() noexcept
|
|
{
|
|
return *timer_maker_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto& torrents()
|
|
{
|
|
return torrents_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& torrents() const
|
|
{
|
|
return torrents_;
|
|
}
|
|
|
|
[[nodiscard]] auto unique_lock() const
|
|
{
|
|
return std::unique_lock(session_mutex_);
|
|
}
|
|
|
|
// paths
|
|
|
|
[[nodiscard]] constexpr auto const& configDir() const noexcept
|
|
{
|
|
return config_dir_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& torrentDir() const noexcept
|
|
{
|
|
return torrent_dir_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& resumeDir() const noexcept
|
|
{
|
|
return resume_dir_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& downloadDir() const noexcept
|
|
{
|
|
return download_dir_;
|
|
}
|
|
|
|
void setDownloadDir(std::string_view dir)
|
|
{
|
|
download_dir_ = dir;
|
|
}
|
|
|
|
// default trackers
|
|
// (trackers to apply automatically to public torrents)
|
|
|
|
[[nodiscard]] constexpr auto const& defaultTrackersStr() const noexcept
|
|
{
|
|
return default_trackers_str_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& defaultTrackers() const noexcept
|
|
{
|
|
return default_trackers_;
|
|
}
|
|
|
|
void setDefaultTrackers(std::string_view trackers);
|
|
|
|
// incomplete dir
|
|
|
|
[[nodiscard]] constexpr auto const& incompleteDir() const noexcept
|
|
{
|
|
return incomplete_dir_;
|
|
}
|
|
|
|
void setIncompleteDir(std::string_view dir)
|
|
{
|
|
incomplete_dir_ = dir;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto useIncompleteDir() const noexcept
|
|
{
|
|
return incomplete_dir_enabled_;
|
|
}
|
|
|
|
constexpr void useIncompleteDir(bool enabled) noexcept
|
|
{
|
|
incomplete_dir_enabled_ = enabled;
|
|
}
|
|
|
|
// scripts
|
|
|
|
constexpr void useScript(TrScript i, bool enabled)
|
|
{
|
|
scripts_enabled_[i] = enabled;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto useScript(TrScript i) const
|
|
{
|
|
return scripts_enabled_[i];
|
|
}
|
|
|
|
void setScript(TrScript i, std::string_view path)
|
|
{
|
|
scripts_[i] = path;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& script(TrScript i) const
|
|
{
|
|
return scripts_[i];
|
|
}
|
|
|
|
// blocklist
|
|
|
|
[[nodiscard]] constexpr auto useBlocklist() const noexcept
|
|
{
|
|
return blocklist_enabled_;
|
|
}
|
|
|
|
void useBlocklist(bool enabled);
|
|
|
|
[[nodiscard]] constexpr auto const& blocklistUrl() const noexcept
|
|
{
|
|
return blocklist_url_;
|
|
}
|
|
|
|
void setBlocklistUrl(std::string_view url)
|
|
{
|
|
blocklist_url_ = url;
|
|
}
|
|
|
|
// RPC
|
|
|
|
void setRpcWhitelist(std::string_view whitelist) const;
|
|
|
|
void useRpcWhitelist(bool enabled) const;
|
|
|
|
[[nodiscard]] bool useRpcWhitelist() const;
|
|
|
|
[[nodiscard]] constexpr auto externalIP() const noexcept
|
|
{
|
|
return external_ip_;
|
|
}
|
|
|
|
void setExternalIP(tr_address external_ip)
|
|
{
|
|
external_ip_ = external_ip;
|
|
}
|
|
|
|
// peer networking
|
|
|
|
[[nodiscard]] constexpr auto const& peerCongestionAlgorithm() const noexcept
|
|
{
|
|
return peer_congestion_algorithm_;
|
|
}
|
|
|
|
void setPeerCongestionAlgorithm(std::string_view algorithm)
|
|
{
|
|
peer_congestion_algorithm_ = algorithm;
|
|
}
|
|
|
|
void setSocketTOS(tr_socket_t sock, tr_address_type type) const
|
|
{
|
|
tr_netSetTOS(sock, peer_socket_tos_, type);
|
|
}
|
|
|
|
[[nodiscard]] constexpr bool incPeerCount() noexcept
|
|
{
|
|
if (this->peer_count_ >= this->peer_limit_)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
++this->peer_count_;
|
|
return true;
|
|
}
|
|
|
|
constexpr void decPeerCount() noexcept
|
|
{
|
|
if (this->peer_count_ > 0)
|
|
{
|
|
--this->peer_count_;
|
|
}
|
|
}
|
|
|
|
// bandwidth
|
|
|
|
[[nodiscard]] tr_bandwidth& getBandwidthGroup(std::string_view name);
|
|
|
|
//
|
|
|
|
[[nodiscard]] constexpr auto& openFiles() noexcept
|
|
{
|
|
return open_files_;
|
|
}
|
|
|
|
void closeTorrentFiles(tr_torrent* tor) noexcept;
|
|
void closeTorrentFile(tr_torrent* tor, tr_file_index_t file_num) noexcept;
|
|
|
|
// announce ip
|
|
|
|
[[nodiscard]] constexpr auto const& announceIP() const noexcept
|
|
{
|
|
return announce_ip_;
|
|
}
|
|
|
|
void setAnnounceIP(std::string_view ip)
|
|
{
|
|
announce_ip_ = ip;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto useAnnounceIP() const noexcept
|
|
{
|
|
return announce_ip_enabled_;
|
|
}
|
|
|
|
constexpr void useAnnounceIP(bool enabled) noexcept
|
|
{
|
|
announce_ip_enabled_ = enabled;
|
|
}
|
|
|
|
// callbacks
|
|
|
|
using queue_start_callback_t = void (*)(tr_session*, tr_torrent*, void* user_data);
|
|
|
|
constexpr void setQueueStartCallback(queue_start_callback_t cb, void* user_data)
|
|
{
|
|
queue_start_callback_ = cb;
|
|
queue_start_user_data_ = user_data;
|
|
}
|
|
|
|
void onQueuedTorrentStarted(tr_torrent* tor)
|
|
{
|
|
if (queue_start_callback_ != nullptr)
|
|
{
|
|
queue_start_callback_(this, tor, queue_start_user_data_);
|
|
}
|
|
}
|
|
|
|
constexpr void setIdleLimitHitCallback(tr_session_idle_limit_hit_func cb, void* user_data)
|
|
{
|
|
idle_limit_hit_callback_ = cb;
|
|
idle_limit_hit_user_data_ = user_data;
|
|
}
|
|
|
|
void onIdleLimitHit(tr_torrent* tor)
|
|
{
|
|
if (idle_limit_hit_callback_ != nullptr)
|
|
{
|
|
idle_limit_hit_callback_(this, tor, idle_limit_hit_user_data_);
|
|
}
|
|
}
|
|
|
|
constexpr void setRatioLimitHitCallback(tr_session_ratio_limit_hit_func cb, void* user_data)
|
|
{
|
|
ratio_limit_hit_cb_ = cb;
|
|
ratio_limit_hit_user_data_ = user_data;
|
|
}
|
|
|
|
void onRatioLimitHit(tr_torrent* tor)
|
|
{
|
|
if (ratio_limit_hit_cb_ != nullptr)
|
|
{
|
|
ratio_limit_hit_cb_(this, tor, ratio_limit_hit_user_data_);
|
|
}
|
|
}
|
|
|
|
constexpr void setMetadataCallback(tr_session_metadata_func cb, void* user_data)
|
|
{
|
|
got_metadata_cb_ = cb;
|
|
got_metadata_user_data_ = user_data;
|
|
}
|
|
|
|
void onMetadataCompleted(tr_torrent* tor)
|
|
{
|
|
if (got_metadata_cb_ != nullptr)
|
|
{
|
|
got_metadata_cb_(this, tor, got_metadata_user_data_);
|
|
}
|
|
}
|
|
|
|
constexpr void setTorrentCompletenessCallback(tr_torrent_completeness_func cb, void* user_data)
|
|
{
|
|
completeness_func_ = cb;
|
|
completeness_func_user_data_ = user_data;
|
|
}
|
|
|
|
void onTorrentCompletenessChanged(tr_torrent* tor, tr_completeness completeness, bool was_running)
|
|
{
|
|
if (completeness_func_ != nullptr)
|
|
{
|
|
completeness_func_(tor, completeness, was_running, completeness_func_user_data_);
|
|
}
|
|
}
|
|
|
|
/// stats
|
|
|
|
[[nodiscard]] constexpr auto& stats() noexcept
|
|
{
|
|
return session_stats_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto const& stats() const noexcept
|
|
{
|
|
return session_stats_;
|
|
}
|
|
|
|
void addUploaded(uint32_t n_bytes) noexcept
|
|
{
|
|
session_stats_.addUploaded(n_bytes);
|
|
}
|
|
|
|
void addDownloaded(uint32_t n_bytes) noexcept
|
|
{
|
|
session_stats_.addDownloaded(n_bytes);
|
|
}
|
|
|
|
void addFileCreated() noexcept
|
|
{
|
|
session_stats_.addFileCreated();
|
|
}
|
|
|
|
public:
|
|
static constexpr std::array<std::tuple<tr_quark, tr_quark, TrScript>, 3> Scripts{
|
|
{ { TR_KEY_script_torrent_added_enabled, TR_KEY_script_torrent_added_filename, TR_SCRIPT_ON_TORRENT_ADDED },
|
|
{ TR_KEY_script_torrent_done_enabled, TR_KEY_script_torrent_done_filename, TR_SCRIPT_ON_TORRENT_DONE },
|
|
{ TR_KEY_script_torrent_done_seeding_enabled,
|
|
TR_KEY_script_torrent_done_seeding_filename,
|
|
TR_SCRIPT_ON_TORRENT_DONE_SEEDING } }
|
|
};
|
|
|
|
struct tr_turtle_info turtle;
|
|
|
|
struct tr_event_handle* events = nullptr;
|
|
|
|
// UDP connectivity used for the DHT and uTP
|
|
class tr_udp_core
|
|
{
|
|
public:
|
|
tr_udp_core(tr_session& session);
|
|
|
|
~tr_udp_core();
|
|
|
|
void set_socket_buffers();
|
|
|
|
void set_socket_tos()
|
|
{
|
|
session_.setSocketTOS(udp_socket_, TR_AF_INET);
|
|
session_.setSocketTOS(udp6_socket_, TR_AF_INET6);
|
|
}
|
|
|
|
void sendto(void const* buf, size_t buflen, struct sockaddr const* to, socklen_t const tolen) const;
|
|
|
|
[[nodiscard]] constexpr auto port() const noexcept
|
|
{
|
|
return udp_port_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto udp_socket() const noexcept
|
|
{
|
|
return udp_socket_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto udp6_socket() const noexcept
|
|
{
|
|
return udp6_socket_;
|
|
}
|
|
|
|
private:
|
|
tr_port udp_port_ = {};
|
|
tr_session& session_;
|
|
struct event* udp_event_ = nullptr;
|
|
struct event* udp6_event_ = nullptr;
|
|
std::optional<in6_addr> udp6_bound_;
|
|
tr_socket_t udp_socket_ = TR_BAD_SOCKET;
|
|
tr_socket_t udp6_socket_ = TR_BAD_SOCKET;
|
|
|
|
void rebind_ipv6(bool);
|
|
};
|
|
|
|
std::unique_ptr<tr_udp_core> udp_core_;
|
|
|
|
/* The open port on the local machine for incoming peer requests */
|
|
tr_port private_peer_port;
|
|
|
|
/**
|
|
* The open port on the public device for incoming peer requests.
|
|
* This is usually the same as private_peer_port but can differ
|
|
* if the public device is a router and it decides to use a different
|
|
* port than the one requested by Transmission.
|
|
*/
|
|
tr_port public_peer_port;
|
|
|
|
[[nodiscard]] constexpr auto peerPort() const noexcept
|
|
{
|
|
return public_peer_port;
|
|
}
|
|
|
|
constexpr auto setPeerPort(tr_port port) noexcept
|
|
{
|
|
public_peer_port = port;
|
|
}
|
|
|
|
struct tr_peerMgr* peerMgr = nullptr;
|
|
struct tr_shared* shared = nullptr;
|
|
|
|
std::unique_ptr<Cache> cache;
|
|
|
|
std::unique_ptr<tr_web> web;
|
|
std::unique_ptr<tr_lpd> lpd_;
|
|
|
|
struct tr_announcer* announcer = nullptr;
|
|
struct tr_announcer_udp* announcer_udp = nullptr;
|
|
|
|
// monitors the "global pool" speeds
|
|
tr_bandwidth top_bandwidth_;
|
|
|
|
std::vector<std::pair<tr_interned_string, std::unique_ptr<tr_bandwidth>>> bandwidth_groups_;
|
|
|
|
tr_bindinfo bind_ipv4 = tr_bindinfo{ tr_inaddr_any };
|
|
tr_bindinfo bind_ipv6 = tr_bindinfo{ tr_in6addr_any };
|
|
|
|
[[nodiscard]] constexpr auto queueEnabled(tr_direction dir) const noexcept
|
|
{
|
|
return queue_enabled_[dir];
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto queueSize(tr_direction dir) const noexcept
|
|
{
|
|
return queue_size_[dir];
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto queueStalledEnabled() const noexcept
|
|
{
|
|
return queue_stalled_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto queueStalledMinutes() const noexcept
|
|
{
|
|
return queue_stalled_minutes_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto peerLimit() const noexcept
|
|
{
|
|
return peer_limit_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto peerLimitPerTorrent() const noexcept
|
|
{
|
|
return peer_limit_per_torrent_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto uploadSlotsPerTorrent() const noexcept
|
|
{
|
|
return upload_slots_per_torrent_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isClosing() const noexcept
|
|
{
|
|
return is_closing_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isClosed() const noexcept
|
|
{
|
|
return is_closed_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto encryptionMode() const noexcept
|
|
{
|
|
return encryption_mode_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto preallocationMode() const noexcept
|
|
{
|
|
return preallocation_mode_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto shouldScrapePausedTorrents() const noexcept
|
|
{
|
|
return should_scrape_paused_torrents_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto shouldPauseAddedTorrents() const noexcept
|
|
{
|
|
return should_pause_added_torrents_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto shouldDeleteSource() const noexcept
|
|
{
|
|
return should_delete_source_torrents_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto allowsDHT() const noexcept
|
|
{
|
|
return is_dht_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto allowsLPD() const noexcept
|
|
{
|
|
return is_lpd_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto allowsPEX() const noexcept
|
|
{
|
|
return is_pex_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto allowsTCP() const noexcept
|
|
{
|
|
return is_tcp_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] bool allowsUTP() const noexcept;
|
|
|
|
[[nodiscard]] constexpr auto allowsPrefetch() const noexcept
|
|
{
|
|
return is_prefetch_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isIdleLimited() const noexcept
|
|
{
|
|
return is_idle_limited_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto idleLimitMinutes() const noexcept
|
|
{
|
|
return idle_limit_minutes_;
|
|
}
|
|
|
|
[[nodiscard]] std::vector<tr_torrent*> getAllTorrents() const
|
|
{
|
|
return std::vector<tr_torrent*>{ std::begin(torrents()), std::end(torrents()) };
|
|
}
|
|
|
|
/*module_visible*/
|
|
|
|
auto rpcNotify(tr_rpc_callback_type type, tr_torrent* tor = nullptr)
|
|
{
|
|
if (rpc_func_ != nullptr)
|
|
{
|
|
return (*rpc_func_)(this, type, tor, rpc_func_user_data_);
|
|
}
|
|
|
|
return TR_RPC_OK;
|
|
}
|
|
|
|
[[nodiscard]] size_t countQueueFreeSlots(tr_direction dir) const noexcept;
|
|
|
|
[[nodiscard]] std::vector<tr_torrent*> getNextQueuedTorrents(tr_direction dir, size_t num_wanted) const;
|
|
|
|
[[nodiscard]] bool addressIsBlocked(tr_address const& addr) const noexcept;
|
|
|
|
struct PublicAddressResult
|
|
{
|
|
tr_address address;
|
|
bool is_default_value;
|
|
};
|
|
|
|
[[nodiscard]] PublicAddressResult publicAddress(tr_address_type type) const noexcept;
|
|
|
|
[[nodiscard]] constexpr auto speedLimitBps(tr_direction dir) const noexcept
|
|
{
|
|
return speed_limit_Bps_[dir];
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isSpeedLimited(tr_direction dir) const noexcept
|
|
{
|
|
return speed_limit_enabled_[dir];
|
|
}
|
|
|
|
[[nodiscard]] auto pieceSpeedBps(tr_direction dir) const noexcept
|
|
{
|
|
return top_bandwidth_.getPieceSpeedBytesPerSecond(0, dir);
|
|
}
|
|
|
|
[[nodiscard]] std::optional<unsigned int> activeSpeedLimitBps(tr_direction dir) const noexcept;
|
|
|
|
[[nodiscard]] constexpr auto isIncompleteFileNamingEnabled() const noexcept
|
|
{
|
|
return is_incomplete_file_naming_enabled_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isPortRandom() const noexcept
|
|
{
|
|
return is_port_random_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto isRatioLimited() const noexcept
|
|
{
|
|
return is_ratio_limited_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto desiredRatio() const noexcept
|
|
{
|
|
return desired_ratio_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr auto peerIdTTLHours() const noexcept
|
|
{
|
|
return peer_id_ttl_hours_;
|
|
}
|
|
|
|
void verifyRemove(tr_torrent* tor)
|
|
{
|
|
if (verifier_)
|
|
{
|
|
verifier_->remove(tor);
|
|
}
|
|
}
|
|
|
|
void verifyAdd(tr_torrent* tor)
|
|
{
|
|
if (verifier_)
|
|
{
|
|
verifier_->add(tor);
|
|
}
|
|
}
|
|
|
|
private:
|
|
[[nodiscard]] tr_port randomPort() const;
|
|
|
|
void loadBlocklists();
|
|
|
|
struct init_data;
|
|
void initImpl(init_data&);
|
|
void setImpl(init_data&);
|
|
void closeImplStart();
|
|
void closeImplWaitForIdleUdp();
|
|
void closeImplFinish();
|
|
|
|
friend class libtransmission::test::SessionTest;
|
|
friend bool tr_blocklistExists(tr_session const* session);
|
|
friend bool tr_sessionGetAntiBruteForceEnabled(tr_session const* session);
|
|
friend bool tr_sessionIsRPCEnabled(tr_session const* session);
|
|
friend bool tr_sessionIsRPCPasswordEnabled(tr_session const* session);
|
|
friend char const* tr_sessionGetRPCPassword(tr_session const* session);
|
|
friend char const* tr_sessionGetRPCUsername(tr_session const* session);
|
|
friend char const* tr_sessionGetRPCWhitelist(tr_session const* session);
|
|
friend int tr_sessionGetAntiBruteForceThreshold(tr_session const* session);
|
|
friend size_t tr_blocklistGetRuleCount(tr_session const* session);
|
|
friend size_t tr_blocklistSetContent(tr_session* session, char const* content_filename);
|
|
friend tr_session* tr_sessionInit(char const* config_dir, bool message_queueing_enabled, tr_variant* client_settings);
|
|
friend uint16_t tr_sessionGetRPCPort(tr_session const* session);
|
|
friend uint16_t tr_sessionSetPeerPortRandom(tr_session* session);
|
|
friend void tr_sessionClose(tr_session* session);
|
|
friend void tr_sessionGetSettings(tr_session const* s, tr_variant* setme_dictionary);
|
|
friend void tr_sessionLimitSpeed(tr_session* session, tr_direction dir, bool limited);
|
|
friend void tr_sessionReloadBlocklists(tr_session* session);
|
|
friend void tr_sessionSet(tr_session* session, tr_variant* settings);
|
|
friend void tr_sessionSetAntiBruteForceEnabled(tr_session* session, bool is_enabled);
|
|
friend void tr_sessionSetAntiBruteForceThreshold(tr_session* session, int max_bad_requests);
|
|
friend void tr_sessionSetDHTEnabled(tr_session* session, bool enabled);
|
|
friend void tr_sessionSetDeleteSource(tr_session* session, bool delete_source);
|
|
friend void tr_sessionSetEncryption(tr_session* session, tr_encryption_mode mode);
|
|
friend void tr_sessionSetIdleLimit(tr_session* session, uint16_t idle_minutes);
|
|
friend void tr_sessionSetIdleLimited(tr_session* session, bool is_limited);
|
|
friend void tr_sessionSetIncompleteFileNamingEnabled(tr_session* session, bool enabled);
|
|
friend void tr_sessionSetLPDEnabled(tr_session* session, bool enabled);
|
|
friend void tr_sessionSetPaused(tr_session* session, bool is_paused);
|
|
friend void tr_sessionSetPeerLimit(tr_session* session, uint16_t max_global_peers);
|
|
friend void tr_sessionSetPeerLimitPerTorrent(tr_session* session, uint16_t max_peers);
|
|
friend void tr_sessionSetPeerPortRandomOnStart(tr_session* session, bool random);
|
|
friend void tr_sessionSetPexEnabled(tr_session* session, bool enabled);
|
|
friend void tr_sessionSetQueueEnabled(tr_session* session, tr_direction dir, bool do_limit_simultaneous_seed_torrents);
|
|
friend void tr_sessionSetQueueSize(tr_session* session, tr_direction dir, int max_simultaneous_seed_torrents);
|
|
friend void tr_sessionSetQueueStalledEnabled(tr_session* session, bool is_enabled);
|
|
friend void tr_sessionSetQueueStalledMinutes(tr_session* session, int minutes);
|
|
friend void tr_sessionSetRPCCallback(tr_session* session, tr_rpc_func func, void* user_data);
|
|
friend void tr_sessionSetRPCEnabled(tr_session* session, bool is_enabled);
|
|
friend void tr_sessionSetRPCPassword(tr_session* session, char const* password);
|
|
friend void tr_sessionSetRPCPasswordEnabled(tr_session* session, bool enabled);
|
|
friend void tr_sessionSetRPCPort(tr_session* session, uint16_t hport);
|
|
friend void tr_sessionSetRPCUsername(tr_session* session, char const* username);
|
|
friend void tr_sessionSetRatioLimit(tr_session* session, double desired_ratio);
|
|
friend void tr_sessionSetRatioLimited(tr_session* session, bool is_limited);
|
|
friend void tr_sessionSetSpeedLimit_Bps(tr_session* session, tr_direction dir, unsigned int bytes_per_second);
|
|
friend void tr_sessionSetUTPEnabled(tr_session* session, bool enabled);
|
|
|
|
static std::recursive_mutex session_mutex_;
|
|
|
|
std::vector<std::unique_ptr<BlocklistFile>> blocklists_;
|
|
|
|
std::unique_ptr<tr_rpc_server> rpc_server_;
|
|
|
|
tr_announce_list default_trackers_;
|
|
|
|
tr_session_id session_id_;
|
|
|
|
std::array<unsigned int, 2> speed_limit_Bps_ = { 0U, 0U };
|
|
std::array<bool, 2> speed_limit_enabled_ = { false, false };
|
|
|
|
std::array<bool, 2> queue_enabled_ = { false, false };
|
|
std::array<int, 2> queue_size_ = { 0, 0 };
|
|
|
|
tr_rpc_func rpc_func_ = nullptr;
|
|
void* rpc_func_user_data_ = nullptr;
|
|
|
|
float desired_ratio_ = 2.0F;
|
|
|
|
int umask_ = 022;
|
|
|
|
// One of <netinet/ip.h>'s IPTOS_ values.
|
|
// See tr_netTos*() in libtransmission/net.h for more info
|
|
int peer_socket_tos_ = *tr_netTosFromName(TR_DEFAULT_PEER_SOCKET_TOS_STR);
|
|
|
|
int queue_stalled_minutes_ = 0;
|
|
|
|
tr_encryption_mode encryption_mode_ = TR_ENCRYPTION_PREFERRED;
|
|
|
|
tr_preallocation_mode preallocation_mode_ = TR_PREALLOCATE_SPARSE;
|
|
|
|
tr_port random_port_low_;
|
|
tr_port random_port_high_;
|
|
|
|
uint16_t peer_count_ = 0;
|
|
uint16_t peer_limit_ = 200;
|
|
uint16_t peer_limit_per_torrent_ = 50;
|
|
|
|
uint16_t idle_limit_minutes_ = 0;
|
|
|
|
uint16_t upload_slots_per_torrent_ = 8;
|
|
|
|
uint8_t peer_id_ttl_hours_ = 6;
|
|
|
|
bool is_closing_ = false;
|
|
bool is_closed_ = false;
|
|
|
|
bool is_utp_enabled_ = false;
|
|
bool is_pex_enabled_ = false;
|
|
bool is_dht_enabled_ = false;
|
|
bool is_lpd_enabled_ = false;
|
|
bool is_tcp_enabled_ = true;
|
|
|
|
bool is_idle_limited_ = false;
|
|
bool is_prefetch_enabled_ = false;
|
|
bool is_ratio_limited_ = false;
|
|
bool queue_stalled_enabled_ = false;
|
|
|
|
bool is_port_random_ = false;
|
|
|
|
bool should_pause_added_torrents_ = false;
|
|
bool should_delete_source_torrents_ = false;
|
|
bool should_scrape_paused_torrents_ = false;
|
|
bool is_incomplete_file_naming_enabled_ = false;
|
|
|
|
class WebMediator final : public tr_web::Mediator
|
|
{
|
|
public:
|
|
explicit WebMediator(tr_session* session)
|
|
: session_{ session }
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] std::optional<std::string> cookieFile() const override;
|
|
[[nodiscard]] std::optional<std::string> publicAddressV4() const override;
|
|
[[nodiscard]] std::optional<std::string> publicAddressV6() const override;
|
|
[[nodiscard]] std::optional<std::string_view> userAgent() const override;
|
|
[[nodiscard]] unsigned int clamp(int torrent_id, unsigned int byte_count) const override;
|
|
void notifyBandwidthConsumed(int torrent_id, size_t byte_count) override;
|
|
// runs the tr_web::fetch response callback in the libtransmission thread
|
|
void run(tr_web::FetchDoneFunc&& func, tr_web::FetchResponse&& response) const override;
|
|
|
|
private:
|
|
tr_session* const session_;
|
|
};
|
|
|
|
WebMediator web_mediator_{ this };
|
|
|
|
class LpdMediator final : public tr_lpd::Mediator
|
|
{
|
|
public:
|
|
explicit LpdMediator(tr_session& session)
|
|
: session_{ session }
|
|
{
|
|
}
|
|
|
|
[[nodiscard]] tr_port port() const override
|
|
{
|
|
return session_.peerPort();
|
|
}
|
|
|
|
[[nodiscard]] bool allowsLPD() const override
|
|
{
|
|
return session_.allowsLPD();
|
|
}
|
|
|
|
[[nodiscard]] std::vector<TorrentInfo> torrents() const override;
|
|
|
|
bool onPeerFound(std::string_view info_hash_str, tr_address address, tr_port port) override;
|
|
|
|
void setNextAnnounceTime(std::string_view info_hash_str, time_t announce_after) override;
|
|
|
|
private:
|
|
tr_session& session_;
|
|
};
|
|
|
|
LpdMediator lpd_mediator_{ *this };
|
|
|
|
std::unique_ptr<event_base, void (*)(event_base*)> const event_base_;
|
|
std::unique_ptr<evdns_base, void (*)(evdns_base*)> const evdns_base_;
|
|
std::unique_ptr<libtransmission::TimerMaker> const timer_maker_;
|
|
|
|
void onNowTimer();
|
|
std::unique_ptr<libtransmission::Timer> now_timer_;
|
|
|
|
std::unique_ptr<libtransmission::Timer> save_timer_;
|
|
|
|
tr_torrents torrents_;
|
|
|
|
std::unique_ptr<tr_verify_worker> verifier_ = std::make_unique<tr_verify_worker>();
|
|
|
|
std::array<std::string, TR_SCRIPT_N_TYPES> scripts_;
|
|
|
|
std::string const config_dir_;
|
|
std::string const resume_dir_;
|
|
std::string const torrent_dir_;
|
|
std::string download_dir_;
|
|
std::string incomplete_dir_;
|
|
|
|
std::string blocklist_url_;
|
|
std::string default_trackers_str_;
|
|
std::string peer_congestion_algorithm_;
|
|
|
|
tr_stats session_stats_;
|
|
|
|
std::optional<tr_address> external_ip_;
|
|
|
|
queue_start_callback_t queue_start_callback_ = nullptr;
|
|
void* queue_start_user_data_ = nullptr;
|
|
|
|
tr_session_idle_limit_hit_func idle_limit_hit_callback_ = nullptr;
|
|
void* idle_limit_hit_user_data_ = nullptr;
|
|
|
|
tr_session_ratio_limit_hit_func ratio_limit_hit_cb_ = nullptr;
|
|
void* ratio_limit_hit_user_data_ = nullptr;
|
|
|
|
tr_session_metadata_func got_metadata_cb_ = nullptr;
|
|
void* got_metadata_user_data_ = nullptr;
|
|
|
|
tr_torrent_completeness_func completeness_func_ = nullptr;
|
|
void* completeness_func_user_data_ = nullptr;
|
|
|
|
std::array<bool, TR_SCRIPT_N_TYPES> scripts_enabled_ = {};
|
|
bool blocklist_enabled_ = false;
|
|
bool incomplete_dir_enabled_ = false;
|
|
|
|
tr_open_files open_files_;
|
|
|
|
std::string announce_ip_;
|
|
bool announce_ip_enabled_ = false;
|
|
|
|
public:
|
|
struct struct_utp_context* utp_context = nullptr;
|
|
std::unique_ptr<libtransmission::Timer> utp_timer;
|
|
|
|
// These UDP announcer quirks are tightly hooked with session
|
|
bool tau_handle_message(uint8_t const* msg, size_t msglen) const;
|
|
void tau_sendto(struct evutil_addrinfo* ai, tr_port port, void const* buf, size_t buflen) const;
|
|
};
|
|
|
|
constexpr bool tr_isPriority(tr_priority_t p)
|
|
{
|
|
return p == TR_PRI_LOW || p == TR_PRI_NORMAL || p == TR_PRI_HIGH;
|
|
}
|