diff --git a/ChangeLog b/ChangeLog index 3770040f7f..9310c08d8b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ 2.1.0 not released + * fix peer_info holding an i2p destination * implement i2p_pex, peer exchange support for i2p torrents * deprecate torrent_alert::torrent_name() * requires OpenSSL minimum version 1.1.0 with SNI support diff --git a/bindings/python/src/peer_info.cpp b/bindings/python/src/peer_info.cpp index a8bd773f7b..400a953d7f 100644 --- a/bindings/python/src/peer_info.cpp +++ b/bindings/python/src/peer_info.cpp @@ -28,13 +28,22 @@ std::int64_t get_download_queue_time(peer_info const& pi) tuple get_local_endpoint(peer_info const& pi) { - return boost::python::make_tuple(pi.local_endpoint.address().to_string(), pi.local_endpoint.port()); + auto const ep = pi.local_endpoint(); + return boost::python::make_tuple(ep.address().to_string(), ep.port()); } +tuple get_remote_endpoint(peer_info const& pi) +{ + auto const ep = pi.remote_endpoint(); + return boost::python::make_tuple(ep.address().to_string(), ep.port()); +} + +#if TORRENT_ABI_VERSION < 4 tuple get_ip(peer_info const& pi) { return boost::python::make_tuple(pi.ip.address().to_string(), pi.ip.port()); } +#endif list get_pieces(peer_info const& pi) { @@ -61,7 +70,9 @@ void bind_peer_info() .add_property("source", make_getter(&peer_info::source, by_value())) .add_property("read_state", make_getter(&peer_info::read_state, by_value())) .add_property("write_state", make_getter(&peer_info::write_state, by_value())) +#if TORRENT_ABI_VERSION < 4 .add_property("ip", get_ip) +#endif .def_readonly("up_speed", &peer_info::up_speed) .def_readonly("down_speed", &peer_info::down_speed) .def_readonly("payload_up_speed", &peer_info::payload_up_speed) @@ -107,10 +118,11 @@ void bind_peer_info() #if TORRENT_ABI_VERSION == 1 .def_readonly("estimated_reciprocation_rate", &peer_info::estimated_reciprocation_rate) #endif - .add_property("local_endpoint", get_local_endpoint) #if TORRENT_USE_I2P .def("i2p_destination", &peer_info::i2p_destination) #endif + .def("local_endpoint", get_local_endpoint) + .def("remote_endpoint", get_remote_endpoint) ; // flags diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 59469c67b1..bfe642de93 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -304,7 +304,7 @@ int peer_index(lt::tcp::endpoint addr, std::vector const& peers) { using namespace lt; auto i = std::find_if(peers.begin(), peers.end() - , [&addr](peer_info const& pi) { return pi.ip == addr; }); + , [&addr](peer_info const& pi) { return pi.remote_endpoint() == addr; }); if (i == peers.end()) return -1; return int(i - peers.begin()); @@ -401,7 +401,7 @@ int print_peer_info(std::string& out else #endif { - std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->ip).c_str()); + std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->remote_endpoint()).c_str()); out += str; } } @@ -413,7 +413,7 @@ int print_peer_info(std::string& out else #endif { - std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->local_endpoint).c_str()); + std::snprintf(str, sizeof(str), "%-30s ", ::print_endpoint(i->local_endpoint()).c_str()); out += str; } } diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index ace708733f..588ca9ca3e 100644 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -13,6 +13,8 @@ see LICENSE file. #ifndef TORRENT_PEER_INFO_HPP_INCLUDED #define TORRENT_PEER_INFO_HPP_INCLUDED +#include + #include "libtorrent/socket.hpp" #include "libtorrent/aux_/deadline_timer.hpp" #include "libtorrent/peer_id.hpp" @@ -365,18 +367,33 @@ TORRENT_VERSION_NAMESPACE_2 TORRENT_DEPRECATED int estimated_reciprocation_rate; #endif +#if TORRENT_ABI_VERSION < 4 + TORRENT_DEPRECATED tcp::endpoint ip; +#endif + + private: + + struct ip_endpoint { + tcp::endpoint remote; + tcp::endpoint local; + }; + // the sha256_hash is the hash of the i2p destination + std::variant m_endpoint; + + public: + // the IP-address to this peer. The type is an asio endpoint. For // more info, see the asio_ documentation. This field is not valid for // i2p peers. Instead use the i2p_destination() function. // // .. _asio: http://asio.sourceforge.net/asio-0.3.8/doc/asio/reference.html - tcp::endpoint ip; + tcp::endpoint remote_endpoint() const; // the IP and port pair the socket is bound to locally. i.e. the IP // address of the interface it's going out over. This may be useful for // multi-homed clients with multiple interfaces to the internet. // This field is not valid for i2p peers. - tcp::endpoint local_endpoint; + tcp::endpoint local_endpoint() const; // The peer is not waiting for any external events to // send or receive data. @@ -402,6 +419,9 @@ TORRENT_VERSION_NAMESPACE_2 bandwidth_state_flags_t read_state; bandwidth_state_flags_t write_state; + // internal + void set_endpoints(tcp::endpoint const& local, tcp::endpoint const& remote); + #if TORRENT_USE_I2P // If this peer is an i2p peer, this function returns the destination // address of the peer diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index fcd3198ce7..379807aebf 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -4642,9 +4642,8 @@ namespace { if (!(p.flags & peer_info::i2p_socket)) #endif { - p.ip = remote(); error_code ec; - p.local_endpoint = get_socket().local_endpoint(ec); + p.set_endpoints(get_socket().local_endpoint(ec), remote()); } if (m_snubbed) p.flags |= peer_info::snubbed; diff --git a/src/peer_info.cpp b/src/peer_info.cpp index 2d6fa86104..bf7136b4c4 100644 --- a/src/peer_info.cpp +++ b/src/peer_info.cpp @@ -17,26 +17,46 @@ namespace libtorrent { peer_info::peer_info(peer_info&&) = default; peer_info& peer_info::operator=(peer_info const&) = default; + tcp::endpoint peer_info::remote_endpoint() const + { +#if TORRENT_USE_I2P + if (flags & i2p_socket) return {}; +#endif + TORRENT_ASSERT(std::holds_alternative(m_endpoint)); + return std::get(m_endpoint).remote; + } + + tcp::endpoint peer_info::local_endpoint() const + { +#if TORRENT_USE_I2P + if (flags & i2p_socket) return {}; +#endif + TORRENT_ASSERT(std::holds_alternative(m_endpoint)); + return std::get(m_endpoint).local; + } + + void peer_info::set_endpoints(tcp::endpoint const& local, tcp::endpoint const& remote) + { + TORRENT_ASSERT(!(flags & i2p_socket)); + m_endpoint = ip_endpoint{remote, local}; +#if TORRENT_ABI_VERSION < 4 + ip = remote; +#endif + } + #if TORRENT_USE_I2P sha256_hash peer_info::i2p_destination() const { sha256_hash ret; if (!(flags & i2p_socket)) return ret; - - char const* destination = reinterpret_cast(&ip); - static_assert(sizeof(tcp::endpoint) * 2 >= sizeof(sha256_hash), "tcp::endpoint is smaller than expected"); - - std::memcpy(ret.data(), destination, ret.size()); - return ret; + TORRENT_ASSERT(std::holds_alternative(m_endpoint)); + return std::get(m_endpoint); } void peer_info::set_i2p_destination(sha256_hash dest) { flags |= i2p_socket; - char* destination = reinterpret_cast(&ip); - static_assert(sizeof(tcp::endpoint) * 2 >= sizeof(sha256_hash), "tcp::endpoint is smaller than expected"); - - std::memcpy(destination, dest.data(), dest.size()); + m_endpoint = dest; } #endif }