add base_mapping_t (#2025)

factor out parts of mapping struct from NATPMP and UPnP
This commit is contained in:
Pavel Pimenov 2017-05-28 03:26:47 +03:00 committed by Arvid Norberg
parent 4709c03ab1
commit 4cee8104d7
5 changed files with 94 additions and 97 deletions

View File

@ -48,6 +48,11 @@ namespace libtorrent { namespace aux {
none, tcp, udp none, tcp, udp
}; };
enum class portmap_action : std::uint8_t
{
none, add, del
};
struct TORRENT_EXTRA_EXPORT portmap_callback struct TORRENT_EXTRA_EXPORT portmap_callback
{ {
// int: port-mapping index // int: port-mapping index
@ -66,6 +71,30 @@ namespace libtorrent { namespace aux {
protected: protected:
~portmap_callback() {} ~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 #endif // LIBTORRENT_PORTMAP_HPP

View File

@ -77,35 +77,14 @@ private:
void mapping_expired(error_code const& e, int i); void mapping_expired(error_code const& e, int i);
void close_impl(); 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); 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 // the local port for this mapping. If this is set
// to 0, the mapping is not in use // to 0, the mapping is not in use
int local_port = 0; 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 // set to true when the first map request is sent
bool map_sent = false; bool map_sent = false;
@ -113,6 +92,12 @@ private:
bool outstanding_request = false; 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::portmap_callback& m_callback;
aux::vector<mapping_t> m_mappings; aux::vector<mapping_t> m_mappings;

View File

@ -252,15 +252,8 @@ private:
tcp::endpoint local_ep; 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 // the local port for this mapping. If this is set
// to 0, the mapping is not in use // to 0, the mapping is not in use
tcp::endpoint local_ep; tcp::endpoint local_ep;
@ -270,9 +263,6 @@ private:
// should announce to others // should announce to others
int external_port = 0; int external_port = 0;
// 2 = udp, 1 = tcp
aux::portmap_protocol protocol = aux::portmap_protocol::none;
// the number of times this mapping has failed // the number of times this mapping has failed
int failcount = 0; int failcount = 0;
}; };

View File

@ -131,9 +131,9 @@ void natpmp::start()
, end(m_mappings.end()); i != end; ++i) , end(m_mappings.end()); i != end; ++i)
{ {
if (i->protocol == portmap_protocol::none if (i->protocol == portmap_protocol::none
|| i->act != mapping_t::action::none) || i->act != portmap_action::none)
continue; continue;
i->act = mapping_t::action::add; i->act = portmap_action::add;
update_mapping(int(i - m_mappings.begin())); 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); 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) TORRENT_FORMAT(2, 3)
void natpmp::log(char const* fmt, ...) const 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.protocol == portmap_protocol::none) return;
if (!m.map_sent) if (!m.map_sent)
{ {
m.act = mapping_t::action::none; m.act = portmap_action::none;
m.protocol = portmap_protocol::none; m.protocol = portmap_protocol::none;
return; return;
} }
m.act = mapping_t::action::del; m.act = portmap_action::del;
update_mapping(index); update_mapping(index);
} }
@ -245,22 +260,11 @@ int natpmp::add_mapping(portmap_protocol const p, int const external_port
i->protocol = p; i->protocol = p;
i->external_port = external_port; i->external_port = external_port;
i->local_port = local_ep.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()); int const mapping_index = int(i - m_mappings.begin());
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) mapping_log("add",*i);
{
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()));
}
#endif #endif
update_mapping(mapping_index); update_mapping(mapping_index);
@ -278,7 +282,7 @@ void natpmp::try_next_mapping(int const i)
auto const m = std::find_if( auto const m = std::find_if(
m_mappings.begin(), m_mappings.end() 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; }); && ma.protocol != portmap_protocol::none; });
if (m == m_mappings.end()) if (m == m_mappings.end())
@ -312,20 +316,10 @@ void natpmp::update_mapping(int const i)
natpmp::mapping_t const& m = m_mappings[i]; natpmp::mapping_t const& m = m_mappings[i];
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
if (should_log()) mapping_log("update", m);
{
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()));
}
#endif #endif
if (m.act == mapping_t::action::none if (m.act == portmap_action::none
|| m.protocol == portmap_protocol::none) || m.protocol == portmap_protocol::none)
{ {
try_next_mapping(i); try_next_mapping(i);
@ -350,7 +344,7 @@ void natpmp::send_map_request(int const i)
|| m_currently_mapping == i); || m_currently_mapping == i);
m_currently_mapping = i; m_currently_mapping = i;
mapping_t& m = m_mappings[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 buf[12];
char* out = buf; char* out = buf;
write_uint8(0, out); // NAT-PMP version 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(0, out); // reserved
write_uint16(m.local_port, out); // private port write_uint16(m.local_port, out); // private port
write_uint16(m.external_port, out); // requested public 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 write_uint32(ttl, out); // port mapping lifetime
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
@ -366,8 +360,8 @@ void natpmp::send_map_request(int const i)
{ {
log("==> port map [ mapping: %d action: %s" log("==> port map [ mapping: %d action: %s"
" proto: %s local: %u external: %u ttl: %u ]" " proto: %s local: %u external: %u ttl: %u ]"
, i, m.act == mapping_t::action::add ? "add" : "delete" , i, to_string(m.act)
, m.protocol == portmap_protocol::udp ? "udp" : "tcp" , to_string(m.protocol)
, m.local_port, m.external_port, ttl); , m.local_port, m.external_port, ttl);
} }
#endif #endif
@ -382,7 +376,7 @@ void natpmp::send_map_request(int const i)
// responses and just remove all mappings // responses and just remove all mappings
// immediately // immediately
m_currently_mapping = -1; m_currently_mapping = -1;
m.act = mapping_t::action::none; m.act = portmap_action::none;
try_next_mapping(i); try_next_mapping(i);
} }
else else
@ -407,7 +401,7 @@ void natpmp::resend_request(int const i, error_code const& e)
if (m_retry_count >= 9 || m_abort) if (m_retry_count >= 9 || m_abort)
{ {
m_currently_mapping = -1; m_currently_mapping = -1;
m_mappings[i].act = mapping_t::action::none; m_mappings[i].act = portmap_action::none;
// try again in two hours // try again in two hours
m_mappings[i].expires = aux::time_now() + hours(2); m_mappings[i].expires = aux::time_now() + hours(2);
try_next_mapping(i); try_next_mapping(i);
@ -565,13 +559,13 @@ void natpmp::on_reply(error_code const& e
if (result != 0) if (result != 0)
{ {
// TODO: 3 it would be nice to have a separate NAT-PMP error category // 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::unsupported_protocol_version,
errors::natpmp_not_authorized, errors::natpmp_not_authorized,
errors::network_failure, errors::network_failure,
errors::no_resources, errors::no_resources,
errors::unsupported_opcode, errors::unsupported_opcode
}; };
errors::error_code_enum ev = errors::no_error; errors::error_code_enum ev = errors::no_error;
if (result >= 1 && result <= 5) ev = errors[result - 1]; 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 m_callback.on_port_mapping(index, address(), 0, proto
, ev, aux::portmap_transport::natpmp); , 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; portmap_protocol const proto = m->protocol;
m_callback.on_port_mapping(index, m_external_ip, m->external_port, proto 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; if (m_abort) return;
m_currently_mapping = -1; m_currently_mapping = -1;
m->act = mapping_t::action::none; m->act = portmap_action::none;
m_send_timer.cancel(ec); m_send_timer.cancel(ec);
update_expiration_timer(); update_expiration_timer();
try_next_mapping(index); try_next_mapping(index);
@ -609,14 +603,14 @@ void natpmp::update_expiration_timer()
, end(m_mappings.end()); i != end; ++i) , end(m_mappings.end()); i != end; ++i)
{ {
if (i->protocol == portmap_protocol::none 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()); int const index = int(i - m_mappings.begin());
if (i->expires < now) if (i->expires < now)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("mapping %u expired", index); log("mapping %u expired", index);
#endif #endif
i->act = mapping_t::action::add; i->act = portmap_action::add;
if (m_next_refresh == index) m_next_refresh = -1; if (m_next_refresh == index) m_next_refresh = -1;
update_mapping(index); update_mapping(index);
} }
@ -654,7 +648,7 @@ void natpmp::mapping_expired(error_code const& e, int const i)
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("mapping %u expired", i); log("mapping %u expired", i);
#endif #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; if (m_next_refresh == i) m_next_refresh = -1;
update_mapping(i); update_mapping(i);
} }
@ -676,7 +670,7 @@ void natpmp::close_impl()
for (auto& m : m_mappings) for (auto& m : m_mappings)
{ {
if (m.protocol == portmap_protocol::none) continue; if (m.protocol == portmap_protocol::none) continue;
m.act = mapping_t::action::del; m.act = portmap_action::del;
} }
error_code ec; error_code ec;
m_refresh_timer.cancel(ec); m_refresh_timer.cancel(ec);

