diff --git a/CMakeLists.txt b/CMakeLists.txt index 51fc88170..4a3a7b98e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,6 +48,7 @@ set(sources ip_filter ip_notifier ip_voter + listen_socket_handle performance_counters peer_class peer_class_set diff --git a/Jamfile b/Jamfile index cfb1c7743..e5f6785f5 100644 --- a/Jamfile +++ b/Jamfile @@ -604,6 +604,7 @@ SOURCES = ip_filter ip_notifier ip_voter + listen_socket_handle merkle peer_connection platform_util diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index cac561f43..e257da83f 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -174,12 +174,12 @@ nobase_include_HEADERS = \ aux_/deque.hpp \ aux_/escape_string.hpp \ aux_/io.hpp \ + aux_/listen_socket_handle.hpp \ aux_/max_path.hpp \ aux_/path.hpp \ aux_/merkle.hpp \ aux_/session_call.hpp \ aux_/session_impl.hpp \ - aux_/session_listen_socket.hpp \ aux_/session_settings.hpp \ aux_/session_udp_sockets.hpp \ aux_/proxy_settings.hpp \ diff --git a/include/libtorrent/announce_entry.hpp b/include/libtorrent/announce_entry.hpp index 7ba4ab362..ced1d0b19 100644 --- a/include/libtorrent/announce_entry.hpp +++ b/include/libtorrent/announce_entry.hpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/error_code.hpp" #include "libtorrent/string_view.hpp" #include "libtorrent/socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" #include #include @@ -45,8 +46,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - namespace aux { struct session_listen_socket; } - // announces are sent to each tracker using every listen socket // this class holds information about one listen socket for one tracker struct TORRENT_EXPORT announce_endpoint @@ -55,7 +54,7 @@ namespace libtorrent { friend struct announce_entry; // internal - explicit announce_endpoint(aux::session_listen_socket* s); + explicit announce_endpoint(aux::listen_socket_handle const& s); // if this tracker has returned an error or warning message // that message is stored here @@ -76,7 +75,7 @@ namespace libtorrent { private: // internal - aux::session_listen_socket* socket; + aux::listen_socket_handle socket; public: // TODO: include the number of peers received from this tracker, at last @@ -227,7 +226,7 @@ namespace libtorrent { #endif // internal - announce_endpoint* find_endpoint(aux::session_listen_socket* s); + announce_endpoint* find_endpoint(aux::listen_socket_handle const& s); // trims whitespace characters from the beginning of the URL. void trim(); diff --git a/include/libtorrent/aux_/listen_socket_handle.hpp b/include/libtorrent/aux_/listen_socket_handle.hpp new file mode 100644 index 000000000..7e43db6b1 --- /dev/null +++ b/include/libtorrent/aux_/listen_socket_handle.hpp @@ -0,0 +1,101 @@ +/* + +Copyright (c) 2017, Steven Siloti +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +* Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in +the documentation and/or other materials provided with the distribution. +* Neither the name of the author nor the names of its +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef TORRENT_LISTEN_SOCKET_HANDLE_HPP_INCLUDED +#define TORRENT_LISTEN_SOCKET_HANDLE_HPP_INCLUDED + +#include "libtorrent/address.hpp" +#include "libtorrent/socket.hpp" // for tcp::endpoint +#include "libtorrent/ip_voter.hpp" +#include "libtorrent/aux_/session_udp_sockets.hpp" +#include + +namespace libtorrent { namespace aux { + + struct listen_socket_base + { + // this may be empty but can be set + // to the WAN IP address of a NAT router + ip_voter external_address; + + // this is a cached local endpoint for the listen TCP socket + tcp::endpoint local_endpoint; + + // indicates whether this is an SSL listen socket or not + transport ssl = transport::plaintext; + }; + + struct TORRENT_EXTRA_EXPORT listen_socket_handle + { + friend struct session_impl; + + listen_socket_handle() {} + + listen_socket_handle(std::shared_ptr s) // NOLINT + : m_sock(s) + {} + + explicit operator bool() const { return !m_sock.expired(); } + + address get_external_address() const; + tcp::endpoint get_local_endpoint() const; + + bool is_ssl() const; + + bool operator==(listen_socket_handle const& o) const + { + return !m_sock.owner_before(o.m_sock) && !o.m_sock.owner_before(m_sock); + } + + bool operator!=(listen_socket_handle const& o) const + { + return !(*this == o); + } + + bool operator<(listen_socket_handle const& o) const + { return m_sock.owner_before(o.m_sock); } + + listen_socket_handle& operator=(listen_socket_handle const& o) + { + m_sock = o.m_sock; + return *this; + } + + listen_socket_base* impl() const; + + private: + std::weak_ptr m_sock; + }; + +} } + +#endif diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 7bd9ba45e..0a1be877e 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -48,7 +48,6 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include "libtorrent/session.hpp" // for user_load_function_t -#include "libtorrent/ip_voter.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" @@ -133,7 +132,7 @@ namespace aux { TORRENT_EXTRA_EXPORT entry save_dht_settings(dht_settings const& settings); #endif - struct listen_socket_t final : aux::session_listen_socket + struct listen_socket_t : listen_socket_base { listen_socket_t() { @@ -148,22 +147,6 @@ namespace aux { listen_socket_t& operator=(listen_socket_t const&) = delete; listen_socket_t& operator=(listen_socket_t&&) = delete; - address get_external_address() override - { return external_address.external_address(); } - - tcp::endpoint get_local_endpoint() override - { return local_endpoint; } - - bool is_ssl() override - { return ssl == transport::ssl; } - - // this may be empty but can be set - // to the WAN IP address of a NAT router - ip_voter external_address; - - // this is a cached local endpoint for the listen TCP socket - tcp::endpoint local_endpoint; - // the name of the device the socket is bound to, may be empty // if the socket is not bound to a device std::string device; @@ -187,14 +170,13 @@ namespace aux { int tcp_port_mapping[2]; int udp_port_mapping[2]; - // indicates whether this is an SSL listen socket or not - transport ssl = transport::plaintext; - // the actual sockets (TCP listen socket and UDP socket) // An entry does not necessarily have a UDP or TCP socket. One of these // pointers may be nullptr! // These must be shared_ptr to avoid a dangling reference if an // incoming packet is in the event queue when the socket is erased + // TODO: make these direct members and generate shared_ptrs to them + // which alias the listen_socket_t shared_ptr std::shared_ptr sock; std::shared_ptr udp_sock; }; @@ -584,11 +566,11 @@ namespace aux { std::uint16_t ssl_listen_port() const override; std::uint16_t ssl_listen_port(listen_socket_t* sock) const; - void for_each_listen_socket(std::function f) override + void for_each_listen_socket(std::function f) override { for (auto& s : m_listen_sockets) { - f(s.get()); + f(listen_socket_handle(s)); } } @@ -656,7 +638,7 @@ namespace aux { int send_buffer_size() const override { return send_buffer_size_impl; } // implements dht_observer - virtual void set_external_address(aux::session_listen_socket* iface + virtual void set_external_address(aux::listen_socket_handle const& iface , address const& ip, address const& source) override; virtual void get_peers(sha1_hash const& ih) override; virtual void announce(sha1_hash const& ih, address const& addr, int port) override; @@ -778,7 +760,7 @@ namespace aux { void on_lsd_peer(tcp::endpoint const& peer, sha1_hash const& ih) override; void setup_socket_buffers(socket_type& s) override; - void set_external_address(listen_socket_t& sock, address const& ip + void set_external_address(std::shared_ptr const& sock, address const& ip , int const source_type, address const& source); void interface_to_endpoints(std::string const& device, int const port @@ -1098,14 +1080,19 @@ namespace aux { , error_code& ec , int flags); - void send_udp_packet_hostname_listen(aux::session_listen_socket* sock + void send_udp_packet_hostname_listen(aux::listen_socket_handle const& sock , char const* hostname , int port , span p , error_code& ec , int flags) { - listen_socket_t* s = static_cast(sock); + auto s = static_cast(sock.impl()); + if (!s) + { + ec = boost::asio::error::bad_descriptor; + return; + } send_udp_packet_hostname(s->udp_sock, hostname, port, p, ec, flags); } @@ -1115,13 +1102,18 @@ namespace aux { , error_code& ec , int flags); - void send_udp_packet_listen(aux::session_listen_socket* sock + void send_udp_packet_listen(aux::listen_socket_handle const& sock , udp::endpoint const& ep , span p , error_code& ec , int flags) { - listen_socket_t* s = static_cast(sock); + auto s = static_cast(sock.impl()); + if (!s) + { + ec = boost::asio::error::bad_descriptor; + return; + } send_udp_packet(s->udp_sock, ep, p, ec, flags); } diff --git a/include/libtorrent/aux_/session_interface.hpp b/include/libtorrent/aux_/session_interface.hpp index 8542cc730..5210a888a 100644 --- a/include/libtorrent/aux_/session_interface.hpp +++ b/include/libtorrent/aux_/session_interface.hpp @@ -42,7 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/error_code.hpp" #include "libtorrent/socket.hpp" // for tcp::endpoint #include "libtorrent/aux_/vector.hpp" -#include "libtorrent/aux_/session_listen_socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" #include #include @@ -198,7 +198,7 @@ namespace libtorrent { namespace aux { virtual std::uint16_t listen_port() const = 0; virtual std::uint16_t ssl_listen_port() const = 0; - virtual void for_each_listen_socket(std::function f) = 0; + virtual void for_each_listen_socket(std::function f) = 0; // ask for which interface and port to bind outgoing peer connections on virtual tcp::endpoint bind_outgoing_socket(socket_type& s, address const& diff --git a/include/libtorrent/error_code.hpp b/include/libtorrent/error_code.hpp index 5daea9bb7..9948c34e9 100644 --- a/include/libtorrent/error_code.hpp +++ b/include/libtorrent/error_code.hpp @@ -323,6 +323,8 @@ namespace libtorrent { banned_by_port_filter, // The session_handle is not referring to a valid session_impl invalid_session_handle, + // the listen socket associated with this request was closed + invalid_listen_socket, // The NAT-PMP router responded with an unsupported protocol version diff --git a/include/libtorrent/kademlia/dht_observer.hpp b/include/libtorrent/kademlia/dht_observer.hpp index bff8823e4..41b5d9d74 100644 --- a/include/libtorrent/kademlia/dht_observer.hpp +++ b/include/libtorrent/kademlia/dht_observer.hpp @@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { -namespace aux { struct session_listen_socket; } +namespace aux { struct listen_socket_handle; } namespace dht { @@ -73,7 +73,7 @@ namespace dht { struct TORRENT_EXTRA_EXPORT dht_observer : dht_logger { - virtual void set_external_address(aux::session_listen_socket* iface + virtual void set_external_address(aux::listen_socket_handle const& iface , address const& addr, address const& source) = 0; virtual void get_peers(sha1_hash const& ih) = 0; virtual void outgoing_get_peers(sha1_hash const& target diff --git a/include/libtorrent/kademlia/dht_tracker.hpp b/include/libtorrent/kademlia/dht_tracker.hpp index 61729a306..03a5a2d7e 100644 --- a/include/libtorrent/kademlia/dht_tracker.hpp +++ b/include/libtorrent/kademlia/dht_tracker.hpp @@ -39,7 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include +#include #include #include #include @@ -61,7 +61,7 @@ namespace libtorrent { namespace dht { , std::enable_shared_from_this { using send_fun_t = std::function, error_code&, int)>; dht_tracker(dht_observer* observer @@ -84,10 +84,10 @@ namespace libtorrent { namespace dht { // tell the node to recalculate its node id based on the current // understanding of its external address (which may have changed) - void update_node_id(aux::session_listen_socket* s); + void update_node_id(aux::listen_socket_handle const& s); - void new_socket(aux::session_listen_socket* s); - void delete_socket(aux::session_listen_socket* s); + void new_socket(aux::listen_socket_handle const& s); + void delete_socket(aux::listen_socket_handle const& s); void add_node(udp::endpoint const& node); void add_router_node(udp::endpoint const& node); @@ -147,7 +147,7 @@ namespace libtorrent { namespace dht { struct tracker_node { tracker_node(io_service& ios - , aux::session_listen_socket* s, socket_manager* sock + , aux::listen_socket_handle const& s, socket_manager* sock , libtorrent::dht_settings const& settings , node_id const& nid , dht_observer* observer, counters& cnt @@ -157,12 +157,12 @@ namespace libtorrent { namespace dht { node dht; deadline_timer connection_timer; }; - using tracker_nodes_t = std::map; + using tracker_nodes_t = std::map; std::shared_ptr self() { return shared_from_this(); } - void connection_timeout(aux::session_listen_socket* s, error_code const& e); + void connection_timeout(aux::listen_socket_handle const& s, error_code const& e); void refresh_timeout(error_code const& e); void refresh_key(error_code const& e); void update_storage_node_ids(); @@ -170,7 +170,7 @@ namespace libtorrent { namespace dht { // implements socket_manager virtual bool has_quota() override; - virtual bool send_packet(aux::session_listen_socket* s, entry& e, udp::endpoint const& addr) override; + virtual bool send_packet(aux::listen_socket_handle const& s, entry& e, udp::endpoint const& addr) override; // this is the bdecode_node DHT messages are parsed into. It's a member // in order to avoid having to deallocate and re-allocate it for every diff --git a/include/libtorrent/kademlia/node.hpp b/include/libtorrent/kademlia/node.hpp index 89c80238a..efae62c29 100644 --- a/include/libtorrent/kademlia/node.hpp +++ b/include/libtorrent/kademlia/node.hpp @@ -48,13 +48,13 @@ POSSIBILITY OF SUCH DAMAGE. #include // for udp::endpoint #include +#include namespace libtorrent { struct counters; struct dht_routing_bucket; struct dht_settings; - namespace aux { struct session_listen_socket; } } namespace libtorrent { namespace dht { @@ -79,7 +79,7 @@ public: struct socket_manager { virtual bool has_quota() = 0; - virtual bool send_packet(aux::session_listen_socket* s, entry& e, udp::endpoint const& addr) = 0; + virtual bool send_packet(aux::listen_socket_handle const& s, entry& e, udp::endpoint const& addr) = 0; protected: ~socket_manager() = default; }; @@ -90,7 +90,7 @@ using get_foreign_node_t = std::function #include #include +#include -namespace libtorrent { struct dht_settings; class entry; namespace aux { struct session_listen_socket; } } +namespace libtorrent { struct dht_settings; class entry; } namespace libtorrent { namespace dht { @@ -68,7 +69,7 @@ public: rpc_manager(node_id const& our_id , dht_settings const& settings , routing_table& table - , aux::session_listen_socket* sock + , aux::listen_socket_handle const& sock , socket_manager* sock_man , dht_logger* log); ~rpc_manager(); @@ -119,7 +120,7 @@ private: std::unordered_multimap m_transactions; - aux::session_listen_socket* m_sock; + aux::listen_socket_handle m_sock; socket_manager* m_sock_man; #ifndef TORRENT_DISABLE_LOGGING dht_logger* m_log; diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp index eacb9d97f..39d562154 100644 --- a/include/libtorrent/tracker_manager.hpp +++ b/include/libtorrent/tracker_manager.hpp @@ -62,6 +62,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/time.hpp" #include "libtorrent/debug.hpp" #include "libtorrent/error_code.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" namespace libtorrent { @@ -76,7 +77,7 @@ namespace libtorrent { #if TORRENT_USE_I2P class i2p_connection; #endif - namespace aux { struct session_listen_socket; struct session_logger; struct session_settings; } + namespace aux { struct session_logger; struct session_settings; } // returns -1 if gzip header is invalid or the header size in bytes TORRENT_EXTRA_EXPORT int gzip_header(const char* buf, int size); @@ -94,7 +95,6 @@ namespace libtorrent { , kind(announce_request) , key(0) , num_want(0) - , outgoing_socket(nullptr) , private_torrent(false) , triggered_manually(false) #ifdef TORRENT_USE_OPENSSL @@ -152,7 +152,7 @@ namespace libtorrent { #endif sha1_hash info_hash; peer_id pid; - aux::session_listen_socket* outgoing_socket; + aux::listen_socket_handle outgoing_socket; // set to true if the .torrent file this tracker announce is for is marked // as private (i.e. has the "priv": 1 key) @@ -308,7 +308,7 @@ namespace libtorrent { virtual void start() = 0; virtual void close() = 0; address bind_interface() const; - aux::session_listen_socket* bind_socket() const { return m_req.outgoing_socket; } + aux::listen_socket_handle const& bind_socket() const { return m_req.outgoing_socket; } void sent_bytes(int bytes); void received_bytes(int bytes); @@ -338,11 +338,11 @@ namespace libtorrent { { public: - typedef std::function , error_code&, int)> send_fun_t; - typedef std::function , error_code&, int)> send_fun_hostname_t; @@ -389,11 +389,11 @@ namespace libtorrent { aux::session_settings const& settings() const { return m_settings; } resolver_interface& host_resolver() { return m_host_resolver; } - void send_hostname(aux::session_listen_socket* sock + void send_hostname(aux::listen_socket_handle const& sock , char const* hostname, int port, span p , error_code& ec, int flags = 0); - void send(aux::session_listen_socket* sock + void send(aux::listen_socket_handle const& sock , udp::endpoint const& ep, span p , error_code& ec, int flags = 0); diff --git a/simulation/setup_dht.cpp b/simulation/setup_dht.cpp index ee54109ad..62dc390bd 100644 --- a/simulation/setup_dht.cpp +++ b/simulation/setup_dht.cpp @@ -44,7 +44,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/random.hpp" #include "libtorrent/crc32c.hpp" #include "libtorrent/alert_types.hpp" // for dht_routing_bucket -#include "libtorrent/aux_/session_listen_socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" #include "setup_dht.hpp" @@ -76,9 +76,17 @@ namespace { return dht::generate_id(addr); } + std::shared_ptr sim_listen_socket(tcp::endpoint ep) + { + auto ls = std::make_shared(); + ls->external_address.cast_vote(ep.address(), 1, lt::address()); + ls->local_endpoint = ep; + return ls; + } + } // anonymous namespace -struct dht_node final : lt::dht::socket_manager, lt::aux::session_listen_socket +struct dht_node final : lt::dht::socket_manager { dht_node(sim::simulation& sim, lt::dht_settings const& sett, lt::counters& cnt , int const idx, std::uint32_t const flags) @@ -87,7 +95,8 @@ struct dht_node final : lt::dht::socket_manager, lt::aux::session_listen_socket , m_add_dead_nodes((flags & dht_network::add_dead_nodes) != 0) , m_ipv6((flags & dht_network::bind_ipv6) != 0) , m_socket(m_io_service) - , m_dht(this, this, sett, id_from_addr(m_io_service.get_ips().front()) + , m_ls(sim_listen_socket(tcp::endpoint(m_io_service.get_ips().front(), 6881))) + , m_dht(m_ls, this, sett, id_from_addr(m_io_service.get_ips().front()) , nullptr, cnt , [](lt::dht::node_id const&, std::string const&) -> lt::dht::node* { return nullptr; } , *m_dht_storage) @@ -143,7 +152,7 @@ struct dht_node final : lt::dht::socket_manager, lt::aux::session_listen_socket } bool has_quota() override { return true; } - bool send_packet(lt::aux::session_listen_socket* s, entry& e, udp::endpoint const& addr) override + bool send_packet(lt::aux::listen_socket_handle const& s, entry& e, udp::endpoint const& addr) override { // since the simulaton is single threaded, we can get away with allocating // just a single send buffer @@ -157,20 +166,6 @@ struct dht_node final : lt::dht::socket_manager, lt::aux::session_listen_socket return true; } - address get_external_address() override - { - return get_local_endpoint().address(); - } - - tcp::endpoint get_local_endpoint() override - { - if (sock().is_open()) return tcp::endpoint(sock().local_endpoint().address(), sock().local_endpoint().port()); - if (m_ipv6) return tcp::endpoint(address_v6(), 0); - return tcp::endpoint(address_v4(), 0); - } - - bool is_ssl() override { return false; } - // the node_id and IP address of this node std::pair node_info() const { @@ -246,6 +241,7 @@ private: bool const m_ipv6; lt::udp::socket m_socket; lt::udp::socket& sock() { return m_socket; } + std::shared_ptr m_ls; lt::dht::node m_dht; lt::udp::endpoint m_ep; char m_buffer[1300]; diff --git a/simulation/test_dht_rate_limit.cpp b/simulation/test_dht_rate_limit.cpp index 2bb8f09de..6b5c1f239 100644 --- a/simulation/test_dht_rate_limit.cpp +++ b/simulation/test_dht_rate_limit.cpp @@ -34,7 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "simulator/simulator.hpp" -#include "libtorrent/aux_/session_listen_socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" #include "libtorrent/udp_socket.hpp" #include "libtorrent/kademlia/dht_tracker.hpp" #include "libtorrent/kademlia/dht_state.hpp" @@ -56,7 +56,7 @@ using namespace std::placeholders; struct obs : dht::dht_observer { - void set_external_address(lt::aux::session_listen_socket*, address const& /* addr */ + void set_external_address(lt::aux::listen_socket_handle const&, address const& /* addr */ , address const& /* source */) override {} void get_peers(sha1_hash const&) override {} @@ -84,22 +84,7 @@ struct obs : dht::dht_observer #endif }; -struct mock_socket : lt::aux::session_listen_socket -{ - address get_external_address() override - { - return get_local_endpoint().address(); - } - - tcp::endpoint get_local_endpoint() override - { - return tcp::endpoint(address_v4::from_string("40.30.20.10"), 8888); - } - - bool is_ssl() override { return false; } -}; - -void send_packet(lt::udp_socket& sock, lt::aux::session_listen_socket*, udp::endpoint const& ep +void send_packet(lt::udp_socket& sock, lt::aux::listen_socket_handle const&, udp::endpoint const& ep , span p, error_code& ec, int flags) { sock.send(ep, p, ec, flags); @@ -118,7 +103,9 @@ TORRENT_TEST(dht_rate_limit) // receiver (the DHT under test) lt::udp_socket sock(dht_ios); obs o; - mock_socket ds; + auto ls = std::make_shared(); + ls->external_address.cast_vote(address_v4::from_string("40.30.20.10"), 1, lt::address()); + ls->local_endpoint = tcp::endpoint(address_v4::from_string("40.30.20.10"), 8888); error_code ec; sock.bind(udp::endpoint(address_v4::from_string("40.30.20.10"), 8888), ec); dht_settings dhtsett; @@ -134,7 +121,7 @@ TORRENT_TEST(dht_rate_limit) auto dht = std::make_shared( &o, dht_ios, std::bind(&send_packet, std::ref(sock), _1, _2, _3, _4, _5) , dhtsett, cnt, *dht_storage, state); - dht->new_socket(&ds); + dht->new_socket(ls); bool stop = false; std::function on_read @@ -244,7 +231,9 @@ TORRENT_TEST(dht_delete_socket) sock.bind(udp::endpoint(address_v4::from_string("40.30.20.10"), 8888), ec); obs o; - mock_socket ds; + auto ls = std::make_shared(); + ls->external_address.cast_vote(address_v4::from_string("40.30.20.10"), 1, lt::address()); + ls->local_endpoint = tcp::endpoint(address_v4::from_string("40.30.20.10"), 8888); dht_settings dhtsett; counters cnt; dht::dht_state state; @@ -254,7 +243,7 @@ TORRENT_TEST(dht_delete_socket) , dhtsett, cnt, *dht_storage, state); dht->start([](std::vector> const&){}); - dht->new_socket(&ds); + dht->new_socket(ls); // schedule the removal of the socket at exactly 2 second, // this simulates the fact that the internal scheduled call @@ -264,7 +253,7 @@ TORRENT_TEST(dht_delete_socket) t1.expires_from_now(chrono::seconds(2)); t1.async_wait([&](error_code const&) { - dht->delete_socket(&ds); + dht->delete_socket(ls); }); // stop the DHT diff --git a/src/Makefile.am b/src/Makefile.am index d5a38f165..7a6e51e04 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -94,6 +94,7 @@ libtorrent_rasterbar_la_SOURCES = \ ip_notifier.cpp \ ip_voter.cpp \ lazy_bdecode.cpp \ + listen_socket_handle.cpp \ lsd.cpp \ magnet_uri.cpp \ merkle.cpp \ diff --git a/src/announce_entry.cpp b/src/announce_entry.cpp index 90c7f3bf7..9aa7237d1 100644 --- a/src/announce_entry.cpp +++ b/src/announce_entry.cpp @@ -35,7 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/string_util.hpp" // for is_space #include "libtorrent/aux_/time.hpp" #include "libtorrent/aux_/session_settings.hpp" -#include "libtorrent/aux_/session_listen_socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" namespace libtorrent { @@ -47,8 +47,8 @@ namespace libtorrent { minutes32 constexpr tracker_retry_delay_max{60}; } - announce_endpoint::announce_endpoint(aux::session_listen_socket* s) - : local_endpoint(s ? s->get_local_endpoint() : tcp::endpoint()) + announce_endpoint::announce_endpoint(aux::listen_socket_handle const& s) + : local_endpoint(s ? s.get_local_endpoint() : tcp::endpoint()) , socket(s) , fails(0) , updating(false) @@ -143,7 +143,7 @@ namespace libtorrent { } #endif - announce_endpoint* announce_entry::find_endpoint(aux::session_listen_socket* s) + announce_endpoint* announce_entry::find_endpoint(aux::listen_socket_handle const& s) { auto aep = std::find_if(endpoints.begin(), endpoints.end() , [&](announce_endpoint const& a) { return a.socket == s; }); diff --git a/src/create_torrent.cpp b/src/create_torrent.cpp index 4fb0b14f8..5f5eea226 100644 --- a/src/create_torrent.cpp +++ b/src/create_torrent.cpp @@ -68,7 +68,7 @@ namespace libtorrent { if (attr.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) return file_storage::attribute_hidden; return 0; #else - struct stat s; + struct ::stat s; if (::lstat(convert_to_native(p).c_str(), &s) < 0) return 0; std::uint32_t file_attr = 0; if (s.st_mode & S_IXUSR) diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp index 26b34d9d1..acd98356b 100644 --- a/src/http_tracker_connection.cpp +++ b/src/http_tracker_connection.cpp @@ -193,6 +193,12 @@ namespace libtorrent { } #endif + if (!tracker_req().outgoing_socket) + { + fail(errors::invalid_listen_socket, -1, "outgoing socket was closed"); + return; + } + m_tracker_connection = std::make_shared(get_io_service(), m_man.host_resolver() , std::bind(&http_tracker_connection::on_response, shared_from_this(), _1, _2, _3, _4) , true, settings.get_int(settings_pack::max_http_recv_buffer_size) diff --git a/src/kademlia/dht_tracker.cpp b/src/kademlia/dht_tracker.cpp index 63c301145..e0eb36cc9 100644 --- a/src/kademlia/dht_tracker.cpp +++ b/src/kademlia/dht_tracker.cpp @@ -106,7 +106,7 @@ namespace libtorrent { namespace dht { m_blocker.set_rate_limit(m_settings.block_ratelimit); } - void dht_tracker::update_node_id(aux::session_listen_socket* s) + void dht_tracker::update_node_id(aux::listen_socket_handle const& s) { auto n = m_nodes.find(s); if (n != m_nodes.end()) @@ -114,11 +114,11 @@ namespace libtorrent { namespace dht { update_storage_node_ids(); } - void dht_tracker::new_socket(aux::session_listen_socket* s) + void dht_tracker::new_socket(aux::listen_socket_handle const& s) { - if (s->is_ssl()) return; + if (s.is_ssl()) return; - address local_address = s->get_local_endpoint().address(); + address local_address = s.get_local_endpoint().address(); #if TORRENT_USE_IPV6 // don't try to start dht nodes on non-global IPv6 addresses // with IPv4 the interface might be behind NAT so we can't skip them based on the scope of the local address @@ -156,12 +156,12 @@ namespace libtorrent { namespace dht { } } - void dht_tracker::delete_socket(aux::session_listen_socket* s) + void dht_tracker::delete_socket(aux::listen_socket_handle const& s) { - if (s->is_ssl()) return; + if (s.is_ssl()) return; #if TORRENT_USE_IPV6 - address local_address = s->get_local_endpoint().address(); + address local_address = s.get_local_endpoint().address(); // since we don't start nodes on local IPv6 interfaces we don't need to remove them either if (local_address.is_v6() && is_local(local_address)) return; @@ -182,7 +182,7 @@ namespace libtorrent { namespace dht { n.second.connection_timer.async_wait( std::bind(&dht_tracker::connection_timeout, self(), n.first, _1)); #if TORRENT_USE_IPV6 - if (n.first->get_local_endpoint().protocol() == tcp::v6()) + if (n.first.get_local_endpoint().protocol() == tcp::v6()) n.second.dht.bootstrap(concat(m_state.nodes6, m_state.nodes), f); else #endif @@ -246,7 +246,7 @@ namespace libtorrent { namespace dht { add_dht_counters(n.second.dht, c); } - void dht_tracker::connection_timeout(aux::session_listen_socket* s, error_code const& e) + void dht_tracker::connection_timeout(aux::listen_socket_handle const& s, error_code const& e) { if (e || !m_running) return; @@ -339,7 +339,7 @@ namespace libtorrent { namespace dht { { for (auto& n : m_nodes) { - if (ep.protocol() != (n.first->get_external_address().is_v4() ? udp::v4() : udp::v6())) + if (ep.protocol() != (n.first.get_external_address().is_v4() ? udp::v4() : udp::v6())) continue; n.second.dht.sample_infohashes(ep, target, f); break; @@ -473,7 +473,7 @@ namespace libtorrent { namespace dht { { for (auto& n : m_nodes) { - if (ep.protocol() != (n.first->get_external_address().is_v4() ? udp::v4() : udp::v6())) + if (ep.protocol() != (n.first.get_external_address().is_v4() ? udp::v4() : udp::v6())) continue; n.second.dht.direct_request(ep, e, f); break; @@ -569,7 +569,7 @@ namespace libtorrent { namespace dht { } dht_tracker::tracker_node::tracker_node(io_service& ios - , aux::session_listen_socket* s, socket_manager* sock + , aux::listen_socket_handle const& s, socket_manager* sock , libtorrent::dht_settings const& settings , node_id const& nid , dht_observer* observer, counters& cnt @@ -616,7 +616,7 @@ namespace libtorrent { namespace dht { { // use the local rather than external address because if the user is behind NAT // we won't know the external IP on startup - ret.nids.push_back(std::make_pair(n.first->get_local_endpoint().address(), n.second.dht.nid())); + ret.nids.push_back(std::make_pair(n.first.get_local_endpoint().address(), n.second.dht.nid())); auto nodes = save_nodes(n.second.dht); ret.nodes.insert(ret.nodes.end(), nodes.begin(), nodes.end()); } @@ -652,7 +652,7 @@ namespace libtorrent { namespace dht { return m_send_quota > 0; } - bool dht_tracker::send_packet(aux::session_listen_socket* s, entry& e, udp::endpoint const& addr) + bool dht_tracker::send_packet(aux::listen_socket_handle const& s, entry& e, udp::endpoint const& addr) { TORRENT_ASSERT(m_nodes.find(s) != m_nodes.end()); @@ -669,14 +669,14 @@ namespace libtorrent { namespace dht { m_send_quota -= int(m_send_buf.size()); error_code ec; - if (s->get_local_endpoint().protocol().family() != addr.protocol().family()) + if (s.get_local_endpoint().protocol().family() != addr.protocol().family()) { // the node is trying to send a packet to a different address family // than its socket, this can happen during bootstrap // pick a node with the right address family and use its socket auto n = std::find_if(m_nodes.begin(), m_nodes.end() , [&](tracker_nodes_t::value_type const& v) - { return v.first->get_local_endpoint().protocol().family() == addr.protocol().family(); }); + { return v.first.get_local_endpoint().protocol().family() == addr.protocol().family(); }); if (n != m_nodes.end()) m_send_fun(n->first, addr, m_send_buf, ec, 0); diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index 8674cb2ea..4eebc11e0 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -48,7 +48,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/hasher.hpp" #include "libtorrent/random.hpp" #include -#include "libtorrent/aux_/session_listen_socket.hpp" #include #include "libtorrent/aux_/throw.hpp" #include "libtorrent/alert_types.hpp" // for dht_lookup @@ -74,10 +73,10 @@ namespace { void nop() {} -node_id calculate_node_id(node_id const& nid, aux::session_listen_socket* sock) +node_id calculate_node_id(node_id const& nid, aux::listen_socket_handle const& sock) { address external_address; - external_address = sock->get_external_address(); + external_address = sock.get_external_address(); // if we don't have an observer, don't pretend that external_address is valid // generating an ID based on 0.0.0.0 would be terrible. random is better @@ -103,7 +102,7 @@ void incoming_error(entry& e, char const* msg, int error_code = 203) } // anonymous namespace -node::node(aux::session_listen_socket* sock, socket_manager* sock_man +node::node(aux::listen_socket_handle const& sock, socket_manager* sock_man , dht_settings const& settings , node_id const& nid , dht_observer* observer @@ -112,11 +111,11 @@ node::node(aux::session_listen_socket* sock, socket_manager* sock_man , dht_storage_interface& storage) : m_settings(settings) , m_id(calculate_node_id(nid, sock)) - , m_table(m_id, sock->get_local_endpoint().protocol() == tcp::v4() ? udp::v4() : udp::v6(), 8, settings, observer) + , m_table(m_id, sock.get_local_endpoint().protocol() == tcp::v4() ? udp::v4() : udp::v6(), 8, settings, observer) , m_rpc(m_id, m_settings, m_table, sock, sock_man, observer) , m_get_foreign_node(get_foreign_node) , m_observer(observer) - , m_protocol(map_protocol_to_descriptor(sock->get_local_endpoint().protocol() == tcp::v4() ? udp::v4() : udp::v6())) + , m_protocol(map_protocol_to_descriptor(sock.get_local_endpoint().protocol() == tcp::v4() ? udp::v4() : udp::v6())) , m_last_tracker_tick(aux::time_now()) , m_last_self_refresh(min_time()) , m_sock_man(sock_man) @@ -137,9 +136,11 @@ void node::update_node_id() // can just stop here in that case. if (m_observer == nullptr) return; + auto ext_address = m_sock.get_external_address(); + // it's possible that our external address hasn't actually changed. If our // current ID is still valid, don't do anything. - if (verify_id(m_id, m_sock->get_external_address())) + if (verify_id(m_id, ext_address)) return; #ifndef TORRENT_DISABLE_LOGGING @@ -147,7 +148,7 @@ void node::update_node_id() , "updating node ID (because external IP address changed)"); #endif - m_id = generate_id(m_sock->get_external_address()); + m_id = generate_id(ext_address); m_table.update_node_id(m_id); m_rpc.update_node_id(m_id); diff --git a/src/kademlia/rpc_manager.cpp b/src/kademlia/rpc_manager.cpp index b5a0626c8..0e76035f0 100644 --- a/src/kademlia/rpc_manager.cpp +++ b/src/kademlia/rpc_manager.cpp @@ -151,7 +151,7 @@ using observer_storage = aux::aligned_union<1 rpc_manager::rpc_manager(node_id const& our_id , dht_settings const& settings , routing_table& table - , aux::session_listen_socket* sock + , aux::listen_socket_handle const& sock , socket_manager* sock_man , dht_logger* log) : m_pool_allocator(sizeof(observer_storage), 10) diff --git a/include/libtorrent/aux_/session_listen_socket.hpp b/src/listen_socket_handle.cpp similarity index 62% rename from include/libtorrent/aux_/session_listen_socket.hpp rename to src/listen_socket_handle.cpp index f80b0c864..51c29f6c1 100644 --- a/include/libtorrent/aux_/session_listen_socket.hpp +++ b/src/listen_socket_handle.cpp @@ -30,33 +30,37 @@ POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TORRENT_SESSION_LISTEN_SOCKET_HPP_INCLUDED -#define TORRENT_SESSION_LISTEN_SOCKET_HPP_INCLUDED - -#include "libtorrent/address.hpp" -#include "libtorrent/socket.hpp" // for tcp::endpoint +#include "libtorrent/aux_/listen_socket_handle.hpp" namespace libtorrent { namespace aux { - // abstract interface for a listen socket owned by session_impl - // pointers to this type serve as a handle for the listen socket - // use a separate abstract type to prohibit outside access to private fields of listen_socket_t - // and because some users of these handles should not be coupled to session_impl - struct TORRENT_EXTRA_EXPORT session_listen_socket + address listen_socket_handle::get_external_address() const { - virtual address get_external_address() = 0; - virtual tcp::endpoint get_local_endpoint() = 0; + auto s = m_sock.lock(); + TORRENT_ASSERT(s); + if (!s) throw_ex(); + return s->external_address.external_address(); + } - virtual bool is_ssl() = 0; + tcp::endpoint listen_socket_handle::get_local_endpoint() const + { + auto s = m_sock.lock(); + TORRENT_ASSERT(s); + if (!s) throw_ex(); + return s->local_endpoint; + } - session_listen_socket() = default; + bool listen_socket_handle::is_ssl() const + { + auto s = m_sock.lock(); + TORRENT_ASSERT(s); + if (!s) throw_ex(); + return s->ssl == transport::ssl; + } - protected: - session_listen_socket(session_listen_socket const&) = default; - session_listen_socket& operator=(session_listen_socket const&) = default; - ~session_listen_socket() = default; - }; + listen_socket_base* listen_socket_handle::impl() const + { + return m_sock.lock().get(); + } } } - -#endif diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 27d30a4de..1db32ba44 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1212,7 +1212,7 @@ namespace { if (req.outgoing_socket) { - listen_socket_t* ls = static_cast(req.outgoing_socket); + auto ls = static_cast(req.outgoing_socket.impl()); req.listen_port = listen_port(ls); #ifdef TORRENT_USE_OPENSSL // SSL torrents use the SSL listen port @@ -1229,7 +1229,7 @@ namespace { // SSL torrents use the SSL listen port if (use_ssl) req.listen_port = ssl_listen_port(&ls); #endif - req.outgoing_socket = ls.get(); + req.outgoing_socket = listen_socket_handle(ls); m_tracker_manager.queue_request(get_io_service(), req, c); } } @@ -1954,7 +1954,7 @@ namespace { { #ifndef TORRENT_DISABLE_DHT if (m_dht) - m_dht->delete_socket(remove_iter->get()); + m_dht->delete_socket(listen_socket_handle(*remove_iter)); #endif #ifndef TORRENT_DISABLE_LOGGING @@ -1984,7 +1984,7 @@ namespace { #ifndef TORRENT_DISABLE_DHT if (m_dht) - m_dht->new_socket(m_listen_sockets.back().get()); + m_dht->new_socket(listen_socket_handle(m_listen_sockets.back())); #endif } } @@ -5678,7 +5678,7 @@ namespace { m_dht = std::make_shared( static_cast(this) , m_io_service - , [=](aux::session_listen_socket* sock + , [=](aux::listen_socket_handle const& sock , udp::endpoint const& ep , span p , error_code& ec @@ -5690,7 +5690,7 @@ namespace { , std::move(m_dht_state)); for (auto& s : m_listen_sockets) - m_dht->new_socket(s.get()); + m_dht->new_socket(listen_socket_handle(s)); for (auto const& n : m_dht_router_nodes) { @@ -6704,11 +6704,13 @@ namespace { } // this is the DHT observer version. DHT is the implied source - void session_impl::set_external_address(aux::session_listen_socket* iface, address const& ip + void session_impl::set_external_address(aux::listen_socket_handle const& iface, address const& ip , address const& source) { - TORRENT_ASSERT(iface); - set_external_address(*static_cast(iface), ip, source_dht, source); + auto i = iface.m_sock.lock(); + TORRENT_ASSERT(i); + if (!i) return; + set_external_address(std::static_pointer_cast(i), ip, source_dht, source); } void session_impl::get_peers(sha1_hash const& ih) @@ -6815,7 +6817,7 @@ namespace { if (i->local_endpoint.address().is_v4() != ip.is_v4()) continue; - set_external_address(*i, ip, source_type, source); + set_external_address(i, ip, source_type, source); break; } } @@ -6828,10 +6830,10 @@ namespace { , [&](std::shared_ptr const& v) { return v->local_endpoint == local_endpoint; }); if (sock != m_listen_sockets.end()) - set_external_address(**sock, ip, source_type, source); + set_external_address(*sock, ip, source_type, source); } - void session_impl::set_external_address(listen_socket_t& sock + void session_impl::set_external_address(std::shared_ptr const& sock , address const& ip, int const source_type, address const& source) { #ifndef TORRENT_DISABLE_LOGGING @@ -6842,7 +6844,7 @@ namespace { } #endif - if (!sock.external_address.cast_vote(ip, source_type, source)) return; + if (!sock->external_address.cast_vote(ip, source_type, source)) return; #ifndef TORRENT_DISABLE_LOGGING session_log(" external IP updated"); @@ -6860,7 +6862,7 @@ namespace { // restart the DHT with a new node ID #ifndef TORRENT_DISABLE_DHT - if (m_dht) m_dht->update_node_id(&sock); + if (m_dht) m_dht->update_node_id(listen_socket_handle(sock)); #endif } diff --git a/src/torrent.cpp b/src/torrent.cpp index 2ac04eaef..8e4e56377 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -2632,10 +2632,10 @@ namespace libtorrent { { struct announce_state { - explicit announce_state(aux::session_listen_socket* s) + explicit announce_state(aux::listen_socket_handle const& s) : socket(s) {} - aux::session_listen_socket* socket; + aux::listen_socket_handle socket; // the tier is kept as INT_MAX until we find the first // tracker that works, then it's set to that tracker's @@ -2756,8 +2756,8 @@ namespace libtorrent { // update the endpoint list by adding entries for new listen sockets // and removing entries for non-existent ones std::vector::size_type valid_endpoints = 0; - m_ses.for_each_listen_socket([&](aux::session_listen_socket* s) { - if (s->is_ssl() != is_ssl_torrent()) + m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) { + if (s.is_ssl() != is_ssl_torrent()) return; for (auto& aep : ae.endpoints) { @@ -3073,7 +3073,7 @@ namespace libtorrent { // out external IP counter (and pass along the IP of the tracker to know // who to attribute this vote to) if (resp.external_ip != address() && !is_any(tracker_ip)) - m_ses.set_external_address(r.outgoing_socket->get_local_endpoint() + m_ses.set_external_address(r.outgoing_socket.get_local_endpoint() , resp.external_ip , aux::session_interface::source_tracker, tracker_ip); @@ -8713,10 +8713,10 @@ namespace libtorrent { { struct timer_state { - explicit timer_state(aux::session_listen_socket* s) + explicit timer_state(aux::listen_socket_handle const& s) : socket(s) {} - aux::session_listen_socket* socket; + aux::listen_socket_handle socket; int tier = INT_MAX; bool found_working = false; @@ -10894,10 +10894,10 @@ namespace { debug_log("*** increment tracker fail count [%d]", aep->fails); #endif } - else + else if (r.outgoing_socket) { #ifndef TORRENT_DISABLE_LOGGING - debug_log("*** no matching endpoint for request [%s, %s]", r.url.c_str(), print_endpoint(r.outgoing_socket->get_local_endpoint()).c_str()); + debug_log("*** no matching endpoint for request [%s, %s]", r.url.c_str(), print_endpoint(r.outgoing_socket.get_local_endpoint()).c_str()); #endif } diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp index 5088f3ffc..99e95a36f 100644 --- a/src/tracker_manager.cpp +++ b/src/tracker_manager.cpp @@ -173,7 +173,7 @@ namespace libtorrent { address tracker_connection::bind_interface() const { - return m_req.outgoing_socket->get_local_endpoint().address(); + return m_req.outgoing_socket.get_local_endpoint().address(); } void tracker_connection::sent_bytes(int bytes) @@ -375,7 +375,7 @@ namespace libtorrent { return p->on_receive_hostname(hostname, buf); } - void tracker_manager::send_hostname(aux::session_listen_socket* sock + void tracker_manager::send_hostname(aux::listen_socket_handle const& sock , char const* hostname, int const port , span p, error_code& ec, int const flags) { @@ -383,7 +383,7 @@ namespace libtorrent { m_send_fun_hostname(sock, hostname, port, p, ec, flags); } - void tracker_manager::send(aux::session_listen_socket* sock + void tracker_manager::send(aux::listen_socket_handle const& sock , udp::endpoint const& ep , span p , error_code& ec, int const flags) diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 62064ed5b..d57b1f0ba 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -134,8 +134,9 @@ namespace libtorrent { if (i != m_endpoints.end()) m_endpoints.erase(i); - // if that was the last one, fail the whole announce - if (m_endpoints.empty()) + // if that was the last one, or the listen socket was closed + // fail the whole announce + if (m_endpoints.empty() || !tracker_req().outgoing_socket) { tracker_connection::fail(ec, code, msg, interval, min_interval); return; @@ -194,12 +195,20 @@ namespace libtorrent { restart_read_timeout(); + if (!tracker_req().outgoing_socket) + { + fail(error_code(errors::invalid_listen_socket)); + return; + } + + auto bind_address = bind_interface(); + // look for an address that has the same kind as the one // we're listening on. To make sure the tracker get our // correct listening address. - bool is_v4 = bind_interface().is_v4(); + bool is_v4 = bind_address.is_v4(); #if TORRENT_USE_IPV6 - auto scope = is_v4 ? 0 : bind_interface().to_v6().scope_id(); + auto scope = is_v4 ? 0 : bind_address.to_v6().scope_id(); #endif for (auto const& addr : addresses) { diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 38a27d487..5659bdaa9 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -49,7 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bloom_filter.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/aux_/time.hpp" -#include "libtorrent/aux_/session_listen_socket.hpp" +#include "libtorrent/aux_/listen_socket_handle.hpp" #include "libtorrent/kademlia/node_id.hpp" #include "libtorrent/kademlia/routing_table.hpp" @@ -114,7 +114,7 @@ std::list> g_sent_packets; struct mock_socket final : socket_manager { bool has_quota() override { return true; } - bool send_packet(aux::session_listen_socket* s, entry& msg, udp::endpoint const& ep) override + bool send_packet(aux::listen_socket_handle const& s, entry& msg, udp::endpoint const& ep) override { // TODO: 3 ideally the mock_socket would contain this queue of packets, to // make tests independent @@ -123,31 +123,30 @@ struct mock_socket final : socket_manager } }; -struct mock_dht_socket final : aux::session_listen_socket +std::shared_ptr dummy_listen_socket(udp::endpoint src) { - mock_dht_socket() : m_external_address(addr4("236.0.0.1")), m_local_endpoint(addr4("192.168.4.1"), 6881) {} - explicit mock_dht_socket(address ep) : m_external_address(ep), m_local_endpoint(ep, 6881) {} + auto ret = std::make_shared(); + ret->local_endpoint = tcp::endpoint(src.address(), src.port()); + ret->external_address.cast_vote(src.address(), 1, rand_v4()); + return ret; +} - address get_external_address() override { return m_external_address; } - tcp::endpoint get_local_endpoint() override { return m_local_endpoint; } - - bool is_ssl() override { return false; } - - address m_external_address; - tcp::endpoint m_local_endpoint; -}; +std::shared_ptr dummy_listen_socket4() +{ + auto ret = std::make_shared(); + ret->local_endpoint = tcp::endpoint(addr4("192.168.4.1"), 6881); + ret->external_address.cast_vote(addr4("236.0.0.1"), 1, rand_v4()); + return ret; +} #if TORRENT_USE_IPV6 -struct mock_dht_socket6 final : aux::session_listen_socket +std::shared_ptr dummy_listen_socket6() { - address get_external_address() override { return m_external_address; } - tcp::endpoint get_local_endpoint() override { return m_local_endpoint; } - - bool is_ssl() override { return false; } - - address m_external_address = addr6("2002::1"); - tcp::endpoint m_local_endpoint = tcp::endpoint(addr6("2002::1"), 6881); -}; + auto ret = std::make_shared(); + ret->local_endpoint = tcp::endpoint(addr6("2002::1"), 6881); + ret->external_address.cast_vote(addr6("2002::1"), 1, rand_v6()); + return ret; +} #endif node* get_foreign_node_stub(node_id const&, std::string const&) @@ -516,10 +515,10 @@ void put_immutable_item_cb(int num, int expect) struct obs : dht::dht_observer { - void set_external_address(aux::session_listen_socket* s, address const& addr + void set_external_address(aux::listen_socket_handle const& s, address const& addr , address const& source) override { - static_cast(s)->m_external_address = addr; + s.impl()->external_address.cast_vote(addr, 1, rand_v4()); } void get_peers(sha1_hash const& ih) override {} @@ -562,10 +561,10 @@ struct dht_test_setup { explicit dht_test_setup(udp::endpoint src) : sett(test_settings()) - , ds(src.address()) + , ls(dummy_listen_socket(src)) , dht_storage(dht_default_storage_constructor(sett)) , source(src) - , dht_node(&ds, &s, sett + , dht_node(ls, &s, sett , node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage) { dht_storage->update_node_ids({node_id::min()}); @@ -573,7 +572,7 @@ struct dht_test_setup dht_settings sett; mock_socket s; - mock_dht_socket ds; + std::shared_ptr ls; obs observer; counters cnt; std::unique_ptr dht_storage; @@ -2630,8 +2629,8 @@ TORRENT_TEST(dht_dual_stack) // TODO: 3 use dht_test_setup class to simplify the node setup dht_settings sett = test_settings(); mock_socket s; - mock_dht_socket sock4; - mock_dht_socket6 sock6; + auto sock4 = dummy_listen_socket4(); + auto sock6 = dummy_listen_socket6(); obs observer; counters cnt; node* node4p = nullptr, *node6p = nullptr; @@ -2644,8 +2643,8 @@ TORRENT_TEST(dht_dual_stack) }; std::unique_ptr dht_storage(dht_default_storage_constructor(sett)); dht_storage->update_node_ids({node_id(nullptr)}); - dht::node node4(&sock4, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage); - dht::node node6(&sock6, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage); + dht::node node4(sock4, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage); + dht::node node6(sock6, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node, *dht_storage); node4p = &node4; node6p = &node6; @@ -3113,7 +3112,9 @@ TORRENT_TEST(node_set_id) { dht_test_setup t(udp::endpoint(rand_v4(), 20)); node_id old_nid = t.dht_node.nid(); - t.observer.set_external_address(&t.ds, addr4("237.0.0.1"), rand_v4()); + // put in a few votes to make sure the address really changes + for (int i = 0; i < 25; ++i) + t.observer.set_external_address(aux::listen_socket_handle(t.ls), addr4("237.0.0.1"), rand_v4()); t.dht_node.update_node_id(); TEST_CHECK(old_nid != t.dht_node.nid()); // now that we've changed the node's id, make sure the id sent in outgoing messages @@ -3142,13 +3143,13 @@ TORRENT_TEST(read_only_node) dht_settings sett = test_settings(); sett.read_only = true; mock_socket s; - mock_dht_socket ds; + auto ls = dummy_listen_socket4(); obs observer; counters cnt; std::unique_ptr dht_storage(dht_default_storage_constructor(sett)); dht_storage->update_node_ids({node_id(nullptr)}); - dht::node node(&ds, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); + dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); udp::endpoint source(addr("10.0.0.1"), 20); bdecode_node response; msg_args args; @@ -3231,13 +3232,13 @@ TORRENT_TEST(invalid_error_msg) // TODO: 3 use dht_test_setup class to simplify the node setup dht_settings sett = test_settings(); mock_socket s; - mock_dht_socket ds; + auto ls = dummy_listen_socket4(); obs observer; counters cnt; std::unique_ptr dht_storage(dht_default_storage_constructor(sett)); dht_storage->update_node_ids({node_id(nullptr)}); - dht::node node(&ds, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); + dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); udp::endpoint source(addr("10.0.0.1"), 20); entry e; @@ -3319,15 +3320,15 @@ TORRENT_TEST(rpc_invalid_error_msg) // TODO: 3 use dht_test_setup class to simplify the node setup dht_settings sett = test_settings(); mock_socket s; - mock_dht_socket ds; + auto ls = dummy_listen_socket4(); obs observer; counters cnt; dht::routing_table table(node_id(), udp::v4(), 8, sett, &observer); - dht::rpc_manager rpc(node_id(), sett, table, &ds, &s, &observer); + dht::rpc_manager rpc(node_id(), sett, table, ls, &s, &observer); std::unique_ptr dht_storage(dht_default_storage_constructor(sett)); dht_storage->update_node_ids({node_id(nullptr)}); - dht::node node(&ds, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); + dht::node node(ls, &s, sett, node_id(nullptr), &observer, cnt, get_foreign_node_stub, *dht_storage); udp::endpoint source(addr("10.0.0.1"), 20); diff --git a/test/test_primitives.cpp b/test/test_primitives.cpp index e2ce3764d..f3bcb5997 100644 --- a/test/test_primitives.cpp +++ b/test/test_primitives.cpp @@ -49,7 +49,7 @@ TORRENT_TEST(primitives) // make sure the retry interval keeps growing // on failing announces announce_entry ae("dummy"); - ae.endpoints.emplace_back(nullptr); + ae.endpoints.emplace_back(aux::listen_socket_handle()); int last = 0; auto const tracker_backoff = 250; for (int i = 0; i < 10; ++i)