forked from premiere/premiere-libtorrent
make tracker announces happen even if there are no open listen sockets (#2529)
support announcing to IPv6 trackers and running an IPv6 DHT when not listening for incoming connections
This commit is contained in:
parent
30a7b52855
commit
c734f42ac3
|
@ -128,6 +128,12 @@ namespace aux {
|
||||||
struct tracker_logger;
|
struct tracker_logger;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum class duplex : std::uint8_t
|
||||||
|
{
|
||||||
|
accept_incoming,
|
||||||
|
only_outgoing
|
||||||
|
};
|
||||||
|
|
||||||
struct listen_socket_t
|
struct listen_socket_t
|
||||||
{
|
{
|
||||||
listen_socket_t()
|
listen_socket_t()
|
||||||
|
@ -181,6 +187,8 @@ namespace aux {
|
||||||
// indicates whether this is an SSL listen socket or not
|
// indicates whether this is an SSL listen socket or not
|
||||||
transport ssl = transport::plaintext;
|
transport ssl = transport::plaintext;
|
||||||
|
|
||||||
|
duplex incoming = duplex::accept_incoming;
|
||||||
|
|
||||||
// the actual sockets (TCP listen socket and UDP socket)
|
// the actual sockets (TCP listen socket and UDP socket)
|
||||||
// An entry does not necessarily have a UDP or TCP socket. One of these
|
// An entry does not necessarily have a UDP or TCP socket. One of these
|
||||||
// pointers may be nullptr!
|
// pointers may be nullptr!
|
||||||
|
@ -194,8 +202,9 @@ namespace aux {
|
||||||
|
|
||||||
struct TORRENT_EXTRA_EXPORT listen_endpoint_t
|
struct TORRENT_EXTRA_EXPORT listen_endpoint_t
|
||||||
{
|
{
|
||||||
listen_endpoint_t(address adr, int p, std::string dev, transport s)
|
listen_endpoint_t(address adr, int p, std::string dev, transport s
|
||||||
: addr(adr), port(p), device(dev), ssl(s) {}
|
, duplex d = duplex::accept_incoming)
|
||||||
|
: addr(adr), port(p), device(dev), ssl(s), incoming(d) {}
|
||||||
|
|
||||||
bool operator==(listen_endpoint_t const& o) const
|
bool operator==(listen_endpoint_t const& o) const
|
||||||
{
|
{
|
||||||
|
@ -206,6 +215,7 @@ namespace aux {
|
||||||
int port;
|
int port;
|
||||||
std::string device;
|
std::string device;
|
||||||
transport ssl;
|
transport ssl;
|
||||||
|
duplex incoming;
|
||||||
};
|
};
|
||||||
|
|
||||||
// partitions sockets based on whether they match one of the given endpoints
|
// partitions sockets based on whether they match one of the given endpoints
|
||||||
|
@ -675,6 +685,7 @@ namespace aux {
|
||||||
// implements session_interface
|
// implements session_interface
|
||||||
tcp::endpoint bind_outgoing_socket(socket_type& s, address
|
tcp::endpoint bind_outgoing_socket(socket_type& s, address
|
||||||
const& remote_address, error_code& ec) const override;
|
const& remote_address, error_code& ec) const override;
|
||||||
|
bool verify_incoming_interface(address const& addr);
|
||||||
bool verify_bound_address(address const& addr, bool utp
|
bool verify_bound_address(address const& addr, bool utp
|
||||||
, error_code& ec) override;
|
, error_code& ec) override;
|
||||||
|
|
||||||
|
@ -761,8 +772,8 @@ namespace aux {
|
||||||
void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip
|
void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip
|
||||||
, ip_source_t const source_type, address const& source);
|
, ip_source_t const source_type, address const& source);
|
||||||
|
|
||||||
void interface_to_endpoints(std::string const& device, int const port
|
void interface_to_endpoints(std::string const& device, int port
|
||||||
, bool const ssl, std::vector<listen_endpoint_t>& eps);
|
, transport ssl, duplex incoming, std::vector<listen_endpoint_t>& eps);
|
||||||
|
|
||||||
// the settings for the client
|
// the settings for the client
|
||||||
aux::session_settings m_settings;
|
aux::session_settings m_settings;
|
||||||
|
@ -937,8 +948,8 @@ namespace aux {
|
||||||
// round-robin index into m_outgoing_interfaces
|
// round-robin index into m_outgoing_interfaces
|
||||||
mutable std::uint8_t m_interface_index = 0;
|
mutable std::uint8_t m_interface_index = 0;
|
||||||
|
|
||||||
std::shared_ptr<listen_socket_t> setup_listener(std::string const& device
|
std::shared_ptr<listen_socket_t> setup_listener(
|
||||||
, tcp::endpoint bind_ep, transport ssl, error_code& ec);
|
listen_endpoint_t const& lep, error_code& ec);
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_DHT
|
#ifndef TORRENT_DISABLE_DHT
|
||||||
dht::dht_state m_dht_state;
|
dht::dht_state m_dht_state;
|
||||||
|
|
|
@ -155,6 +155,7 @@ namespace libtorrent {
|
||||||
#endif
|
#endif
|
||||||
sha1_hash info_hash;
|
sha1_hash info_hash;
|
||||||
peer_id pid;
|
peer_id pid;
|
||||||
|
|
||||||
aux::listen_socket_handle outgoing_socket;
|
aux::listen_socket_handle outgoing_socket;
|
||||||
|
|
||||||
// set to true if the .torrent file this tracker announce is for is marked
|
// set to true if the .torrent file this tracker announce is for is marked
|
||||||
|
|
|
@ -97,7 +97,7 @@ namespace libtorrent {
|
||||||
void fail(error_code const& ec, int code = -1
|
void fail(error_code const& ec, int code = -1
|
||||||
, char const* msg = ""
|
, char const* msg = ""
|
||||||
, seconds32 interval = seconds32(0)
|
, seconds32 interval = seconds32(0)
|
||||||
, seconds32 min_interval = seconds32(0));
|
, seconds32 min_interval = seconds32(30));
|
||||||
|
|
||||||
void send_udp_connect();
|
void send_udp_connect();
|
||||||
void send_udp_announce();
|
void send_udp_announce();
|
||||||
|
|
|
@ -406,6 +406,104 @@ void test_ipv6_support(char const* listen_interfaces
|
||||||
TEST_EQUAL(v6_announces, expect_v6);
|
TEST_EQUAL(v6_announces, expect_v6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_udpv6_support(char const* listen_interfaces
|
||||||
|
, int const expect_v4, int const expect_v6)
|
||||||
|
{
|
||||||
|
using sim::asio::ip::address_v4;
|
||||||
|
sim_config network_cfg;
|
||||||
|
sim::simulation sim{network_cfg};
|
||||||
|
|
||||||
|
sim::asio::io_service web_server_v4(sim, address_v4::from_string("10.0.0.2"));
|
||||||
|
sim::asio::io_service web_server_v6(sim, address_v6::from_string("ff::dead:beef"));
|
||||||
|
|
||||||
|
int v4_announces = 0;
|
||||||
|
int v6_announces = 0;
|
||||||
|
|
||||||
|
{
|
||||||
|
lt::session_proxy zombie;
|
||||||
|
|
||||||
|
std::vector<asio::ip::address> ips;
|
||||||
|
|
||||||
|
for (int i = 0; i < num_interfaces; i++)
|
||||||
|
{
|
||||||
|
char ep[30];
|
||||||
|
std::snprintf(ep, sizeof(ep), "10.0.0.%d", i + 1);
|
||||||
|
ips.push_back(address::from_string(ep));
|
||||||
|
std::snprintf(ep, sizeof(ep), "ffff::1337:%d", i + 1);
|
||||||
|
ips.push_back(address::from_string(ep));
|
||||||
|
}
|
||||||
|
|
||||||
|
asio::io_service ios(sim, ips);
|
||||||
|
lt::settings_pack sett = settings();
|
||||||
|
if (listen_interfaces)
|
||||||
|
{
|
||||||
|
sett.set_str(settings_pack::listen_interfaces, listen_interfaces);
|
||||||
|
}
|
||||||
|
std::unique_ptr<lt::session> ses(new lt::session(sett, ios));
|
||||||
|
|
||||||
|
// since we don't have a udp tracker to run in the sim, looking for the
|
||||||
|
// alerts is the closest proxy
|
||||||
|
ses->set_alert_notify([&]{
|
||||||
|
ses->get_io_service().post([&] {
|
||||||
|
std::vector<lt::alert*> alerts;
|
||||||
|
ses->pop_alerts(&alerts);
|
||||||
|
|
||||||
|
for (lt::alert* a : alerts)
|
||||||
|
{
|
||||||
|
lt::time_duration d = a->timestamp().time_since_epoch();
|
||||||
|
std::uint32_t const millis = std::uint32_t(
|
||||||
|
lt::duration_cast<lt::milliseconds>(d).count());
|
||||||
|
std::printf("%4d.%03d: %s\n", millis / 1000, millis % 1000,
|
||||||
|
a->message().c_str());
|
||||||
|
if (auto tr = alert_cast<tracker_announce_alert>(a))
|
||||||
|
{
|
||||||
|
if (tr->local_endpoint.address().is_v4())
|
||||||
|
++v4_announces;
|
||||||
|
else
|
||||||
|
++v6_announces;
|
||||||
|
}
|
||||||
|
else if (alert_cast<tracker_error_alert>(a))
|
||||||
|
{
|
||||||
|
TEST_CHECK(false && "unexpected tracker error");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
lt::add_torrent_params p;
|
||||||
|
p.name = "test-torrent";
|
||||||
|
p.save_path = ".";
|
||||||
|
p.info_hash.assign("abababababababababab");
|
||||||
|
|
||||||
|
p.trackers.push_back("udp://tracker.com:8080/announce");
|
||||||
|
ses->async_add_torrent(p);
|
||||||
|
|
||||||
|
// stop the torrent 5 seconds in
|
||||||
|
sim::timer t1(sim, lt::seconds(5)
|
||||||
|
, [&ses](boost::system::error_code const&)
|
||||||
|
{
|
||||||
|
std::vector<lt::torrent_handle> torrents = ses->get_torrents();
|
||||||
|
for (auto const& t : torrents)
|
||||||
|
{
|
||||||
|
t.pause();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// then shut down 10 seconds in
|
||||||
|
sim::timer t2(sim, lt::seconds(10)
|
||||||
|
, [&ses,&zombie](boost::system::error_code const&)
|
||||||
|
{
|
||||||
|
zombie = ses->abort();
|
||||||
|
ses.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
sim.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_EQUAL(v4_announces, expect_v4);
|
||||||
|
TEST_EQUAL(v6_announces, expect_v6);
|
||||||
|
}
|
||||||
|
|
||||||
// this test makes sure that a tracker whose host name resolves to both IPv6 and
|
// this test makes sure that a tracker whose host name resolves to both IPv6 and
|
||||||
// IPv4 addresses will be announced to twice, once for each address family
|
// IPv4 addresses will be announced to twice, once for each address family
|
||||||
TORRENT_TEST(ipv6_support)
|
TORRENT_TEST(ipv6_support)
|
||||||
|
@ -414,6 +512,20 @@ TORRENT_TEST(ipv6_support)
|
||||||
test_ipv6_support(nullptr, 2, num_interfaces * 2);
|
test_ipv6_support(nullptr, 2, num_interfaces * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(announce_no_listen)
|
||||||
|
{
|
||||||
|
// if we don't listen on any sockets at all (but only make outgoing peer
|
||||||
|
// connections) we still need to make sure we announce to trackers
|
||||||
|
test_ipv6_support("", 2, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TORRENT_TEST(announce_udp_no_listen)
|
||||||
|
{
|
||||||
|
// since there's no actual udp tracker in this test, we will only try to
|
||||||
|
// announce once, and fail. We won't announce the event=stopped
|
||||||
|
test_udpv6_support("", 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
TORRENT_TEST(ipv6_support_bind_v4_v6_any)
|
TORRENT_TEST(ipv6_support_bind_v4_v6_any)
|
||||||
{
|
{
|
||||||
// 2 because there's one announce on startup and one when shutting down
|
// 2 because there's one announce on startup and one when shutting down
|
||||||
|
|
|
@ -1348,7 +1348,10 @@ namespace {
|
||||||
!= m_settings.get_int(settings_pack::ssl_listen))
|
!= m_settings.get_int(settings_pack::ssl_listen))
|
||||||
||
|
||
|
||||||
#endif
|
#endif
|
||||||
(pack.has_val(settings_pack::listen_interfaces)
|
(pack.has_val(settings_pack::force_proxy)
|
||||||
|
&& !pack.get_bool(settings_pack::force_proxy)
|
||||||
|
&& m_settings.get_bool(settings_pack::force_proxy))
|
||||||
|
|| (pack.has_val(settings_pack::listen_interfaces)
|
||||||
&& pack.get_str(settings_pack::listen_interfaces)
|
&& pack.get_str(settings_pack::listen_interfaces)
|
||||||
!= m_settings.get_str(settings_pack::listen_interfaces));
|
!= m_settings.get_str(settings_pack::listen_interfaces));
|
||||||
|
|
||||||
|
@ -1381,25 +1384,27 @@ namespace {
|
||||||
reopen_outgoing_sockets();
|
reopen_outgoing_sockets();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<listen_socket_t> session_impl::setup_listener(std::string const& device
|
std::shared_ptr<listen_socket_t> session_impl::setup_listener(
|
||||||
, tcp::endpoint bind_ep, transport const ssl, error_code& ec)
|
listen_endpoint_t const& lep, error_code& ec)
|
||||||
{
|
{
|
||||||
int retries = m_settings.get_int(settings_pack::max_retry_port_bind);
|
int retries = m_settings.get_int(settings_pack::max_retry_port_bind);
|
||||||
|
tcp::endpoint bind_ep(lep.addr, std::uint16_t(lep.port));
|
||||||
|
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("attempting to open listen socket to: %s on device: %s ssl: %x"
|
session_log("attempting to open listen socket to: %s on device: %s ssl: %x"
|
||||||
, print_endpoint(bind_ep).c_str(), device.c_str(), static_cast<int>(ssl));
|
, print_endpoint(bind_ep).c_str(), lep.device.c_str(), static_cast<int>(lep.ssl));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
auto ret = std::make_shared<listen_socket_t>();
|
auto ret = std::make_shared<listen_socket_t>();
|
||||||
ret->ssl = ssl;
|
ret->ssl = lep.ssl;
|
||||||
ret->original_port = bind_ep.port();
|
ret->original_port = bind_ep.port();
|
||||||
|
ret->incoming = lep.incoming;
|
||||||
operation_t last_op = operation_t::unknown;
|
operation_t last_op = operation_t::unknown;
|
||||||
socket_type_t const sock_type
|
socket_type_t const sock_type
|
||||||
= (ssl == transport::ssl)
|
= (lep.ssl == transport::ssl)
|
||||||
? socket_type_t::tcp_ssl
|
? socket_type_t::tcp_ssl
|
||||||
: socket_type_t::tcp;
|
: socket_type_t::tcp;
|
||||||
|
|
||||||
|
@ -1407,7 +1412,7 @@ namespace {
|
||||||
// accept connections on our local machine in this case.
|
// accept connections on our local machine in this case.
|
||||||
// TODO: 3 the logic in this if-block should be factored out into a
|
// TODO: 3 the logic in this if-block should be factored out into a
|
||||||
// separate function. At least most of it
|
// separate function. At least most of it
|
||||||
if (!m_settings.get_bool(settings_pack::force_proxy))
|
if (ret->incoming == duplex::accept_incoming)
|
||||||
{
|
{
|
||||||
ret->sock = std::make_shared<tcp::acceptor>(m_io_service);
|
ret->sock = std::make_shared<tcp::acceptor>(m_io_service);
|
||||||
ret->sock->open(bind_ep.protocol(), ec);
|
ret->sock->open(bind_ep.protocol(), ec);
|
||||||
|
@ -1423,7 +1428,7 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep, last_op
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep, last_op
|
||||||
, ec, sock_type);
|
, ec, sock_type);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1484,26 +1489,26 @@ namespace {
|
||||||
}
|
}
|
||||||
#endif // TORRENT_USE_IPV6
|
#endif // TORRENT_USE_IPV6
|
||||||
|
|
||||||
if (!device.empty())
|
if (!lep.device.empty())
|
||||||
{
|
{
|
||||||
// we have an actual device we're interested in listening on, if we
|
// we have an actual device we're interested in listening on, if we
|
||||||
// have SO_BINDTODEVICE functionality, use it now.
|
// have SO_BINDTODEVICE functionality, use it now.
|
||||||
#if TORRENT_HAS_BINDTODEVICE
|
#if TORRENT_HAS_BINDTODEVICE
|
||||||
ret->sock->set_option(bind_to_device(device.c_str()), ec);
|
ret->sock->set_option(bind_to_device(lep.device.c_str()), ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("bind to device failed (device: %s): %s"
|
session_log("bind to device failed (device: %s): %s"
|
||||||
, device.c_str(), ec.message().c_str());
|
, lep.device.c_str(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif // TORRENT_DISABLE_LOGGING
|
#endif // TORRENT_DISABLE_LOGGING
|
||||||
|
|
||||||
last_op = operation_t::sock_bind_to_device;
|
last_op = operation_t::sock_bind_to_device;
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
|
||||||
, last_op, ec, sock_type);
|
, last_op, ec, sock_type);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1523,7 +1528,7 @@ namespace {
|
||||||
session_log("failed to bind listen socket to: %s on device: %s :"
|
session_log("failed to bind listen socket to: %s on device: %s :"
|
||||||
" [%s] (%d) %s (retries: %d)"
|
" [%s] (%d) %s (retries: %d)"
|
||||||
, print_endpoint(bind_ep).c_str()
|
, print_endpoint(bind_ep).c_str()
|
||||||
, device.c_str()
|
, lep.device.c_str()
|
||||||
, ec.category().name(), ec.value(), ec.message().c_str()
|
, ec.category().name(), ec.value(), ec.message().c_str()
|
||||||
, retries);
|
, retries);
|
||||||
}
|
}
|
||||||
|
@ -1555,20 +1560,20 @@ namespace {
|
||||||
session_log("failed to bind listen socket to: %s on device: %s :"
|
session_log("failed to bind listen socket to: %s on device: %s :"
|
||||||
" [%s] (%d) %s (giving up)"
|
" [%s] (%d) %s (giving up)"
|
||||||
, print_endpoint(bind_ep).c_str()
|
, print_endpoint(bind_ep).c_str()
|
||||||
, device.c_str()
|
, lep.device.c_str()
|
||||||
, ec.category().name(), ec.value(), ec.message().c_str());
|
, ec.category().name(), ec.value(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
|
||||||
, last_op, ec, sock_type);
|
, last_op, ec, sock_type);
|
||||||
}
|
}
|
||||||
ret->sock.reset();
|
ret->sock.reset();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret->local_endpoint = ret->sock->local_endpoint(ec);
|
ret->local_endpoint = ret->sock->local_endpoint(ec);
|
||||||
ret->device = device;
|
ret->device = lep.device;
|
||||||
last_op = operation_t::getname;
|
last_op = operation_t::getname;
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
|
@ -1581,7 +1586,7 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
|
||||||
, last_op, ec, sock_type);
|
, last_op, ec, sock_type);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1599,20 +1604,20 @@ namespace {
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("cannot listen on interface \"%s\": %s"
|
session_log("cannot listen on interface \"%s\": %s"
|
||||||
, device.c_str(), ec.message().c_str());
|
, lep.device.c_str(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
|
||||||
, last_op, ec, sock_type);
|
, last_op, ec, sock_type);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
} // force-proxy mode
|
} // accept incoming
|
||||||
|
|
||||||
socket_type_t const udp_sock_type
|
socket_type_t const udp_sock_type
|
||||||
= (ssl == transport::ssl)
|
= (lep.ssl == transport::ssl)
|
||||||
? socket_type_t::utp_ssl
|
? socket_type_t::utp_ssl
|
||||||
: socket_type_t::udp;
|
: socket_type_t::udp;
|
||||||
udp::endpoint const udp_bind_ep(bind_ep.address(), bind_ep.port());
|
udp::endpoint const udp_bind_ep(bind_ep.address(), bind_ep.port());
|
||||||
|
@ -1625,36 +1630,36 @@ namespace {
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("failed to open UDP socket: %s: %s"
|
session_log("failed to open UDP socket: %s: %s"
|
||||||
, device.c_str(), ec.message().c_str());
|
, lep.device.c_str(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
last_op = operation_t::sock_open;
|
last_op = operation_t::sock_open;
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device
|
||||||
, bind_ep, last_op, ec, udp_sock_type);
|
, bind_ep, last_op, ec, udp_sock_type);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_HAS_BINDTODEVICE
|
#if TORRENT_HAS_BINDTODEVICE
|
||||||
if (!device.empty())
|
if (!lep.device.empty())
|
||||||
{
|
{
|
||||||
ret->udp_sock->sock.set_option(bind_to_device(device.c_str()), ec);
|
ret->udp_sock->sock.set_option(bind_to_device(lep.device.c_str()), ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("bind to device failed (device: %s): %s"
|
session_log("bind to device failed (device: %s): %s"
|
||||||
, device.c_str(), ec.message().c_str());
|
, lep.device.c_str(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif // TORRENT_DISABLE_LOGGING
|
#endif // TORRENT_DISABLE_LOGGING
|
||||||
|
|
||||||
last_op = operation_t::sock_bind_to_device;
|
last_op = operation_t::sock_bind_to_device;
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
{
|
{
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device, bind_ep
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
|
||||||
, last_op, ec, udp_sock_type);
|
, last_op, ec, udp_sock_type);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1670,18 +1675,26 @@ namespace {
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
session_log("failed to bind UDP socket: %s: %s"
|
session_log("failed to bind UDP socket: %s: %s"
|
||||||
, device.c_str(), ec.message().c_str());
|
, lep.device.c_str(), ec.message().c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_alerts.should_post<listen_failed_alert>())
|
if (m_alerts.should_post<listen_failed_alert>())
|
||||||
m_alerts.emplace_alert<listen_failed_alert>(device
|
m_alerts.emplace_alert<listen_failed_alert>(lep.device
|
||||||
, bind_ep, last_op, ec, udp_sock_type);
|
, bind_ep, last_op, ec, udp_sock_type);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
ret->udp_external_port = ret->udp_sock->sock.local_port();
|
ret->udp_external_port = ret->udp_sock->sock.local_port();
|
||||||
|
|
||||||
|
// if we did not open a TCP listen socket, ret->local_endpoint was never
|
||||||
|
// initialized, so do that now, based on the UDP socket
|
||||||
|
if (ret->incoming != duplex::accept_incoming)
|
||||||
|
{
|
||||||
|
auto const udp_ep = ret->udp_sock->local_endpoint();
|
||||||
|
ret->local_endpoint = tcp::endpoint(udp_ep.address(), udp_ep.port());
|
||||||
|
}
|
||||||
|
|
||||||
error_code err;
|
error_code err;
|
||||||
set_socket_buffer_size(ret->udp_sock->sock, m_settings, err);
|
set_socket_buffer_size(ret->udp_sock->sock, m_settings, err);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -1747,7 +1760,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::interface_to_endpoints(std::string const& device, int const port
|
void session_impl::interface_to_endpoints(std::string const& device, int const port
|
||||||
, bool const ssl, std::vector<listen_endpoint_t>& eps)
|
, transport const ssl, duplex const incoming, std::vector<listen_endpoint_t>& eps)
|
||||||
{
|
{
|
||||||
// First, check to see if it's an IP address
|
// First, check to see if it's an IP address
|
||||||
error_code err;
|
error_code err;
|
||||||
|
@ -1757,8 +1770,7 @@ namespace {
|
||||||
#if !TORRENT_USE_IPV6
|
#if !TORRENT_USE_IPV6
|
||||||
if (adr.is_v4())
|
if (adr.is_v4())
|
||||||
#endif
|
#endif
|
||||||
eps.emplace_back(adr, port, std::string()
|
eps.emplace_back(adr, port, std::string(), ssl, incoming);
|
||||||
, ssl ? transport::ssl : transport::plaintext);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1791,8 +1803,7 @@ namespace {
|
||||||
// (which must be of the same family as the address we're
|
// (which must be of the same family as the address we're
|
||||||
// connecting to)
|
// connecting to)
|
||||||
if (device != ipface.name) continue;
|
if (device != ipface.name) continue;
|
||||||
eps.emplace_back(ipface.interface_address, port, device
|
eps.emplace_back(ipface.interface_address, port, device, ssl, incoming);
|
||||||
, ssl ? transport::ssl : transport::plaintext);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1817,14 +1828,18 @@ namespace {
|
||||||
// of a new socket failing to bind due to a conflict with a stale socket
|
// of a new socket failing to bind due to a conflict with a stale socket
|
||||||
std::vector<listen_endpoint_t> eps;
|
std::vector<listen_endpoint_t> eps;
|
||||||
|
|
||||||
|
duplex const incoming = m_settings.get_bool(settings_pack::force_proxy)
|
||||||
|
? duplex::only_outgoing
|
||||||
|
: duplex::accept_incoming;
|
||||||
|
|
||||||
for (auto const& iface : m_listen_interfaces)
|
for (auto const& iface : m_listen_interfaces)
|
||||||
{
|
{
|
||||||
std::string const& device = iface.device;
|
std::string const& device = iface.device;
|
||||||
int const port = iface.port;
|
int const port = iface.port;
|
||||||
bool const ssl = iface.ssl;
|
transport const ssl = iface.ssl ? transport::ssl : transport::plaintext;
|
||||||
|
|
||||||
#ifndef TORRENT_USE_OPENSSL
|
#ifndef TORRENT_USE_OPENSSL
|
||||||
if (ssl)
|
if (ssl == transport::ssl)
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
session_log("attempted to listen ssl with no library support on device: \"%s\""
|
session_log("attempted to listen ssl with no library support on device: \"%s\""
|
||||||
|
@ -1845,7 +1860,7 @@ namespace {
|
||||||
// IP address or a device name. In case it's a device name, we want to
|
// IP address or a device name. In case it's a device name, we want to
|
||||||
// (potentially) end up binding a socket for each IP address associated
|
// (potentially) end up binding a socket for each IP address associated
|
||||||
// with that device.
|
// with that device.
|
||||||
interface_to_endpoints(device, port, ssl, eps);
|
interface_to_endpoints(device, port, ssl, incoming, eps);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
|
@ -1856,6 +1871,18 @@ namespace {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// if no listen interfaces are specified, create sockets to use
|
||||||
|
// any interface
|
||||||
|
if (eps.empty())
|
||||||
|
{
|
||||||
|
eps.emplace_back(address_v4(), 0, "", transport::plaintext
|
||||||
|
, duplex::only_outgoing);
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
eps.emplace_back(address_v6(), 0, "", transport::plaintext
|
||||||
|
, duplex::only_outgoing);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
auto remove_iter = partition_listen_sockets(eps, m_listen_sockets);
|
auto remove_iter = partition_listen_sockets(eps, m_listen_sockets);
|
||||||
|
|
||||||
while (remove_iter != m_listen_sockets.end())
|
while (remove_iter != m_listen_sockets.end())
|
||||||
|
@ -1882,8 +1909,7 @@ namespace {
|
||||||
// an existing socket
|
// an existing socket
|
||||||
for (auto const& ep : eps)
|
for (auto const& ep : eps)
|
||||||
{
|
{
|
||||||
std::shared_ptr<listen_socket_t> s = setup_listener(ep.device
|
std::shared_ptr<listen_socket_t> s = setup_listener(ep, ec);
|
||||||
, tcp::endpoint(ep.addr, std::uint16_t(ep.port)), ep.ssl, ec);
|
|
||||||
|
|
||||||
if (!ec && (s->sock || s->udp_sock))
|
if (!ec && (s->sock || s->udp_sock))
|
||||||
{
|
{
|
||||||
|
@ -1954,6 +1980,7 @@ namespace {
|
||||||
// initiate accepting on the listen sockets
|
// initiate accepting on the listen sockets
|
||||||
for (auto& s : m_listen_sockets)
|
for (auto& s : m_listen_sockets)
|
||||||
{
|
{
|
||||||
|
TORRENT_ASSERT((s->incoming == duplex::accept_incoming) == bool(s->sock));
|
||||||
if (s->sock) async_accept(s->sock, s->ssl);
|
if (s->sock) async_accept(s->sock, s->ssl);
|
||||||
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
if (map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
||||||
}
|
}
|
||||||
|
@ -1972,9 +1999,9 @@ namespace {
|
||||||
|
|
||||||
for (auto const& iface : m_outgoing_interfaces)
|
for (auto const& iface : m_outgoing_interfaces)
|
||||||
{
|
{
|
||||||
interface_to_endpoints(iface, 0, false, eps);
|
interface_to_endpoints(iface, 0, transport::plaintext, duplex::accept_incoming, eps);
|
||||||
#ifdef TORRENT_USE_OPENSSL
|
#ifdef TORRENT_USE_OPENSSL
|
||||||
interface_to_endpoints(iface, 0, true, eps);
|
interface_to_endpoints(iface, 0, transport::ssl, duplex::accept_incoming, eps);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2411,7 +2438,7 @@ namespace {
|
||||||
|
|
||||||
span<char const> const buf = packet.data;
|
span<char const> const buf = packet.data;
|
||||||
|
|
||||||
// give the uTP socket manager first dis on the packet. Presumably
|
// give the uTP socket manager first dibs on the packet. Presumably
|
||||||
// the majority of packets are uTP packets.
|
// the majority of packets are uTP packets.
|
||||||
if (!mgr.incoming_packet(socket, packet.from, buf))
|
if (!mgr.incoming_packet(socket, packet.from, buf))
|
||||||
{
|
{
|
||||||
|
@ -2746,7 +2773,7 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if there are outgoing interfaces specified, verify this
|
// if there are outgoing interfaces specified, verify this
|
||||||
// peer is correctly bound to on of them
|
// peer is correctly bound to one of them
|
||||||
if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty())
|
if (!m_settings.get_str(settings_pack::outgoing_interfaces).empty())
|
||||||
{
|
{
|
||||||
tcp::endpoint local = s->local_endpoint(ec);
|
tcp::endpoint local = s->local_endpoint(ec);
|
||||||
|
@ -2761,6 +2788,22 @@ namespace {
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!verify_incoming_interface(local.address()))
|
||||||
|
{
|
||||||
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
|
if (should_log())
|
||||||
|
{
|
||||||
|
error_code err;
|
||||||
|
session_log(" rejected connection, local interface has incoming connections disabled: %s"
|
||||||
|
, local.address().to_string(err).c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (m_alerts.should_post<peer_blocked_alert>())
|
||||||
|
m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
|
||||||
|
, endp, peer_blocked_alert::invalid_local_interface);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!verify_bound_address(local.address()
|
if (!verify_bound_address(local.address()
|
||||||
, is_utp(*s), ec))
|
, is_utp(*s), ec))
|
||||||
{
|
{
|
||||||
|
@ -5022,6 +5065,19 @@ namespace {
|
||||||
return bind_ep;
|
return bind_ep;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// verify that the interface ``addr`` belongs to, allows incoming connections
|
||||||
|
bool session_impl::verify_incoming_interface(address const& addr)
|
||||||
|
{
|
||||||
|
for (auto const& s : m_listen_sockets)
|
||||||
|
{
|
||||||
|
if (s->local_endpoint.address() == addr)
|
||||||
|
{
|
||||||
|
return s->incoming == duplex::accept_incoming;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// verify that the given local address satisfies the requirements of
|
// verify that the given local address satisfies the requirements of
|
||||||
// the outgoing interfaces. i.e. that one of the allowed outgoing
|
// the outgoing interfaces. i.e. that one of the allowed outgoing
|
||||||
// interfaces has this address. For uTP sockets, which are all backed
|
// interfaces has this address. For uTP sockets, which are all backed
|
||||||
|
@ -5042,7 +5098,7 @@ namespace {
|
||||||
for (auto const& s : m_outgoing_interfaces)
|
for (auto const& s : m_outgoing_interfaces)
|
||||||
{
|
{
|
||||||
error_code err;
|
error_code err;
|
||||||
address ip = address::from_string(s.c_str(), err);
|
address const ip = address::from_string(s.c_str(), err);
|
||||||
if (err) continue;
|
if (err) continue;
|
||||||
if (ip == addr) return true;
|
if (ip == addr) return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2771,7 +2771,7 @@ namespace libtorrent {
|
||||||
{
|
{
|
||||||
// update the endpoint list by adding entries for new listen sockets
|
// update the endpoint list by adding entries for new listen sockets
|
||||||
// and removing entries for non-existent ones
|
// and removing entries for non-existent ones
|
||||||
std::vector<announce_endpoint>::size_type valid_endpoints = 0;
|
std::size_t valid_endpoints = 0;
|
||||||
m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) {
|
m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) {
|
||||||
if (s.is_ssl() != is_ssl_torrent())
|
if (s.is_ssl() != is_ssl_torrent())
|
||||||
return;
|
return;
|
||||||
|
@ -10930,6 +10930,7 @@ namespace {
|
||||||
, retry_interval);
|
, retry_interval);
|
||||||
aep->last_error = ec;
|
aep->last_error = ec;
|
||||||
aep->message = msg;
|
aep->message = msg;
|
||||||
|
fails = aep->fails;
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
debug_log("*** increment tracker fail count [%d]", aep->fails);
|
debug_log("*** increment tracker fail count [%d]", aep->fails);
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in New Issue