diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index da9ce25bf..927333590 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -1366,7 +1366,7 @@ namespace libtorrent struct TORRENT_EXPORT portmap_alert TORRENT_FINAL : alert { // internal - portmap_alert(aux::stack_allocator& alloc, int i, int port, int t); + portmap_alert(aux::stack_allocator& alloc, int i, int port, int t, int protocol); TORRENT_DEFINE_ALERT(portmap_alert, 51) @@ -1382,6 +1382,15 @@ namespace libtorrent // 0 for NAT-PMP and 1 for UPnP. int map_type; + + enum protocol_t + { + tcp, + udp + }; + + // the protocol this mapping was for. one of protocol_t enums + int protocol; }; #ifndef TORRENT_DISABLE_LOGGING diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 391f1c24b..a5f066498 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -335,7 +335,7 @@ namespace libtorrent , std::vector
const& addresses, int port); #endif - void maybe_update_udp_mapping(int nat, int local_port, int external_port); + void maybe_update_udp_mapping(int nat, bool ssl, int local_port, int external_port); #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) torrent const* find_encrypted_torrent( @@ -354,7 +354,7 @@ namespace libtorrent // called when a port mapping is successful, or a router returns // a failure to map a port void on_port_mapping(int mapping, address const& ip, int port - , error_code const& ec, int nat_transport); + , int protocol, error_code const& ec, int nat_transport); bool is_aborted() const TORRENT_OVERRIDE { return m_abort; } bool is_paused() const TORRENT_OVERRIDE { return m_paused; } diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp index 6cb9927f9..f4b2be886 100644 --- a/include/libtorrent/natpmp.hpp +++ b/include/libtorrent/natpmp.hpp @@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/disable_warnings_push.hpp" #include -#include +#include #include #include "libtorrent/aux_/disable_warnings_pop.hpp" @@ -54,7 +54,7 @@ namespace libtorrent // int: port mapping index // int: external port // std::string: error message -typedef boost::function portmap_callback_t; +typedef boost::function portmap_callback_t; typedef boost::function log_callback_t; class natpmp : public boost::enable_shared_from_this diff --git a/include/libtorrent/udp_socket.hpp b/include/libtorrent/udp_socket.hpp index 675e95748..81f79f6b2 100644 --- a/include/libtorrent/udp_socket.hpp +++ b/include/libtorrent/udp_socket.hpp @@ -79,14 +79,7 @@ namespace libtorrent , dont_queue = 8 }; - bool is_open() const - { - return m_ipv4_sock.is_open() -#if TORRENT_USE_IPV6 - || m_ipv6_sock.is_open() -#endif - ; - } + bool is_open() const { return m_abort == false; } io_service& get_io_service() { return m_ipv4_sock.get_io_service(); } void subscribe(udp_socket_observer* o); @@ -144,7 +137,7 @@ namespace libtorrent udp::endpoint proxy_addr() const { return m_proxy_addr; } - protected: + private: struct queued_packet { @@ -170,12 +163,12 @@ namespace libtorrent ; } - private: - // non-copyable udp_socket(udp_socket const&); udp_socket& operator=(udp_socket const&); + void close_impl(); + // observers on this udp socket std::vector m_observers; std::vector m_added_observers; diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index 42ce868ec..2421b9cd1 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -43,7 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/resolver.hpp" #include -#include +#include #include #include #include @@ -100,9 +100,7 @@ namespace libtorrent // int: external port // std::string: error message // an empty string as error means success -// a port-mapping index of -1 means it's -// an informational log message -typedef boost::function portmap_callback_t; +typedef boost::function portmap_callback_t; typedef boost::function log_callback_t; struct parse_state diff --git a/src/alert.cpp b/src/alert.cpp index 4bd7bc9ed..670454fe8 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -774,6 +774,8 @@ namespace libtorrent { static char const* const nat_type_str[] = {"NAT-PMP", "UPnP"}; + static char const* const protocol_str[] = {"TCP", "UDP"}; + static char const* const socket_type_str[] = { "null", "TCP", @@ -911,15 +913,16 @@ namespace libtorrent { + ": " + convert_from_native(error.message()); } - portmap_alert::portmap_alert(aux::stack_allocator&, int i, int port, int t) - : mapping(i), external_port(port), map_type(t) + portmap_alert::portmap_alert(aux::stack_allocator&, int i, int port, int t + , int proto) + : mapping(i), external_port(port), map_type(t), protocol(proto) {} std::string portmap_alert::message() const { char ret[200]; - snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %u" - , nat_type_str[map_type], external_port); + snprintf(ret, sizeof(ret), "successfully mapped port using %s. external port: %s/%u" + , nat_type_str[map_type], protocol_str[protocol], external_port); return ret; } diff --git a/src/natpmp.cpp b/src/natpmp.cpp index f9338c12f..44d4e4e94 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -185,10 +185,11 @@ void natpmp::disable(error_code const& ec, mutex::scoped_lock& l) , end(m_mappings.end()); i != end; ++i) { if (i->protocol == none) continue; + int const proto = i->protocol; i->protocol = none; int index = i - m_mappings.begin(); l.unlock(); - m_callback(index, address(), 0, ec); + m_callback(index, address(), 0, proto, ec); l.lock(); } close_impl(l); @@ -563,15 +564,18 @@ void natpmp::on_reply(error_code const& e if (result >= 1 && result <= 5) ev = errors[result - 1]; m->expires = aux::time_now() + hours(2); + int const proto = m->protocol; l.unlock(); - m_callback(index, address(), 0, error_code(ev, get_libtorrent_category())); + m_callback(index, address(), 0, proto + , error_code(ev, get_libtorrent_category())); l.lock(); } else if (m->action == mapping_t::action_add) { + int const proto = m->protocol; l.unlock(); - m_callback(index, m_external_ip, m->external_port, - error_code(errors::no_error, get_libtorrent_category())); + m_callback(index, m_external_ip, m->external_port, proto + , error_code(errors::no_error, get_libtorrent_category())); l.lock(); } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 214ecd054..86d961247 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2040,7 +2040,7 @@ retry: } #ifdef TORRENT_USE_OPENSSL - int ssl_port = m_settings.get_int(settings_pack::ssl_listen); + int const ssl_port = m_settings.get_int(settings_pack::ssl_listen); udp::endpoint ssl_bind_if(m_listen_interface.address(), ssl_port); // if ssl port is 0, we don't want to listen on an SSL port @@ -2062,7 +2062,27 @@ retry: } ec.clear(); } - // TODO: 3 port map SSL udp socket here + else + { + maybe_update_udp_mapping(0, true, ssl_port, ssl_port); + maybe_update_udp_mapping(1, true, ssl_port, ssl_port); + } + } + else + { + m_ssl_udp_socket.close(); + + // if there are mappings for the SSL socket, delete them now + if (m_ssl_udp_mapping[0] != -1 && m_natpmp) + { + m_natpmp->delete_mapping(m_ssl_udp_mapping[0]); + m_ssl_udp_mapping[0] = -1; + } + if (m_ssl_udp_mapping[1] != -1 && m_upnp) + { + m_upnp->delete_mapping(m_ssl_udp_mapping[1]); + m_ssl_udp_mapping[1] = -1; + } } #endif // TORRENT_USE_OPENSSL @@ -2094,8 +2114,8 @@ retry: else { m_external_udp_port = m_udp_socket.local_port(); - maybe_update_udp_mapping(0, m_listen_interface.port(), m_listen_interface.port()); - maybe_update_udp_mapping(1, m_listen_interface.port(), m_listen_interface.port()); + maybe_update_udp_mapping(0, false, m_listen_interface.port(), m_listen_interface.port()); + maybe_update_udp_mapping(1, false, m_listen_interface.port(), m_listen_interface.port()); } // we made it! now post all the listen_succeeded_alerts @@ -2174,7 +2194,11 @@ retry: if (m_tcp_mapping[0] != -1) m_natpmp->delete_mapping(m_tcp_mapping[0]); m_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp, tcp_port, tcp_port); #ifdef TORRENT_USE_OPENSSL - if (m_ssl_tcp_mapping[0] != -1) m_natpmp->delete_mapping(m_ssl_tcp_mapping[0]); + if (m_ssl_tcp_mapping[0] != -1) + { + m_natpmp->delete_mapping(m_ssl_tcp_mapping[0]); + m_ssl_tcp_mapping[0] = -1; + } if (ssl_port > 0) m_ssl_tcp_mapping[0] = m_natpmp->add_mapping(natpmp::tcp , ssl_port, ssl_port); #endif @@ -2184,7 +2208,11 @@ retry: if (m_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_tcp_mapping[1]); m_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp, tcp_port, tcp_port); #ifdef TORRENT_USE_OPENSSL - if (m_ssl_tcp_mapping[1] != -1) m_upnp->delete_mapping(m_ssl_tcp_mapping[1]); + if (m_ssl_tcp_mapping[1] != -1) + { + m_upnp->delete_mapping(m_ssl_tcp_mapping[1]); + m_ssl_tcp_mapping[1] = -1; + } if (ssl_port > 0) m_ssl_tcp_mapping[1] = m_upnp->add_mapping(upnp::tcp , ssl_port, ssl_port); #endif @@ -5359,6 +5387,11 @@ retry: boost::uint16_t session_impl::ssl_listen_port() const { #ifdef TORRENT_USE_OPENSSL + + // honor the SSL listen port being disabled + if (m_settings.get_int(settings_pack::ssl_listen) == 0) + return 0; + // if peer connections are set up to be received over a socks // proxy, and it's the same one as we're using for the tracker // just tell the tracker the socks5 port we're listening on @@ -5427,7 +5460,7 @@ retry: } void session_impl::on_port_mapping(int mapping, address const& ip, int port - , error_code const& ec, int map_transport) + , int protocol, error_code const& ec, int map_transport) { TORRENT_ASSERT(is_single_thread()); @@ -5438,7 +5471,8 @@ retry: m_external_udp_port = port; if (m_alerts.should_post()) m_alerts.emplace_alert(mapping, port - , map_transport); + , map_transport, protocol == natpmp::udp + ? portmap_alert::udp : portmap_alert::tcp); return; } @@ -5457,7 +5491,8 @@ retry: } if (m_alerts.should_post()) m_alerts.emplace_alert(mapping, port - , map_transport); + , map_transport, protocol == natpmp::udp + ? portmap_alert::udp : portmap_alert::tcp); return; } @@ -5471,7 +5506,8 @@ retry: { if (m_alerts.should_post()) m_alerts.emplace_alert(mapping, port - , map_transport); + , map_transport, protocol == natpmp::udp + ? portmap_alert::udp : portmap_alert::tcp); } } @@ -5869,38 +5905,45 @@ retry: #endif - void session_impl::maybe_update_udp_mapping(int nat, int local_port, int external_port) + void session_impl::maybe_update_udp_mapping(int const nat, bool const ssl + , int const local_port, int const external_port) { int local, external, protocol; +#ifdef TORRENT_USE_OPENSSL + int* mapping = ssl ? m_ssl_udp_mapping : m_udp_mapping; +#else + TORRENT_UNUSED(ssl); + int* mapping = m_udp_mapping; +#endif if (nat == 0 && m_natpmp) { - if (m_udp_mapping[nat] != -1) + if (mapping[nat] != -1) { - if (m_natpmp->get_mapping(m_udp_mapping[nat], local, external, protocol)) + if (m_natpmp->get_mapping(mapping[nat], local, external, protocol)) { // we already have a mapping. If it's the same, don't do anything if (local == local_port && external == external_port && protocol == natpmp::udp) return; } - m_natpmp->delete_mapping(m_udp_mapping[nat]); + m_natpmp->delete_mapping(mapping[nat]); } - m_udp_mapping[nat] = m_natpmp->add_mapping(natpmp::udp + mapping[nat] = m_natpmp->add_mapping(natpmp::udp , local_port, external_port); return; } else if (nat == 1 && m_upnp) { - if (m_udp_mapping[nat] != -1) + if (mapping[nat] != -1) { - if (m_upnp->get_mapping(m_udp_mapping[nat], local, external, protocol)) + if (m_upnp->get_mapping(mapping[nat], local, external, protocol)) { // we already have a mapping. If it's the same, don't do anything if (local == local_port && external == external_port && protocol == natpmp::udp) return; } - m_upnp->delete_mapping(m_udp_mapping[nat]); + m_upnp->delete_mapping(mapping[nat]); } - m_udp_mapping[nat] = m_upnp->add_mapping(upnp::udp + mapping[nat] = m_upnp->add_mapping(upnp::udp , local_port, external_port); return; } @@ -6602,12 +6645,12 @@ retry: // into the session_impl. m_natpmp = boost::make_shared(boost::ref(m_io_service) , boost::bind(&session_impl::on_port_mapping - , this, _1, _2, _3, _4, 0) + , this, _1, _2, _3, _4, _5, 0) , boost::bind(&session_impl::on_port_map_log , this, _1, 0)); m_natpmp->start(); - int ssl_port = ssl_listen_port(); + int const ssl_port = ssl_listen_port(); if (m_listen_interface.port() > 0) { @@ -6639,7 +6682,7 @@ retry: , m_listen_interface.address() , m_settings.get_str(settings_pack::user_agent) , boost::bind(&session_impl::on_port_mapping - , this, _1, _2, _3, _4, 1) + , this, _1, _2, _3, _4, _5, 1) , boost::bind(&session_impl::on_port_map_log , this, _1, 1) , m_settings.get_bool(settings_pack::upnp_ignore_nonrouters)); diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index f7e26a0ea..a923a8af6 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -78,7 +78,7 @@ udp_socket::udp_socket(io_service& ios) , m_queue_packets(false) , m_tunnel_packets(false) , m_force_proxy(false) - , m_abort(false) + , m_abort(true) , m_outstanding_ops(0) #if TORRENT_USE_IPV6 , m_v6_write_subscribed(false) @@ -307,7 +307,11 @@ void udp_socket::on_read(error_code const& ec, udp::socket* s) } return; } - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; @@ -493,7 +497,11 @@ void udp_socket::on_read_impl(udp::endpoint const& ep return; } - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } return; } @@ -516,7 +524,11 @@ void udp_socket::on_read_impl(udp::endpoint const& ep void udp_socket::setup_read(udp::socket* s) { - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } #if TORRENT_USE_IPV6 if (s == &m_ipv6_sock) @@ -774,17 +786,13 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec) CHECK_MAGIC; TORRENT_ASSERT(is_single_thread()); - TORRENT_ASSERT(m_abort == false); - if (m_abort) - { - ec = boost::asio::error::operation_aborted; - return; - } + m_abort = false; if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec); #if TORRENT_USE_IPV6 if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec); #endif + ec.clear(); if (ep.address().is_v4()) { @@ -858,7 +866,11 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps) m_proxy_settings = ps; - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } if (ps.type == settings_pack::socks5 || ps.type == settings_pack::socks5_pw) @@ -880,6 +892,19 @@ void udp_socket::set_proxy_settings(aux::proxy_settings const& ps) } } +void udp_socket::close_impl() +{ + if (m_outstanding_ops == 0) + { + error_code ec; + m_ipv4_sock.close(ec); +#if TORRENT_USE_IPV6 + m_ipv6_sock.close(ec); +#endif + m_socks5_sock.close(ec); + } +} + void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) { #if defined TORRENT_ASIO_DEBUGGING @@ -897,7 +922,12 @@ void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } + CHECK_MAGIC; if (e == boost::asio::error::operation_aborted) return; @@ -976,7 +1006,11 @@ void udp_socket::on_connect_timeout(error_code const& ec) m_queue_packets = false; - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; TORRENT_ASSERT(is_single_thread()); @@ -1009,7 +1043,11 @@ void udp_socket::on_connected(error_code const& e) if (e == boost::asio::error::operation_aborted) return; - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } if (e) { @@ -1068,7 +1106,11 @@ void udp_socket::handshake1(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; if (e) { @@ -1104,7 +1146,11 @@ void udp_socket::handshake2(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; if (e) @@ -1185,7 +1231,11 @@ void udp_socket::handshake3(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; if (e) { @@ -1221,7 +1271,11 @@ void udp_socket::handshake4(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; if (e) { @@ -1287,7 +1341,11 @@ void udp_socket::connect1(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; if (e) { @@ -1394,7 +1452,11 @@ void udp_socket::hung_up(error_code const& e) + m_outstanding_timeout + m_outstanding_resolve + m_outstanding_socks); - if (m_abort) return; + if (m_abort) + { + close_impl(); + return; + } CHECK_MAGIC; TORRENT_ASSERT(is_single_thread()); diff --git a/src/upnp.cpp b/src/upnp.cpp index c769476f6..c2a80e759 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -1044,9 +1044,10 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l) , end(m_mappings.end()); i != end; ++i) { if (i->protocol == none) continue; + int const proto = i->protocol; i->protocol = none; l.unlock(); - m_callback(i - m_mappings.begin(), address(), 0, ec); + m_callback(i - m_mappings.begin(), address(), 0, proto, ec); l.lock(); } @@ -1375,7 +1376,7 @@ void upnp::on_upnp_map_response(error_code const& e if (s.error_code == -1) { l.unlock(); - m_callback(mapping, d.external_ip, m.external_port, error_code()); + m_callback(mapping, d.external_ip, m.external_port, m.protocol, error_code()); l.lock(); if (d.lease_duration > 0) { @@ -1417,8 +1418,9 @@ void upnp::return_error(int mapping, int code, mutex::scoped_lock& l) error_string += ": "; error_string += e->msg; } + const int proto = m_mappings[mapping].protocol; l.unlock(); - m_callback(mapping, address(), 0, error_code(code, get_upnp_category())); + m_callback(mapping, address(), 0, proto, error_code(code, get_upnp_category())); l.lock(); } @@ -1471,8 +1473,10 @@ void upnp::on_upnp_unmap_response(error_code const& e , boost::bind(&find_error_code, _1, _2, boost::ref(s))); } + int const proto = m_mappings[mapping].protocol; + l.unlock(); - m_callback(mapping, address(), 0, p.status_code() != 200 + m_callback(mapping, address(), 0, proto, p.status_code() != 200 ? error_code(p.status_code(), get_http_category()) : error_code(s.error_code, get_upnp_category())); l.lock();