forward-port reuse address patch for windows

This commit is contained in:
arvidn 2016-01-31 03:06:24 -05:00 committed by arvidn
parent 07d7d72a58
commit e584c30b29
4 changed files with 44 additions and 12 deletions

View File

@ -84,6 +84,7 @@
* almost completely changed the storage interface (for custom storage) * almost completely changed the storage interface (for custom storage)
* added support for hashing pieces in multiple threads * added support for hashing pieces in multiple threads
* improve reliability of binding listen sockets
* support SNI in https web seeds and trackers * support SNI in https web seeds and trackers
* fix unhandled exception in DHT when receiving a DHT packet over IPv6 * fix unhandled exception in DHT when receiving a DHT packet over IPv6

View File

@ -120,7 +120,21 @@ namespace libtorrent
size_t size(Protocol const&) const { return sizeof(m_value); } size_t size(Protocol const&) const { return sizeof(m_value); }
int m_value; int m_value;
}; };
#endif
struct exclusive_address_use
{
exclusive_address_use(int enable): m_value(enable) {}
template<class Protocol>
int level(Protocol const&) const { return SOL_SOCKET; }
template<class Protocol>
int name(Protocol const&) const { return SO_EXCLUSIVEADDRUSE; }
template<class Protocol>
int const* data(Protocol const&) const { return &m_value; }
template<class Protocol>
size_t size(Protocol const&) const { return sizeof(m_value); }
int m_value;
};
#endif // TORRENT_WINDOWS
#ifdef IPV6_TCLASS #ifdef IPV6_TCLASS
struct traffic_class struct traffic_class

View File

@ -1708,16 +1708,14 @@ namespace aux {
return ret; return ret;
} }
// SO_REUSEADDR on windows is a bit special. It actually allows
// two active sockets to bind to the same port. That means we
// may end up binding to the same socket as some other random
// application. Don't do it!
#ifndef TORRENT_WINDOWS
{ {
error_code err; // ignore errors here // this is best-effort. ignore errors
error_code err;
#ifdef TORRENT_WINDOWS
ret.sock->set_option(exclusive_address_use(true), err);
#endif
ret.sock->set_option(tcp::acceptor::reuse_address(true), err); ret.sock->set_option(tcp::acceptor::reuse_address(true), err);
} }
#endif
#if TORRENT_USE_IPV6 #if TORRENT_USE_IPV6
if (!ipv4) if (!ipv4)
@ -1726,6 +1724,7 @@ namespace aux {
#ifdef IPV6_V6ONLY #ifdef IPV6_V6ONLY
ret.sock->set_option(v6only(true), err); ret.sock->set_option(v6only(true), err);
#endif #endif
#ifdef TORRENT_WINDOWS #ifdef TORRENT_WINDOWS
#ifndef PROTECTION_LEVEL_UNRESTRICTED #ifndef PROTECTION_LEVEL_UNRESTRICTED
@ -1733,7 +1732,7 @@ namespace aux {
#endif #endif
// enable Teredo on windows // enable Teredo on windows
ret.sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err); ret.sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err);
#endif #endif // TORRENT_WINDOWS
} }
#endif // TORRENT_USE_IPV6 #endif // TORRENT_USE_IPV6
@ -4893,6 +4892,9 @@ retry:
tcp::endpoint bind_ep(address_v4(), 0); tcp::endpoint bind_ep(address_v4(), 0);
if (m_settings.get_int(settings_pack::outgoing_port) > 0) if (m_settings.get_int(settings_pack::outgoing_port) > 0)
{ {
#ifdef TORRENT_WINDOWS
s.set_option(exclusive_address_use(true), ec);
#endif
s.set_option(tcp::acceptor::reuse_address(true), ec); s.set_option(tcp::acceptor::reuse_address(true), ec);
// ignore errors because the underlying socket may not // ignore errors because the underlying socket may not
// be opened yet. This happens when we're routing through // be opened yet. This happens when we're routing through

View File

@ -789,6 +789,14 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
{ {
m_ipv4_sock.open(udp::v4(), ec); m_ipv4_sock.open(udp::v4(), ec);
if (ec) return; if (ec) return;
// this is best-effort. ignore errors
error_code err;
#ifdef TORRENT_WINDOWS
m_ipv4_sock.set_option(exclusive_address_use(true), err);
#endif
m_ipv4_sock.set_option(boost::asio::socket_base::reuse_address(true), err);
m_ipv4_sock.bind(ep, ec); m_ipv4_sock.bind(ep, ec);
if (ec) return; if (ec) return;
udp::socket::non_blocking_io ioc(true); udp::socket::non_blocking_io ioc(true);
@ -807,10 +815,17 @@ void udp_socket::bind(udp::endpoint const& ep, error_code& ec)
if (is_any(ep.address())) ep6.address(address_v6::any()); if (is_any(ep.address())) ep6.address(address_v6::any());
m_ipv6_sock.open(udp::v6(), ec); m_ipv6_sock.open(udp::v6(), ec);
if (ec) return; if (ec) return;
#ifdef IPV6_V6ONLY
m_ipv6_sock.set_option(v6only(true), ec); // this is best-effort. ignore errors
ec.clear(); error_code err;
#ifdef TORRENT_WINDOWS
m_ipv4_sock.set_option(exclusive_address_use(true), err);
#endif #endif
m_ipv4_sock.set_option(boost::asio::socket_base::reuse_address(true), err);
#ifdef IPV6_V6ONLY
m_ipv6_sock.set_option(v6only(true), err);
#endif
m_ipv6_sock.bind(ep6, ec); m_ipv6_sock.bind(ep6, ec);
if (ec != error_code(boost::system::errc::address_not_available if (ec != error_code(boost::system::errc::address_not_available
, boost::system::generic_category())) , boost::system::generic_category()))