create a natpmp instance for each listen socket
This commit is contained in:
parent
496cf46b25
commit
78be52112f
|
@ -201,6 +201,8 @@ namespace aux {
|
||||||
// time on handler allocation every time we read again.
|
// time on handler allocation every time we read again.
|
||||||
aux::handler_storage<TORRENT_READ_HANDLER_MAX_SIZE> udp_handler_storage;
|
aux::handler_storage<TORRENT_READ_HANDLER_MAX_SIZE> udp_handler_storage;
|
||||||
|
|
||||||
|
std::shared_ptr<natpmp> natpmp_mapper;
|
||||||
|
|
||||||
// the key is an id that is used to identify the
|
// the key is an id that is used to identify the
|
||||||
// client with the tracker only.
|
// client with the tracker only.
|
||||||
std::uint32_t tracker_key = 0;
|
std::uint32_t tracker_key = 0;
|
||||||
|
@ -636,7 +638,7 @@ namespace aux {
|
||||||
|
|
||||||
void start_ip_notifier();
|
void start_ip_notifier();
|
||||||
void start_lsd();
|
void start_lsd();
|
||||||
natpmp* start_natpmp();
|
void start_natpmp();
|
||||||
upnp* start_upnp();
|
upnp* start_upnp();
|
||||||
|
|
||||||
void stop_ip_notifier();
|
void stop_ip_notifier();
|
||||||
|
@ -777,6 +779,8 @@ namespace aux {
|
||||||
|
|
||||||
void on_lsd_peer(tcp::endpoint const& peer, sha1_hash const& ih) override;
|
void on_lsd_peer(tcp::endpoint const& peer, sha1_hash const& ih) override;
|
||||||
|
|
||||||
|
void start_natpmp(aux::listen_socket_t& s);
|
||||||
|
|
||||||
void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip
|
void set_external_address(std::shared_ptr<listen_socket_t> const& sock, address const& ip
|
||||||
, ip_source_t source_type, address const& source);
|
, ip_source_t source_type, address const& source);
|
||||||
|
|
||||||
|
@ -1136,7 +1140,6 @@ namespace aux {
|
||||||
// this is deducted from the connect speed
|
// this is deducted from the connect speed
|
||||||
int m_boost_connections = 0;
|
int m_boost_connections = 0;
|
||||||
|
|
||||||
std::shared_ptr<natpmp> m_natpmp;
|
|
||||||
std::shared_ptr<upnp> m_upnp;
|
std::shared_ptr<upnp> m_upnp;
|
||||||
std::shared_ptr<lsd> m_lsd;
|
std::shared_ptr<lsd> m_lsd;
|
||||||
|
|
||||||
|
|
|
@ -94,7 +94,9 @@ namespace libtorrent {
|
||||||
TORRENT_EXTRA_EXPORT bool in_local_network(std::vector<ip_interface> const& net
|
TORRENT_EXTRA_EXPORT bool in_local_network(std::vector<ip_interface> const& net
|
||||||
, address const& addr);
|
, address const& addr);
|
||||||
|
|
||||||
TORRENT_EXTRA_EXPORT address get_default_gateway(io_service& ios, error_code& ec);
|
// returns the first default gateway found if device is empty
|
||||||
|
TORRENT_EXTRA_EXPORT address get_default_gateway(io_service& ios
|
||||||
|
, string_view device, bool v6, error_code& ec);
|
||||||
|
|
||||||
// attempt to bind socket to the device with the specified name. For systems
|
// attempt to bind socket to the device with the specified name. For systems
|
||||||
// that don't support SO_BINDTODEVICE the socket will be bound to one of the
|
// that don't support SO_BINDTODEVICE the socket will be bound to one of the
|
||||||
|
|
|
@ -51,7 +51,7 @@ struct TORRENT_EXTRA_EXPORT natpmp
|
||||||
{
|
{
|
||||||
natpmp(io_service& ios, aux::portmap_callback& cb);
|
natpmp(io_service& ios, aux::portmap_callback& cb);
|
||||||
|
|
||||||
void start();
|
void start(address const& local_address, std::string device);
|
||||||
|
|
||||||
// maps the ports, if a port is set to 0
|
// maps the ports, if a port is set to 0
|
||||||
// it will not be mapped
|
// it will not be mapped
|
||||||
|
|
|
@ -846,11 +846,17 @@ int _System __libsocket_sysctl(int* mib, u_int namelen, void *oldp, size_t *oldl
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
address get_default_gateway(io_service& ios, error_code& ec)
|
address get_default_gateway(io_service& ios
|
||||||
|
, string_view device, bool v6, error_code& ec)
|
||||||
{
|
{
|
||||||
std::vector<ip_route> ret = enum_routes(ios, ec);
|
std::vector<ip_route> ret = enum_routes(ios, ec);
|
||||||
auto const i = std::find_if(ret.begin(), ret.end()
|
auto const i = std::find_if(ret.begin(), ret.end()
|
||||||
, [](ip_route const& r) { return r.destination == address(); });
|
, [device,v6](ip_route const& r)
|
||||||
|
{
|
||||||
|
return r.destination.is_unspecified()
|
||||||
|
&& r.destination.is_v6() == v6
|
||||||
|
&& (device.empty() || r.name == device);
|
||||||
|
});
|
||||||
if (i == ret.end()) return address();
|
if (i == ret.end()) return address();
|
||||||
return i->gateway;
|
return i->gateway;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,19 +76,31 @@ natpmp::natpmp(io_service& ios
|
||||||
m_mappings.reserve(10);
|
m_mappings.reserve(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void natpmp::start()
|
void natpmp::start(address const& local_address, std::string device)
|
||||||
{
|
{
|
||||||
TORRENT_ASSERT(is_single_thread());
|
TORRENT_ASSERT(is_single_thread());
|
||||||
|
|
||||||
error_code ec;
|
error_code ec;
|
||||||
address const gateway = get_default_gateway(m_socket.get_io_service(), ec);
|
|
||||||
if (ec)
|
// we really want a device name to get the right default gateway
|
||||||
|
// try to find one even if the listen socket isn't bound to a device
|
||||||
|
if (device.empty())
|
||||||
|
{
|
||||||
|
device = device_for_address(local_address, m_socket.get_io_service(), ec);
|
||||||
|
// if this failes fall back to using the first default gateway in the
|
||||||
|
// routing table
|
||||||
|
ec.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
address const gateway = get_default_gateway(m_socket.get_io_service()
|
||||||
|
, device, local_address.is_v6(), ec);
|
||||||
|
if (ec || gateway.is_unspecified())
|
||||||
{
|
{
|
||||||
#ifndef TORRENT_DISABLE_LOGGING
|
#ifndef TORRENT_DISABLE_LOGGING
|
||||||
if (should_log())
|
if (should_log())
|
||||||
{
|
{
|
||||||
log("failed to find default route: %s"
|
log("failed to find default route for %s: %s"
|
||||||
, convert_from_native(ec.message()).c_str());
|
, local_address.to_string().c_str(), convert_from_native(ec.message()).c_str());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
disable(ec);
|
disable(ec);
|
||||||
|
@ -109,13 +121,13 @@ void natpmp::start()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_socket.open(udp::v4(), ec);
|
m_socket.open(local_address.is_v4() ? udp::v4() : udp::v6(), ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
disable(ec);
|
disable(ec);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_socket.bind({address_v4::any(), 0}, ec);
|
m_socket.bind({local_address, 0}, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
disable(ec);
|
disable(ec);
|
||||||
|
|
|
@ -1859,6 +1859,7 @@ namespace aux {
|
||||||
#endif
|
#endif
|
||||||
if ((*remove_iter)->sock) (*remove_iter)->sock->close(ec);
|
if ((*remove_iter)->sock) (*remove_iter)->sock->close(ec);
|
||||||
if ((*remove_iter)->udp_sock) (*remove_iter)->udp_sock->sock.close();
|
if ((*remove_iter)->udp_sock) (*remove_iter)->udp_sock->sock.close();
|
||||||
|
if ((*remove_iter)->natpmp_mapper) (*remove_iter)->natpmp_mapper->close();
|
||||||
remove_iter = m_listen_sockets.erase(remove_iter);
|
remove_iter = m_listen_sockets.erase(remove_iter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1879,9 +1880,11 @@ namespace aux {
|
||||||
|
|
||||||
TORRENT_ASSERT((s->incoming == duplex::accept_incoming) == bool(s->sock));
|
TORRENT_ASSERT((s->incoming == duplex::accept_incoming) == bool(s->sock));
|
||||||
if (s->sock) async_accept(s->sock, s->ssl);
|
if (s->sock) async_accept(s->sock, s->ssl);
|
||||||
|
if (m_settings.get_bool(settings_pack::enable_natpmp))
|
||||||
|
start_natpmp(*s);
|
||||||
// since this is a new socket it needs to map ports
|
// since this is a new socket it needs to map ports
|
||||||
// even if the caller did not request re-mapping
|
// even if the caller did not request re-mapping
|
||||||
if (!map_ports) remap_ports(remap_natpmp_and_upnp, *s);
|
if (!map_ports) remap_ports(remap_upnp, *s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2126,10 +2129,10 @@ namespace aux {
|
||||||
tcp::endpoint const tcp_ep = s.sock ? s.sock->local_endpoint() : tcp::endpoint();
|
tcp::endpoint const tcp_ep = s.sock ? s.sock->local_endpoint() : tcp::endpoint();
|
||||||
udp::endpoint const udp_ep = s.udp_sock ? s.udp_sock->sock.local_endpoint() : udp::endpoint();
|
udp::endpoint const udp_ep = s.udp_sock ? s.udp_sock->sock.local_endpoint() : udp::endpoint();
|
||||||
|
|
||||||
if ((mask & remap_natpmp) && m_natpmp)
|
if ((mask & remap_natpmp) && s.natpmp_mapper)
|
||||||
{
|
{
|
||||||
map_port(*m_natpmp, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]);
|
map_port(*s.natpmp_mapper, portmap_protocol::tcp, tcp_ep, s.tcp_port_mapping[0]);
|
||||||
map_port(*m_natpmp, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[0]);
|
map_port(*s.natpmp_mapper, portmap_protocol::udp, to_tcp(udp_ep), s.udp_port_mapping[0]);
|
||||||
}
|
}
|
||||||
if ((mask & remap_upnp) && m_upnp)
|
if ((mask & remap_upnp) && m_upnp)
|
||||||
{
|
{
|
||||||
|
@ -5450,6 +5453,23 @@ namespace aux {
|
||||||
m_alerts.emplace_alert<lsd_peer_alert>(t->get_handle(), peer);
|
m_alerts.emplace_alert<lsd_peer_alert>(t->get_handle(), peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void session_impl::start_natpmp(aux::listen_socket_t& s)
|
||||||
|
{
|
||||||
|
// don't create mappings for local IPv6 addresses
|
||||||
|
// they can't be reached from outside of the local network anyways
|
||||||
|
if (is_v6(s.local_endpoint) && is_local(s.local_endpoint.address()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!s.natpmp_mapper)
|
||||||
|
{
|
||||||
|
// the natpmp constructor may fail and call the callbacks
|
||||||
|
// into the session_impl.
|
||||||
|
s.natpmp_mapper = std::make_shared<natpmp>(m_io_service, *this);
|
||||||
|
s.natpmp_mapper->start(s.local_endpoint.address(), s.device);
|
||||||
|
}
|
||||||
|
remap_ports(remap_natpmp, s);
|
||||||
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool find_tcp_port_mapping(portmap_transport const transport
|
bool find_tcp_port_mapping(portmap_transport const transport
|
||||||
, port_mapping_t mapping, std::shared_ptr<listen_socket_t> const& ls)
|
, port_mapping_t mapping, std::shared_ptr<listen_socket_t> const& ls)
|
||||||
|
@ -6646,22 +6666,11 @@ namespace aux {
|
||||||
m_alerts.emplace_alert<lsd_error_alert>(ec);
|
m_alerts.emplace_alert<lsd_error_alert>(ec);
|
||||||
}
|
}
|
||||||
|
|
||||||
natpmp* session_impl::start_natpmp()
|
void session_impl::start_natpmp()
|
||||||
{
|
{
|
||||||
INVARIANT_CHECK;
|
INVARIANT_CHECK;
|
||||||
|
|
||||||
if (m_natpmp) return m_natpmp.get();
|
|
||||||
|
|
||||||
// the natpmp constructor may fail and call the callbacks
|
|
||||||
// into the session_impl.
|
|
||||||
m_natpmp = std::make_shared<natpmp>(m_io_service, *this);
|
|
||||||
m_natpmp->start();
|
|
||||||
|
|
||||||
for (auto& s : m_listen_sockets)
|
for (auto& s : m_listen_sockets)
|
||||||
{
|
start_natpmp(*s);
|
||||||
remap_ports(remap_natpmp, *s);
|
|
||||||
}
|
|
||||||
return m_natpmp.get();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
upnp* session_impl::start_upnp()
|
upnp* session_impl::start_upnp()
|
||||||
|
@ -6694,15 +6703,21 @@ namespace aux {
|
||||||
port_mapping_t ret{-1};
|
port_mapping_t ret{-1};
|
||||||
if (m_upnp) ret = m_upnp->add_mapping(t, external_port
|
if (m_upnp) ret = m_upnp->add_mapping(t, external_port
|
||||||
, tcp::endpoint({}, static_cast<std::uint16_t>(local_port)));
|
, tcp::endpoint({}, static_cast<std::uint16_t>(local_port)));
|
||||||
if (m_natpmp) ret = m_natpmp->add_mapping(t, external_port
|
for (auto& s : m_listen_sockets)
|
||||||
, tcp::endpoint({}, static_cast<std::uint16_t>(local_port)));
|
{
|
||||||
|
if (s->natpmp_mapper) ret = s->natpmp_mapper->add_mapping(t, external_port
|
||||||
|
, tcp::endpoint({}, static_cast<std::uint16_t>(local_port)));
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::delete_port_mapping(port_mapping_t handle)
|
void session_impl::delete_port_mapping(port_mapping_t handle)
|
||||||
{
|
{
|
||||||
if (m_upnp) m_upnp->delete_mapping(handle);
|
if (m_upnp) m_upnp->delete_mapping(handle);
|
||||||
if (m_natpmp) m_natpmp->delete_mapping(handle);
|
for (auto& s : m_listen_sockets)
|
||||||
|
{
|
||||||
|
if (s->natpmp_mapper) s->natpmp_mapper->delete_mapping(handle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::stop_ip_notifier()
|
void session_impl::stop_ip_notifier()
|
||||||
|
@ -6722,16 +6737,14 @@ namespace aux {
|
||||||
|
|
||||||
void session_impl::stop_natpmp()
|
void session_impl::stop_natpmp()
|
||||||
{
|
{
|
||||||
if (!m_natpmp) return;
|
|
||||||
|
|
||||||
m_natpmp->close();
|
|
||||||
for (auto& s : m_listen_sockets)
|
for (auto& s : m_listen_sockets)
|
||||||
{
|
{
|
||||||
s->tcp_port_mapping[0] = port_mapping_t{-1};
|
s->tcp_port_mapping[0] = port_mapping_t{-1};
|
||||||
s->udp_port_mapping[0] = port_mapping_t{-1};
|
s->udp_port_mapping[0] = port_mapping_t{-1};
|
||||||
|
if (!s->natpmp_mapper) continue;
|
||||||
|
s->natpmp_mapper->close();
|
||||||
|
s->natpmp_mapper.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
m_natpmp.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void session_impl::stop_upnp()
|
void session_impl::stop_upnp()
|
||||||
|
|
|
@ -42,7 +42,7 @@ int main()
|
||||||
io_service ios;
|
io_service ios;
|
||||||
error_code ec;
|
error_code ec;
|
||||||
|
|
||||||
address def_gw = get_default_gateway(ios, ec);
|
address def_gw = get_default_gateway(ios, "", false, ec);
|
||||||
if (ec)
|
if (ec)
|
||||||
{
|
{
|
||||||
std::printf("%s\n", ec.message().c_str());
|
std::printf("%s\n", ec.message().c_str());
|
||||||
|
|
Loading…
Reference in New Issue