View File

@ -221,7 +221,7 @@ int upnp::add_mapping(portmap_protocol const p, int const external_port
d.mapping.resize(mapping_index + 1); d.mapping.resize(mapping_index + 1);
mapping_t& m = d.mapping[mapping_index]; mapping_t& m = d.mapping[mapping_index];
m.act = mapping_t::action::add; m.act = portmap_action::add;
m.protocol = p; m.protocol = p;
m.external_port = external_port; m.external_port = external_port;
m.local_ep = local_ep; m.local_ep = local_ep;
@ -238,7 +238,7 @@ void upnp::delete_mapping(int const mapping)
if (mapping >= int(m_mappings.size())) return; 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 #ifndef TORRENT_DISABLE_LOGGING
log("deleting port map: [ protocol: %s ext_port: %u " 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(d.magic == 1337);
TORRENT_ASSERT(mapping < d.mapping.end_index()); 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); 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) for (auto const& j : m_mappings)
{ {
mapping_t m; mapping_t m;
m.act = mapping_t::action::add; m.act = portmap_action::add;
m.local_ep = j.local_ep; m.local_ep = j.local_ep;
m.external_port = j.external_port; m.external_port = j.external_port;
m.protocol = j.protocol; m.protocol = j.protocol;
@ -743,7 +743,7 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int const i)
"<NewLeaseDuration>%u</NewLeaseDuration>" "<NewLeaseDuration>%u</NewLeaseDuration>"
"</u:%s></s:Body></s:Envelope>" "</u:%s></s:Body></s:Envelope>"
, soap_action, d.service_namespace.c_str(), d.mapping[i].external_port , 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() , d.mapping[i].local_ep.port()
, local_endpoint.c_str() , local_endpoint.c_str()
, m_user_agent.c_str(), local_endpoint.c_str(), d.mapping[i].local_ep.port() , 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 else
{ {
auto const j = std::find_if(d.mapping.begin(), d.mapping.end() 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; if (j == d.mapping.end()) return;
update_map(d, int(j - d.mapping.begin())); 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]; mapping_t& m = d.mapping[i];
if (m.act == mapping_t::action::none if (m.act == portmap_action::none
|| m.protocol == portmap_protocol::none) || m.protocol == portmap_protocol::none)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("mapping %u does not need updating, skipping", i); log("mapping %u does not need updating, skipping", i);
#endif #endif
m.act = mapping_t::action::none; m.act = portmap_action::none;
next(d, i); next(d, i);
return; return;
} }
@ -799,11 +799,11 @@ void upnp::update_map(rootdevice& d, int const i)
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
log("connecting to %s", d.hostname.c_str()); log("connecting to %s", d.hostname.c_str());
#endif #endif
if (m.act == mapping_t::action::add) if (m.act == portmap_action::add)
{ {
if (m.failcount > 5) if (m.failcount > 5)
{ {
m.act = mapping_t::action::none; m.act = portmap_action::none;
// giving up // giving up
next(d, i); next(d, i);
return; return;
@ -819,7 +819,7 @@ void upnp::update_map(rootdevice& d, int const i)
d.upnp_connection->start(d.hostname, d.port d.upnp_connection->start(d.hostname, d.port
, seconds(10), 1, NULL, false, 5, m.local_ep.address()); , 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(); if (d.upnp_connection) d.upnp_connection->close();
d.upnp_connection = std::make_shared<http_connection>(m_io_service d.upnp_connection = std::make_shared<http_connection>(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()); , 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) void upnp::delete_port_mapping(rootdevice& d, int const i)
@ -863,7 +863,7 @@ void upnp::delete_port_mapping(rootdevice& d, int const i)
"</u:%s></s:Body></s:Envelope>" "</u:%s></s:Body></s:Envelope>"
, soap_action, d.service_namespace.c_str() , soap_action, d.service_namespace.c_str()
, d.mapping[i].external_port , d.mapping[i].external_port
, (d.mapping[i].protocol == portmap_protocol::udp ? "UDP" : "TCP") , to_string(d.mapping[i].protocol)
, soap_action); , soap_action);
post(d, soap, 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) else if (type == xml_string && state.in_error_code)
{ {
std::string error_code_str(string.begin(), string.end()); state.error_code = std::atoi(string.to_string().c_str());
state.error_code = std::atoi(error_code_str.c_str());
state.exit = true; state.exit = true;
} }
} }
@ -1380,7 +1379,7 @@ void upnp::on_upnp_map_response(error_code const& e
{ {
// only permanent leases supported // only permanent leases supported
d.lease_duration = 0; d.lease_duration = 0;
m.act = mapping_t::action::add; m.act = portmap_action::add;
++m.failcount; ++m.failcount;
update_map(d, mapping); update_map(d, mapping);
return; return;
@ -1395,7 +1394,7 @@ void upnp::on_upnp_map_response(error_code const& e
// The external port conflicts with another mapping // The external port conflicts with another mapping
// pick a random port // pick a random port
m.external_port = 40000 + int(random(10000)); m.external_port = 40000 + int(random(10000));
m.act = mapping_t::action::add; m.act = portmap_action::add;
++m.failcount; ++m.failcount;
update_map(d, mapping); update_map(d, mapping);
return; return;
@ -1594,12 +1593,12 @@ void upnp::close()
, end2(d.mapping.end()); j != end2; ++j) , end2(d.mapping.end()); j != end2; ++j)
{ {
if (j->protocol == portmap_protocol::none) continue; 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; continue;
} }
j->act = mapping_t::action::del; j->act = portmap_action::del;
m_mappings[int(j - d.mapping.begin())].protocol = portmap_protocol::none; m_mappings[int(j - d.mapping.begin())].protocol = portmap_protocol::none;
} }
if (num_mappings() > 0) update_map(d, 0); if (num_mappings() > 0) update_map(d, 0);