diff --git a/examples/client_test.cpp b/examples/client_test.cpp index bae590478..c6fa11bb3 100755 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -780,6 +780,13 @@ int main(int ac, char* av[]) std::string now = to_simple_string(second_clock::universal_time()); while (a.get()) { + std::stringstream event_string; + if (a->severity() == alert::fatal) + event_string << esc("31"); // red + else if (a->severity() == alert::warning) + event_string << esc("33"); // yellow + + event_string << now << ": "; if (torrent_finished_alert* p = dynamic_cast(a.get())) { p->handle.set_max_connections(60); @@ -793,38 +800,37 @@ int main(int ac, char* av[]) out.unsetf(std::ios_base::skipws); bencode(std::ostream_iterator(out), data); - events.push_back(now + ": " - + p->handle.get_torrent_info().name() + ": " + a->msg()); + event_string << p->handle.get_torrent_info().name() << ": " + << a->msg(); } else if (peer_error_alert* p = dynamic_cast(a.get())) { - events.push_back(now + ": " + identify_client(p->pid) - + ": " + a->msg()); + event_string << identify_client(p->pid) << ": " << a->msg(); } else if (invalid_request_alert* p = dynamic_cast(a.get())) { - events.push_back(now + ": " + identify_client(p->pid) - + ": " + a->msg()); + event_string << identify_client(p->pid) << ": " << a->msg(); } else if (tracker_warning_alert* p = dynamic_cast(a.get())) { - events.push_back(now + ": tracker message: " + p->msg()); + event_string << "tracker message: " << p->msg(); } else if (tracker_reply_alert* p = dynamic_cast(a.get())) { - events.push_back(now + ": " + p->msg() + " (" - + boost::lexical_cast(p->num_peers) + ")"); + event_string << p->msg() << " (" << p->num_peers << ")"; } else if (url_seed_alert* p = dynamic_cast(a.get())) { - events.push_back(now + ": web seed '" + p->url + "': "+ p->msg()); + event_string << "web seed '" << p->url << "': " << p->msg(); } else { - events.push_back(now + ": " + a->msg()); + event_string << a->msg(); } + event_string << esc("0"); + events.push_back(event_string.str()); - if (events.size() >= 10) events.pop_front(); + if (events.size() >= 20) events.pop_front(); a = ses.pop_alert(); } diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp index 3d1a03ab2..6347ec1e8 100644 --- a/include/libtorrent/natpmp.hpp +++ b/include/libtorrent/natpmp.hpp @@ -52,7 +52,9 @@ typedef boost::function portmap_callback_t; class natpmp { public: - natpmp(io_service& ios, portmap_callback_t const& cb); + natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb); + + void rebind(address const& listen_interface); // maps the ports, if a port is set to 0 // it will not be mapped diff --git a/src/natpmp.cpp b/src/natpmp.cpp index 07191d188..4feaf097f 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -40,7 +40,9 @@ using boost::bind; using namespace libtorrent; using boost::posix_time::microsec_clock; -natpmp::natpmp(io_service& ios, portmap_callback_t const& cb) +enum { num_mappings = 2 }; + +natpmp::natpmp(io_service& ios, address const& listen_interface, portmap_callback_t const& cb) : m_callback(cb) , m_currently_mapping(-1) , m_retry_count(0) @@ -55,25 +57,42 @@ natpmp::natpmp(io_service& ios, portmap_callback_t const& cb) #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log.open("natpmp.log", std::ios::in | std::ios::out | std::ios::trunc); #endif - - udp::resolver r(ios); - udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); - for (;i != udp::resolver_iterator(); ++i) + rebind(listen_interface); +} + +void natpmp::rebind(address const& listen_interface) +{ + address_v4 local; + if (listen_interface.is_v4() && listen_interface != address_v4::from_string("0.0.0.0")) { - if (i->endpoint().address().is_v4()) break; + local = listen_interface.to_v4(); + } + else + { + // make a best guess of the interface we're using and its IP + udp::resolver r(m_socket.io_service()); + udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); + for (;i != udp::resolver_iterator(); ++i) + { + if (i->endpoint().address().is_v4()) break; + } + + if (i == udp::resolver_iterator()) + { + #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << "local host name did not resolve to an IPv4 address. " + "disabling NAT-PMP" << std::endl; + #endif + m_disabled = true; + return; + } + + local = i->endpoint().address().to_v4(); } - if (i == udp::resolver_iterator()) - { -#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - m_log << "local host name did not resolve to an IPv4 address. " - "disabling NAT-PMP" << std::endl; -#endif - m_disabled = true; - return; - } + m_socket.open(udp::v4()); + m_socket.bind(udp::endpoint(local, 0)); - address_v4 local = i->endpoint().address().to_v4(); #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << to_simple_string(microsec_clock::universal_time()) << " local ip: " << local.to_string() << std::endl; @@ -92,18 +111,28 @@ natpmp::natpmp(io_service& ios, portmap_callback_t const& cb) return; } + m_disabled = false; + + udp::endpoint nat_endpoint( + address_v4((local.to_ulong() & 0xffffff00) | 1), 5351); + + if (nat_endpoint == m_nat_endpoint) return; + // assume the router is located on the local // network as x.x.x.1 // TODO: find a better way to figure out the router IP - m_nat_endpoint = udp::endpoint( - address_v4((local.to_ulong() & 0xffffff00) | 1), 5351); + m_nat_endpoint = nat_endpoint; #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << "assuming router is at: " << m_nat_endpoint.address().to_string() << std::endl; #endif - m_socket.open(udp::v4()); - m_socket.bind(udp::endpoint()); + for (int i = 0; i < num_mappings; ++i) + { + if (m_mappings[i].local_port == 0) + continue; + refresh_mapping(i); + } } void natpmp::set_mappings(int tcp, int udp) @@ -305,7 +334,7 @@ void natpmp::update_expiration_timer() boost::posix_time::ptime now = boost::posix_time::second_clock::universal_time(); boost::posix_time::ptime min_expire = now + seconds(3600); int min_index = -1; - for (int i = 0; i < 2; ++i) + for (int i = 0; i < num_mappings; ++i) if (m_mappings[i].expires < min_expire && m_mappings[i].local_port != 0) { @@ -346,7 +375,7 @@ void natpmp::refresh_mapping(int i) void natpmp::try_next_mapping(int i) { ++i; - if (i >= 2) i = 0; + if (i >= num_mappings) i = 0; if (m_mappings[i].need_update) refresh_mapping(i); } @@ -354,7 +383,7 @@ void natpmp::try_next_mapping(int i) void natpmp::close() { if (m_disabled) return; - for (int i = 0; i < 2; ++i) + for (int i = 0; i < num_mappings; ++i) { if (m_mappings[i].local_port == 0) continue; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 330ac7ccc..984862b07 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -492,7 +492,8 @@ namespace libtorrent { namespace detail , m_dht_same_port(true) , m_external_udp_port(0) #endif - , m_natpmp(m_io_service, bind(&session_impl::on_port_mapping, this, _1, _2, _3)) + , m_natpmp(m_io_service, m_listen_interface.address() + , bind(&session_impl::on_port_mapping, this, _1, _2, _3)) , m_timer(m_io_service) , m_checker_impl(*this) { @@ -1459,6 +1460,8 @@ namespace libtorrent { namespace detail // the listen interface changed, rebind the dht listen socket as well m_dht->rebind(new_interface.address() , m_dht_settings.service_port); + if (m_listen_interface.address() != new_interface.address()) + m_natpmp.rebind(new_interface.address()); m_natpmp.set_mappings(0, m_dht_settings.service_port); } #endif @@ -1571,9 +1574,12 @@ namespace libtorrent { namespace detail m_dht->stop(); m_dht = 0; } - if (m_dht_settings.service_port == 0) + if (m_dht_settings.service_port == 0 + || m_dht_same_port) + { m_dht_same_port = true; - m_dht_settings.service_port = m_listen_interface.port(); + m_dht_settings.service_port = m_listen_interface.port(); + } m_external_udp_port = m_dht_settings.service_port; m_natpmp.set_mappings(0, m_dht_settings.service_port); m_dht = new dht::dht_tracker(m_io_service @@ -1597,6 +1603,8 @@ namespace libtorrent { namespace detail // the current setting if (settings.service_port != 0) m_dht_same_port = false; + else + m_dht_same_port = true; if (!m_dht_same_port && settings.service_port != m_dht_settings.service_port && m_dht)