diff --git a/ChangeLog b/ChangeLog index f33676d46..1d67e45b3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ * support magnet link parameters with number siffixes * consistently use "lt" namespace in examples and documentation * fix Mingw build to use native cryptoAPI + * uPnP/NAT-PMP errors no longer set the client's advertised listen port to zero 1.2 release diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index b5f2a92e0..b6ca37460 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -133,15 +133,15 @@ namespace aux { only_outgoing }; + struct listen_port_mapping + { + port_mapping_t mapping = port_mapping_t{-1}; + int port = 0; + }; + struct listen_socket_t { - listen_socket_t() - { - tcp_port_mapping[0] = port_mapping_t{-1}; - tcp_port_mapping[1] = port_mapping_t{-1}; - udp_port_mapping[0] = port_mapping_t{-1}; - udp_port_mapping[1] = port_mapping_t{-1}; - } + listen_socket_t() = default; // listen_socket_t should not be copied or moved because // references to it are held by the DHT and tracker announce @@ -169,19 +169,35 @@ namespace aux { // had to retry binding with a higher port int original_port = 0; - // this is typically set to the same as the local - // listen port. In case a NAT port forward was - // successfully opened, this will be set to the - // port that is open on the external (NAT) interface - // on the NAT box itself. This is the port that has - // to be published to peers, since this is the port - // the client is reachable through. - int tcp_external_port = 0; - int udp_external_port = 0; + // tcp_external_port and udp_external_port return the port which + // should be published to peers/trackers for this socket + // If there are active NAT mappings the return value will be + // the external port returned by the NAT router, otherwise the + // local listen port is returned + int tcp_external_port() + { + for (auto const& m : tcp_port_mapping) + { + if (m.port != 0) return m.port; + } + return local_endpoint.port(); + } + + int udp_external_port() + { + for (auto const& m : udp_port_mapping) + { + if (m.port != 0) return m.port; + } + if (udp_sock) return udp_sock->sock.local_port(); + return 0; + } // 0 is natpmp 1 is upnp - port_mapping_t tcp_port_mapping[2]; - port_mapping_t udp_port_mapping[2]; + // the order of these arrays determines the priorty in + // which their ports will be announced to peers + aux::array tcp_port_mapping; + aux::array udp_port_mapping; // indicates whether this is an SSL listen socket or not transport ssl = transport::plaintext; diff --git a/include/libtorrent/units.hpp b/include/libtorrent/units.hpp index 65dcd77a3..dac07346a 100644 --- a/include/libtorrent/units.hpp +++ b/include/libtorrent/units.hpp @@ -94,11 +94,15 @@ namespace libtorrent { namespace aux { UnderlyingType m_val; }; - // meta function to return the underlying type of a strong_typedef, or the - // type itself if it isn't a strong_typedef - template + // meta function to return the underlying type of a strong_typedef or enumeration + // , or the type itself if it isn't a strong_typedef + template struct underlying_index_t { using type = T; }; + template + struct underlying_index_t::value>::type> + { using type = typename std::underlying_type::type; }; + template struct underlying_index_t> { using type = U; }; diff --git a/simulation/test_dht_rate_limit.cpp b/simulation/test_dht_rate_limit.cpp index fc93f3371..a16873def 100644 --- a/simulation/test_dht_rate_limit.cpp +++ b/simulation/test_dht_rate_limit.cpp @@ -61,7 +61,7 @@ struct obs : dht::dht_observer , address const& /* source */) override {} int get_listen_port(lt::aux::transport, lt::aux::listen_socket_handle const& s) override - { return s.get()->udp_external_port; } + { return s.get()->udp_external_port(); } void get_peers(sha1_hash const&) override {} void outgoing_get_peers(sha1_hash const& /* target */ , sha1_hash const& /* sent_target */, udp::endpoint const& /* ep */) override {} diff --git a/src/session_impl.cpp b/src/session_impl.cpp index f7ca7da20..a06ce6d5f 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1521,8 +1521,7 @@ namespace aux { return ret; } - ret->tcp_external_port = ret->local_endpoint.port(); - TORRENT_ASSERT(ret->tcp_external_port == bind_ep.port() + TORRENT_ASSERT(ret->local_endpoint.port() == bind_ep.port() || bind_ep.port() == 0); ret->sock->listen(m_settings.get_int(settings_pack::listen_queue_size), ec); @@ -1635,7 +1634,6 @@ namespace aux { return ret; } - 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 @@ -1673,7 +1671,7 @@ namespace aux { { session_log(" listening on: %s TCP port: %d UDP port: %d" , bind_ep.address().to_string().c_str() - , ret->tcp_external_port, ret->udp_external_port); + , ret->tcp_external_port(), ret->udp_external_port()); } #endif return ret; @@ -2144,13 +2142,17 @@ namespace aux { if ((mask & remap_natpmp) && s.natpmp_mapper) { - map_port(*s.natpmp_mapper, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]); - map_port(*s.natpmp_mapper, portmap_protocol::udp, make_tcp(udp_ep), s.udp_port_mapping[0]); + map_port(*s.natpmp_mapper, portmap_protocol::tcp, tcp_ep + , s.tcp_port_mapping[portmap_transport::natpmp].mapping); + map_port(*s.natpmp_mapper, portmap_protocol::udp, make_tcp(udp_ep) + , s.udp_port_mapping[portmap_transport::natpmp].mapping); } if ((mask & remap_upnp) && m_upnp) { - map_port(*m_upnp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[1]); - map_port(*m_upnp, portmap_protocol::udp, make_tcp(udp_ep), s.udp_port_mapping[1]); + map_port(*m_upnp, portmap_protocol::tcp, tcp_ep + , s.tcp_port_mapping[portmap_transport::upnp].mapping); + map_port(*m_upnp, portmap_protocol::udp, make_tcp(udp_ep) + , s.udp_port_mapping[portmap_transport::upnp].mapping); } } @@ -2183,7 +2185,7 @@ namespace aux { }); if (ls != m_listen_sockets.end()) - return (*ls)->udp_external_port; + return (*ls)->udp_external_port(); else return -1; } @@ -5369,9 +5371,9 @@ namespace aux { // connections. We may be able to accept uTP connections though, so // announce the UDP port instead if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none) - return std::uint16_t(sock->udp_external_port); + return std::uint16_t(sock->udp_external_port()); else - return std::uint16_t(sock->tcp_external_port); + return std::uint16_t(sock->tcp_external_port()); } #ifdef TORRENT_USE_OPENSSL @@ -5380,14 +5382,14 @@ namespace aux { if (s->ssl == transport::plaintext) { if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none) - return std::uint16_t(s->udp_external_port); + return std::uint16_t(s->udp_external_port()); else - return std::uint16_t(s->tcp_external_port); + return std::uint16_t(s->tcp_external_port()); } } return 0; #else - return std::uint16_t(m_listen_sockets.front()->tcp_external_port); + return std::uint16_t(m_listen_sockets.front()->tcp_external_port()); #endif } @@ -5408,9 +5410,9 @@ namespace aux { // connections. We may be able to accept uTP connections though, so // announce the UDP port instead if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none) - return std::uint16_t(sock->udp_external_port); + return std::uint16_t(sock->udp_external_port()); else - return std::uint16_t(sock->tcp_external_port); + return std::uint16_t(sock->tcp_external_port()); } if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none) @@ -5421,9 +5423,9 @@ namespace aux { if (s->ssl == transport::ssl) { if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none) - return std::uint16_t(s->udp_external_port); + return std::uint16_t(s->udp_external_port()); else - return std::uint16_t(s->tcp_external_port); + return std::uint16_t(s->tcp_external_port()); } } #else @@ -5447,7 +5449,7 @@ namespace aux { if (alt_socket != m_listen_sockets.end()) socket = alt_socket->get(); } - return socket->udp_external_port; + return socket->udp_external_port(); } int session_impl::listen_port(transport const ssl, address const& local_addr) @@ -5461,7 +5463,7 @@ namespace aux { || (listen_addr.is_v4() == local_addr.is_v4() && listen_addr.is_unspecified())); }); if (socket != m_listen_sockets.end()) - return (*socket)->tcp_external_port; + return (*socket)->tcp_external_port(); return 0; } @@ -5521,13 +5523,13 @@ namespace aux { bool find_tcp_port_mapping(portmap_transport const transport , port_mapping_t mapping, std::shared_ptr const& ls) { - return ls->tcp_port_mapping[static_cast(transport)] == mapping; + return ls->tcp_port_mapping[transport].mapping == mapping; } bool find_udp_port_mapping(portmap_transport const transport , port_mapping_t mapping, std::shared_ptr const& ls) { - return ls->udp_port_mapping[static_cast(transport)] == mapping; + return ls->udp_port_mapping[transport].mapping == mapping; } } @@ -5572,8 +5574,8 @@ namespace aux { (*ls)->external_address.cast_vote(ip, source_router, address()); } - if (tcp) (*ls)->tcp_external_port = port; - else (*ls)->udp_external_port = port; + if (tcp) (*ls)->tcp_port_mapping[transport].port = port; + else (*ls)->tcp_port_mapping[transport].port = port; } if (!ec && m_alerts.should_post()) @@ -6731,8 +6733,8 @@ namespace aux { { for (auto& s : m_listen_sockets) { - s->tcp_port_mapping[0] = port_mapping_t{-1}; - s->udp_port_mapping[0] = port_mapping_t{-1}; + s->tcp_port_mapping[portmap_transport::natpmp] = listen_port_mapping(); + s->udp_port_mapping[portmap_transport::natpmp] = listen_port_mapping(); if (!s->natpmp_mapper) continue; s->natpmp_mapper->close(); s->natpmp_mapper.reset(); @@ -6746,8 +6748,8 @@ namespace aux { m_upnp->close(); for (auto& s : m_listen_sockets) { - s->tcp_port_mapping[1] = port_mapping_t{-1}; - s->udp_port_mapping[1] = port_mapping_t{-1}; + s->tcp_port_mapping[portmap_transport::upnp] = listen_port_mapping(); + s->udp_port_mapping[portmap_transport::upnp] = listen_port_mapping(); } m_upnp.reset(); } diff --git a/test/test_dht.cpp b/test/test_dht.cpp index 71ece3920..5450a1257 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -525,7 +525,7 @@ struct obs : dht::dht_observer } int get_listen_port(aux::transport, aux::listen_socket_handle const& s) override - { return s.get()->udp_external_port; } + { return s.get()->udp_external_port(); } void get_peers(sha1_hash const&) override {} void outgoing_get_peers(sha1_hash const& /*target*/