reopen listen sockets when the system's IP changes (#1299)
reopen listen sockets when the system's IP changes. Only Linux and Windows supported for now.
This commit is contained in:
parent
11ca69b9fc
commit
e589e342ef
|
@ -45,6 +45,7 @@ set(sources
|
|||
i2p_stream
|
||||
identify_client
|
||||
ip_filter
|
||||
ip_notifier
|
||||
ip_voter
|
||||
performance_counters
|
||||
peer_class
|
||||
|
|
1
Jamfile
1
Jamfile
|
@ -599,6 +599,7 @@ SOURCES =
|
|||
http_parser
|
||||
identify_client
|
||||
ip_filter
|
||||
ip_notifier
|
||||
ip_voter
|
||||
merkle
|
||||
peer_connection
|
||||
|
|
|
@ -70,6 +70,7 @@ nobase_include_HEADERS = \
|
|||
io_service.hpp \
|
||||
io_service_fwd.hpp \
|
||||
ip_filter.hpp \
|
||||
ip_notifier.hpp \
|
||||
ip_voter.hpp \
|
||||
lazy_entry.hpp \
|
||||
link.hpp \
|
||||
|
@ -77,6 +78,7 @@ nobase_include_HEADERS = \
|
|||
lsd.hpp \
|
||||
magnet_uri.hpp \
|
||||
natpmp.hpp \
|
||||
netlink.hpp \
|
||||
operations.hpp \
|
||||
packet_buffer.hpp \
|
||||
parse_url.hpp \
|
||||
|
|
|
@ -54,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/debug.hpp"
|
||||
#include "libtorrent/piece_block_progress.hpp"
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/ip_notifier.hpp"
|
||||
#include "libtorrent/session_status.hpp"
|
||||
#include "libtorrent/add_torrent_params.hpp"
|
||||
#include "libtorrent/stat.hpp"
|
||||
|
@ -251,6 +252,7 @@ namespace libtorrent
|
|||
void on_exception(std::exception const& e) override;
|
||||
void on_error(error_code const& ec) override;
|
||||
|
||||
void on_ip_change(error_code const& ec);
|
||||
void reopen_listen_sockets();
|
||||
|
||||
torrent_peer_allocator_interface* get_peer_allocator() override
|
||||
|
@ -858,6 +860,9 @@ namespace libtorrent
|
|||
// at startup
|
||||
int m_key = 0;
|
||||
|
||||
// posts a notification when the set of local IPs changes
|
||||
ip_change_notifier m_ip_notifier;
|
||||
|
||||
// the addresses or device names of the interfaces we are supposed to
|
||||
// listen on. if empty, it means that we should let the os decide
|
||||
// which interface to listen on
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016, Steven Siloti
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_IP_NOTIFIER_HPP_INCLUDED
|
||||
#define TORRENT_IP_NOTIFIER_HPP_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include <array>
|
||||
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/address.hpp"
|
||||
#include "libtorrent/io_service.hpp"
|
||||
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
#elif TORRENT_USE_NETLINK
|
||||
#include "libtorrent/netlink.hpp"
|
||||
#elif defined TORRENT_WINDOWS
|
||||
#include <boost/asio/windows/object_handle.hpp>
|
||||
#endif
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
struct ip_change_notifier : boost::noncopyable
|
||||
{
|
||||
explicit ip_change_notifier(io_service& ios);
|
||||
~ip_change_notifier();
|
||||
|
||||
// cb will be invoked when a change is detected in the
|
||||
// system's IP addresses
|
||||
void async_wait(std::function<void(error_code const&)> cb);
|
||||
void cancel();
|
||||
|
||||
private:
|
||||
void on_notify(error_code const& error
|
||||
, std::size_t bytes_transferred
|
||||
, std::function<void(error_code const&)> cb);
|
||||
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
// TODO simulator support
|
||||
#elif TORRENT_USE_NETLINK
|
||||
netlink::socket m_socket;
|
||||
std::array<char, 4096> m_buf;
|
||||
#elif defined TORRENT_WINDOWS
|
||||
OVERLAPPED m_ovl = {};
|
||||
boost::asio::windows::object_handle m_hnd;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,203 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016, Steven Siloti
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef TORRENT_NETLINK_HPP
|
||||
#define TORRENT_NETLINK_HPP
|
||||
|
||||
#include "libtorrent/config.hpp"
|
||||
|
||||
#if TORRENT_USE_NETLINK
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdint>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <boost/asio/basic_raw_socket.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
template <typename Protocol>
|
||||
class basic_nl_endpoint
|
||||
{
|
||||
public:
|
||||
using protocol_type = Protocol;
|
||||
using data_type = boost::asio::detail::socket_addr_type;
|
||||
|
||||
basic_nl_endpoint()
|
||||
{
|
||||
std::memset(&sockaddr, 0, sizeof(sockaddr_nl));
|
||||
sockaddr.nl_family = AF_NETLINK;
|
||||
sockaddr.nl_groups = 0;
|
||||
sockaddr.nl_pid = 0;
|
||||
}
|
||||
|
||||
basic_nl_endpoint(protocol_type netlink_family, std::uint32_t group, ::pid_t pid = 0)
|
||||
: proto(netlink_family)
|
||||
{
|
||||
std::memset(&sockaddr, 0, sizeof(sockaddr_nl));
|
||||
sockaddr.nl_family = AF_NETLINK;
|
||||
sockaddr.nl_groups = group;
|
||||
sockaddr.nl_pid = pid;
|
||||
}
|
||||
|
||||
basic_nl_endpoint(basic_nl_endpoint const& other)
|
||||
{
|
||||
sockaddr = other.sockaddr;
|
||||
}
|
||||
|
||||
basic_nl_endpoint& operator=(const basic_nl_endpoint& other)
|
||||
{
|
||||
sockaddr = other.sockaddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
basic_nl_endpoint& operator=(const basic_nl_endpoint&& other)
|
||||
{
|
||||
sockaddr = other.sockaddr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
protocol_type protocol() const
|
||||
{
|
||||
return proto;
|
||||
}
|
||||
|
||||
data_type* data()
|
||||
{
|
||||
return &sockaddr;
|
||||
}
|
||||
|
||||
const data_type* data() const
|
||||
{
|
||||
return (struct sockaddr*)&sockaddr;
|
||||
}
|
||||
|
||||
std::size_t size() const
|
||||
{
|
||||
return sizeof(sockaddr);
|
||||
}
|
||||
|
||||
std::size_t capacity() const
|
||||
{
|
||||
return sizeof(sockaddr);
|
||||
}
|
||||
|
||||
friend bool operator==(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return l.sockaddr == r.sockaddr;
|
||||
}
|
||||
|
||||
friend bool operator!=(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return !(l.sockaddr == r.sockaddr);
|
||||
}
|
||||
|
||||
friend bool operator<(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return l.sockaddr < r.sockaddr;
|
||||
}
|
||||
|
||||
friend bool operator>(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return r.sockaddr < l.sockaddr;
|
||||
}
|
||||
|
||||
friend bool operator<=(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return !(r < l);
|
||||
}
|
||||
|
||||
friend bool operator>=(const basic_nl_endpoint<Protocol>& l
|
||||
, const basic_nl_endpoint<Protocol>& r)
|
||||
{
|
||||
return !(l < r);
|
||||
}
|
||||
|
||||
private:
|
||||
protocol_type proto;
|
||||
sockaddr_nl sockaddr;
|
||||
};
|
||||
|
||||
class netlink
|
||||
{
|
||||
public:
|
||||
using endpoint = basic_nl_endpoint<netlink>;
|
||||
using socket = boost::asio::basic_raw_socket<netlink>;
|
||||
|
||||
netlink() : nl_family(0)
|
||||
{
|
||||
}
|
||||
|
||||
explicit netlink(int nl_family)
|
||||
: nl_family(nl_family)
|
||||
{
|
||||
}
|
||||
|
||||
int type() const
|
||||
{
|
||||
return SOCK_RAW;
|
||||
}
|
||||
|
||||
int protocol() const
|
||||
{
|
||||
return nl_family;
|
||||
}
|
||||
|
||||
int family() const
|
||||
{
|
||||
return AF_NETLINK;
|
||||
}
|
||||
|
||||
friend bool operator==(const netlink& l, const netlink& r)
|
||||
{
|
||||
return l.nl_family == r.nl_family;
|
||||
}
|
||||
|
||||
friend bool operator!=(const netlink& l, const netlink& r)
|
||||
{
|
||||
return l.nl_family != r.nl_family;
|
||||
}
|
||||
|
||||
private:
|
||||
int nl_family;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -88,6 +88,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
|||
identify_client.cpp \
|
||||
instantiate_connection.cpp \
|
||||
ip_filter.cpp \
|
||||
ip_notifier.cpp \
|
||||
ip_voter.cpp \
|
||||
lazy_bdecode.cpp \
|
||||
lsd.cpp \
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2016, Steven Siloti
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in
|
||||
the documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of the author nor the names of its
|
||||
contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#include "libtorrent/ip_notifier.hpp"
|
||||
|
||||
#if defined TORRENT_WINDOWS && !defined TORRENT_BUILD_SIMULATOR
|
||||
#include <iphlpapi.h>
|
||||
#endif
|
||||
|
||||
using namespace std::placeholders;
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
ip_change_notifier::ip_change_notifier(io_service& ios)
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
#elif TORRENT_USE_NETLINK
|
||||
: m_socket(ios
|
||||
, netlink::endpoint(netlink(NETLINK_ROUTE), RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR))
|
||||
#elif defined TORRENT_WINDOWS
|
||||
: m_hnd(ios, WSACreateEvent())
|
||||
#endif
|
||||
{
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
TORRENT_UNUSED(ios);
|
||||
#elif defined TORRENT_WINDOWS
|
||||
if (!m_hnd.is_open())
|
||||
throw system_error(WSAGetLastError(), system_category());
|
||||
m_ovl.hEvent = m_hnd.native_handle();
|
||||
#elif !TORRENT_USE_NETLINK
|
||||
TORRENT_UNUSED(ios);
|
||||
#endif
|
||||
}
|
||||
|
||||
ip_change_notifier::~ip_change_notifier()
|
||||
{
|
||||
#if defined TORRENT_WINDOWS && !defined TORRENT_BUILD_SIMULATOR
|
||||
cancel();
|
||||
m_hnd.close();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ip_change_notifier::async_wait(std::function<void(error_code const&)> cb)
|
||||
{
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
TORRENT_UNUSED(cb);
|
||||
#elif TORRENT_USE_NETLINK
|
||||
m_socket.async_receive(boost::asio::buffer(m_buf)
|
||||
, std::bind(&ip_change_notifier::on_notify, this, _1, _2, cb));
|
||||
#elif defined TORRENT_WINDOWS
|
||||
HANDLE hnd;
|
||||
DWORD err = NotifyAddrChange(&hnd, &m_ovl);
|
||||
if (err == ERROR_IO_PENDING)
|
||||
{
|
||||
m_hnd.async_wait([this,cb](error_code const& ec) { on_notify(ec, 0, cb); });
|
||||
}
|
||||
else
|
||||
{
|
||||
m_hnd.get_io_service().post([this,cb,err]()
|
||||
{ cb(error_code(err, system_category())); });
|
||||
}
|
||||
#else
|
||||
TORRENT_UNUSED(cb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void ip_change_notifier::cancel()
|
||||
{
|
||||
#if defined TORRENT_BUILD_SIMULATOR
|
||||
#elif TORRENT_USE_NETLINK
|
||||
m_socket.cancel();
|
||||
#elif defined TORRENT_WINDOWS
|
||||
CancelIPChangeNotify(&m_ovl);
|
||||
m_hnd.cancel();
|
||||
#endif
|
||||
}
|
||||
|
||||
void ip_change_notifier::on_notify(error_code const& ec
|
||||
, std::size_t bytes_transferred
|
||||
, std::function<void(error_code const&)> cb)
|
||||
{
|
||||
TORRENT_UNUSED(bytes_transferred);
|
||||
|
||||
// on linux we could parse the message to get information about the
|
||||
// change but Windows requires the application to enumerate the
|
||||
// interfaces after a notification so do that for Linux as well to
|
||||
// minimize the difference between platforms
|
||||
|
||||
// Linux can generate ENOBUFS if the socket's buffers are full
|
||||
// don't treat it as an error
|
||||
if (ec.value() == boost::system::errc::no_buffer_space)
|
||||
cb(error_code());
|
||||
else
|
||||
cb(ec);
|
||||
}
|
||||
}
|
|
@ -411,6 +411,7 @@ namespace aux {
|
|||
#endif
|
||||
)
|
||||
, m_work(new io_service::work(m_io_service))
|
||||
, m_ip_notifier(m_io_service)
|
||||
#if TORRENT_USE_I2P
|
||||
, m_i2p_conn(m_io_service)
|
||||
#endif
|
||||
|
@ -605,6 +606,9 @@ namespace aux {
|
|||
session_log(" done starting session");
|
||||
#endif
|
||||
|
||||
m_ip_notifier.async_wait([this](error_code const& e)
|
||||
{ this->wrap(&session_impl::on_ip_change, e); });
|
||||
|
||||
apply_settings_pack_impl(*pack, true);
|
||||
|
||||
// call update_* after settings set initialized
|
||||
|
@ -859,6 +863,9 @@ namespace aux {
|
|||
// abort the main thread
|
||||
m_abort = true;
|
||||
error_code ec;
|
||||
|
||||
m_ip_notifier.cancel();
|
||||
|
||||
#if TORRENT_USE_I2P
|
||||
m_i2p_conn.close(ec);
|
||||
#endif
|
||||
|
@ -1686,6 +1693,14 @@ namespace aux {
|
|||
this->abort();
|
||||
}
|
||||
|
||||
void session_impl::on_ip_change(error_code const& ec)
|
||||
{
|
||||
if (ec || m_abort) return;
|
||||
m_ip_notifier.async_wait([this] (error_code const& e)
|
||||
{ this->wrap(&session_impl::on_ip_change, e); });
|
||||
reopen_listen_sockets();
|
||||
}
|
||||
|
||||
void session_impl::reopen_listen_sockets()
|
||||
{
|
||||
#ifndef TORRENT_DISABLE_LOGGING
|
||||
|
|
Loading…
Reference in New Issue