diff --git a/include/libtorrent/aux_/portmap.hpp b/include/libtorrent/aux_/portmap.hpp index 57483e01f..42e64a1ca 100644 --- a/include/libtorrent/aux_/portmap.hpp +++ b/include/libtorrent/aux_/portmap.hpp @@ -48,6 +48,11 @@ namespace libtorrent { namespace aux { none, tcp, udp }; + enum class portmap_action : std::uint8_t + { + none, add, del + }; + struct TORRENT_EXTRA_EXPORT portmap_callback { // int: port-mapping index @@ -66,6 +71,30 @@ namespace libtorrent { namespace aux { protected: ~portmap_callback() {} }; + + struct base_mapping + { + // the time the port mapping will expire + time_point expires; + + portmap_action act = portmap_action::none; + + // the external (on the NAT router) port + // for the mapping. This is the port we + // should announce to others + int external_port = 0; + + portmap_protocol protocol = portmap_protocol::none; + }; + + inline char const* to_string(portmap_protocol const p) + { + return p == portmap_protocol::udp ? "UDP" : "TCP"; + } + inline char const* to_string(portmap_action const act) + { + return act == portmap_action::none ? "none" : act == portmap_action::add ? "add" : "delete"; + } }} #endif // LIBTORRENT_PORTMAP_HPP diff --git a/include/libtorrent/natpmp.hpp b/include/libtorrent/natpmp.hpp index 57345fc01..2b6241c41 100644 --- a/include/libtorrent/natpmp.hpp +++ b/include/libtorrent/natpmp.hpp @@ -77,35 +77,14 @@ private: void mapping_expired(error_code const& e, int i); void close_impl(); -#ifndef TORRENT_DISABLE_LOGGING - bool should_log() const; - void log(char const* fmt, ...) const TORRENT_FORMAT(2, 3); -#endif - void disable(error_code const& ec); - struct mapping_t + struct mapping_t : public aux::base_mapping { - enum class action : std::uint8_t { none, add, del }; - - // indicates that the mapping has changed - // and needs an update - action act = action::none; - - // the time the port mapping will expire - time_point expires; - // the local port for this mapping. If this is set // to 0, the mapping is not in use int local_port = 0; - // the external (on the NAT router) port - // for the mapping. This is the port we - // should announce to others - int external_port = 0; - - aux::portmap_protocol protocol = aux::portmap_protocol::none; - // set to true when the first map request is sent bool map_sent = false; @@ -113,6 +92,12 @@ private: bool outstanding_request = false; }; +#ifndef TORRENT_DISABLE_LOGGING + bool should_log() const; + void log(char const* fmt, ...) const TORRENT_FORMAT(2, 3); + void mapping_log(char const* op, mapping_t const& m) const; +#endif + aux::portmap_callback& m_callback; aux::vector m_mappings; diff --git a/include/libtorrent/upnp.hpp b/include/libtorrent/upnp.hpp index 9d053a39c..497ecb65c 100644 --- a/include/libtorrent/upnp.hpp +++ b/include/libtorrent/upnp.hpp @@ -252,15 +252,8 @@ private: tcp::endpoint local_ep; }; - struct mapping_t + struct mapping_t : public aux::base_mapping { - enum class action : std::uint8_t { none, add, del }; - - // the time the port mapping will expire - time_point expires; - - action act = action::none; - // the local port for this mapping. If this is set // to 0, the mapping is not in use tcp::endpoint local_ep; @@ -270,9 +263,6 @@ private: // should announce to others int external_port = 0; - // 2 = udp, 1 = tcp - aux::portmap_protocol protocol = aux::portmap_protocol::none; - // the number of times this mapping has failed int failcount = 0; }; diff --git a/src/natpmp.cpp b/src/natpmp.cpp index ed788ff24..43a0343c6 100644 --- a/src/natpmp.cpp +++ b/src/natpmp.cpp @@ -131,9 +131,9 @@ void natpmp::start() , end(m_mappings.end()); i != end; ++i) { if (i->protocol == portmap_protocol::none - || i->act != mapping_t::action::none) + || i->act != portmap_action::none) continue; - i->act = mapping_t::action::add; + i->act = portmap_action::add; update_mapping(int(i - m_mappings.begin())); } } @@ -176,6 +176,21 @@ bool natpmp::should_log() const return m_callback.should_log_portmap(aux::portmap_transport::natpmp); } +void natpmp::mapping_log(char const* op, mapping_t const& m) const +{ + if (should_log()) + { + log("%s-mapping: proto: %s port: %d local-port: %d action: %s ttl: %" PRId64 + , op + , m.protocol == portmap_protocol::none + ? "none" : to_string(m.protocol) + , m.external_port + , m.local_port + , to_string(m.act) + , total_seconds(m.expires - aux::time_now())); + } +} + TORRENT_FORMAT(2, 3) void natpmp::log(char const* fmt, ...) const { @@ -219,12 +234,12 @@ void natpmp::delete_mapping(int const index) if (m.protocol == portmap_protocol::none) return; if (!m.map_sent) { - m.act = mapping_t::action::none; + m.act = portmap_action::none; m.protocol = portmap_protocol::none; return; } - m.act = mapping_t::action::del; + m.act = portmap_action::del; update_mapping(index); } @@ -245,22 +260,11 @@ int natpmp::add_mapping(portmap_protocol const p, int const external_port i->protocol = p; i->external_port = external_port; i->local_port = local_ep.port(); - i->act = mapping_t::action::add; + i->act = portmap_action::add; int const mapping_index = int(i - m_mappings.begin()); #ifndef TORRENT_DISABLE_LOGGING - if (should_log()) - { - natpmp::mapping_t const& m = *i; - log("add-mapping: proto: %s port: %d local-port: %d action: %s ttl: %" PRId64 - , (m.protocol == portmap_protocol::none - ? "none" : m.protocol == portmap_protocol::tcp ? "tcp" : "udp") - , m.external_port - , m.local_port - , (m.act == mapping_t::action::none - ? "none" : m.act == mapping_t::action::add ? "add" : "delete") - , total_seconds(m.expires - aux::time_now())); - } + mapping_log("add",*i); #endif update_mapping(mapping_index); @@ -278,7 +282,7 @@ void natpmp::try_next_mapping(int const i) auto const m = std::find_if( m_mappings.begin(), m_mappings.end() - , [] (mapping_t const& ma) { return ma.act != mapping_t::action::none + , [] (mapping_t const& ma) { return ma.act != portmap_action::none && ma.protocol != portmap_protocol::none; }); if (m == m_mappings.end()) @@ -312,20 +316,10 @@ void natpmp::update_mapping(int const i) natpmp::mapping_t const& m = m_mappings[i]; #ifndef TORRENT_DISABLE_LOGGING - if (should_log()) - { - log("update-mapping: proto: %s port: %d local-port: %d action: %s ttl: %" PRId64 - , (m.protocol == portmap_protocol::none - ? "none" : m.protocol == portmap_protocol::tcp ? "tcp" : "udp") - , m.external_port - , m.local_port - , (m.act == mapping_t::action::none - ? "none" : m.act == mapping_t::action::add ? "add" : "delete") - , total_seconds(m.expires - aux::time_now())); - } + mapping_log("update", m); #endif - if (m.act == mapping_t::action::none + if (m.act == portmap_action::none || m.protocol == portmap_protocol::none) { try_next_mapping(i); @@ -350,7 +344,7 @@ void natpmp::send_map_request(int const i) || m_currently_mapping == i); m_currently_mapping = i; mapping_t& m = m_mappings[i]; - TORRENT_ASSERT(m.act != mapping_t::action::none); + TORRENT_ASSERT(m.act != portmap_action::none); char buf[12]; char* out = buf; write_uint8(0, out); // NAT-PMP version @@ -358,7 +352,7 @@ void natpmp::send_map_request(int const i) write_uint16(0, out); // reserved write_uint16(m.local_port, out); // private port write_uint16(m.external_port, out); // requested public port - int ttl = m.act == mapping_t::action::add ? 3600 : 0; + int ttl = m.act == portmap_action::add ? 3600 : 0; write_uint32(ttl, out); // port mapping lifetime #ifndef TORRENT_DISABLE_LOGGING @@ -366,8 +360,8 @@ void natpmp::send_map_request(int const i) { log("==> port map [ mapping: %d action: %s" " proto: %s local: %u external: %u ttl: %u ]" - , i, m.act == mapping_t::action::add ? "add" : "delete" - , m.protocol == portmap_protocol::udp ? "udp" : "tcp" + , i, to_string(m.act) + , to_string(m.protocol) , m.local_port, m.external_port, ttl); } #endif @@ -382,7 +376,7 @@ void natpmp::send_map_request(int const i) // responses and just remove all mappings // immediately m_currently_mapping = -1; - m.act = mapping_t::action::none; + m.act = portmap_action::none; try_next_mapping(i); } else @@ -407,7 +401,7 @@ void natpmp::resend_request(int const i, error_code const& e) if (m_retry_count >= 9 || m_abort) { m_currently_mapping = -1; - m_mappings[i].act = mapping_t::action::none; + m_mappings[i].act = portmap_action::none; // try again in two hours m_mappings[i].expires = aux::time_now() + hours(2); try_next_mapping(i); @@ -565,13 +559,13 @@ void natpmp::on_reply(error_code const& e if (result != 0) { // TODO: 3 it would be nice to have a separate NAT-PMP error category - errors::error_code_enum errors[] = + static errors::error_code_enum const errors[] = { errors::unsupported_protocol_version, errors::natpmp_not_authorized, errors::network_failure, errors::no_resources, - errors::unsupported_opcode, + errors::unsupported_opcode }; errors::error_code_enum ev = errors::no_error; if (result >= 1 && result <= 5) ev = errors[result - 1]; @@ -581,7 +575,7 @@ void natpmp::on_reply(error_code const& e m_callback.on_port_mapping(index, address(), 0, proto , ev, aux::portmap_transport::natpmp); } - else if (m->act == mapping_t::action::add) + else if (m->act == portmap_action::add) { portmap_protocol const proto = m->protocol; m_callback.on_port_mapping(index, m_external_ip, m->external_port, proto @@ -591,7 +585,7 @@ void natpmp::on_reply(error_code const& e if (m_abort) return; m_currently_mapping = -1; - m->act = mapping_t::action::none; + m->act = portmap_action::none; m_send_timer.cancel(ec); update_expiration_timer(); try_next_mapping(index); @@ -609,14 +603,14 @@ void natpmp::update_expiration_timer() , end(m_mappings.end()); i != end; ++i) { if (i->protocol == portmap_protocol::none - || i->act != mapping_t::action::none) continue; + || i->act != portmap_action::none) continue; int const index = int(i - m_mappings.begin()); if (i->expires < now) { #ifndef TORRENT_DISABLE_LOGGING log("mapping %u expired", index); #endif - i->act = mapping_t::action::add; + i->act = portmap_action::add; if (m_next_refresh == index) m_next_refresh = -1; update_mapping(index); } @@ -654,7 +648,7 @@ void natpmp::mapping_expired(error_code const& e, int const i) #ifndef TORRENT_DISABLE_LOGGING log("mapping %u expired", i); #endif - m_mappings[i].act = mapping_t::action::add; + m_mappings[i].act = portmap_action::add; if (m_next_refresh == i) m_next_refresh = -1; update_mapping(i); } @@ -676,7 +670,7 @@ void natpmp::close_impl() for (auto& m : m_mappings) { if (m.protocol == portmap_protocol::none) continue; - m.act = mapping_t::action::del; + m.act = portmap_action::del; } error_code ec; m_refresh_timer.cancel(ec); diff --git a/src/upnp.cpp b/src/upnp.cpp index 54f02e257..002717672 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -221,7 +221,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port d.mapping.resize(mapping_index + 1); mapping_t& m = d.mapping[mapping_index]; - m.act = mapping_t::action::add; + m.act = portmap_action::add; m.protocol = p; m.external_port = external_port; m.local_ep = local_ep; @@ -238,7 +238,7 @@ void upnp::delete_mapping(int const mapping) if (mapping >= int(m_mappings.size())) return; - global_mapping_t& m = m_mappings[mapping]; + global_mapping_t const& m = m_mappings[mapping]; #ifndef TORRENT_DISABLE_LOGGING log("deleting port map: [ protocol: %s ext_port: %u " @@ -254,7 +254,7 @@ void upnp::delete_mapping(int const mapping) TORRENT_ASSERT(d.magic == 1337); TORRENT_ASSERT(mapping < d.mapping.end_index()); - d.mapping[mapping].act = mapping_t::action::del; + d.mapping[mapping].act = portmap_action::del; if (!d.service_namespace.empty()) update_map(d, mapping); } @@ -585,7 +585,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer for (auto const& j : m_mappings) { mapping_t m; - m.act = mapping_t::action::add; + m.act = portmap_action::add; m.local_ep = j.local_ep; m.external_port = j.external_port; m.protocol = j.protocol; @@ -743,7 +743,7 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int const i) "%u" "" , soap_action, d.service_namespace.c_str(), d.mapping[i].external_port - , (d.mapping[i].protocol == portmap_protocol::udp ? "UDP" : "TCP") + , to_string(d.mapping[i].protocol) , d.mapping[i].local_ep.port() , local_endpoint.c_str() , m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_ep.port() @@ -762,7 +762,7 @@ void upnp::next(rootdevice& d, int const i) else { auto const j = std::find_if(d.mapping.begin(), d.mapping.end() - , [] (mapping_t const& m) { return m.act != mapping_t::action::none; }); + , [] (mapping_t const& m) { return m.act != portmap_action::none; }); if (j == d.mapping.end()) return; update_map(d, int(j - d.mapping.begin())); @@ -782,13 +782,13 @@ void upnp::update_map(rootdevice& d, int const i) mapping_t& m = d.mapping[i]; - if (m.act == mapping_t::action::none + if (m.act == portmap_action::none || m.protocol == portmap_protocol::none) { #ifndef TORRENT_DISABLE_LOGGING log("mapping %u does not need updating, skipping", i); #endif - m.act = mapping_t::action::none; + m.act = portmap_action::none; next(d, i); return; } @@ -799,11 +799,11 @@ void upnp::update_map(rootdevice& d, int const i) #ifndef TORRENT_DISABLE_LOGGING log("connecting to %s", d.hostname.c_str()); #endif - if (m.act == mapping_t::action::add) + if (m.act == portmap_action::add) { if (m.failcount > 5) { - m.act = mapping_t::action::none; + m.act = portmap_action::none; // giving up next(d, i); return; @@ -819,7 +819,7 @@ void upnp::update_map(rootdevice& d, int const i) d.upnp_connection->start(d.hostname, d.port , seconds(10), 1, NULL, false, 5, m.local_ep.address()); } - else if (m.act == mapping_t::action::del) + else if (m.act == portmap_action::del) { if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection = std::make_shared(m_io_service @@ -831,7 +831,7 @@ void upnp::update_map(rootdevice& d, int const i) , seconds(10), 1, NULL, false, 5, m.local_ep.address()); } - m.act = mapping_t::action::none; + m.act = portmap_action::none; } void upnp::delete_port_mapping(rootdevice& d, int const i) @@ -863,7 +863,7 @@ void upnp::delete_port_mapping(rootdevice& d, int const i) "" , soap_action, d.service_namespace.c_str() , d.mapping[i].external_port - , (d.mapping[i].protocol == portmap_protocol::udp ? "UDP" : "TCP") + , to_string(d.mapping[i].protocol) , soap_action); post(d, soap, soap_action); @@ -1106,8 +1106,7 @@ void find_error_code(int const type, string_view string, error_code_parse_state& } else if (type == xml_string && state.in_error_code) { - std::string error_code_str(string.begin(), string.end()); - state.error_code = std::atoi(error_code_str.c_str()); + state.error_code = std::atoi(string.to_string().c_str()); state.exit = true; } } @@ -1380,7 +1379,7 @@ void upnp::on_upnp_map_response(error_code const& e { // only permanent leases supported d.lease_duration = 0; - m.act = mapping_t::action::add; + m.act = portmap_action::add; ++m.failcount; update_map(d, mapping); return; @@ -1395,7 +1394,7 @@ void upnp::on_upnp_map_response(error_code const& e // The external port conflicts with another mapping // pick a random port m.external_port = 40000 + int(random(10000)); - m.act = mapping_t::action::add; + m.act = portmap_action::add; ++m.failcount; update_map(d, mapping); return; @@ -1594,12 +1593,12 @@ void upnp::close() , end2(d.mapping.end()); j != end2; ++j) { if (j->protocol == portmap_protocol::none) continue; - if (j->act == mapping_t::action::add) + if (j->act == portmap_action::add) { - j->act = mapping_t::action::none; + j->act = portmap_action::none; continue; } - j->act = mapping_t::action::del; + j->act = portmap_action::del; m_mappings[int(j - d.mapping.begin())].protocol = portmap_protocol::none; } if (num_mappings() > 0) update_map(d, 0);