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
};
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

View File

@ -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<mapping_t> m_mappings;

View File

@ -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;
};

View File

@ -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);

View File

@ -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)
"<NewLeaseDuration>%u</NewLeaseDuration>"
"</u:%s></s:Body></s:Envelope>"
, 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<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());
}
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)
"</u:%s></s:Body></s:Envelope>"
, 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);