diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b60dbd0e..4f329339f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -214,6 +214,7 @@ set(libtorrent_aux_include_files allocating_handler array bind_to_device + keepalive block_cache_reference byteswap cppint_import_export diff --git a/ChangeLog b/ChangeLog index b02c20381..9a05f621f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * lower SOCKS5 UDP keepalive timeout * fix external IP voting for multi-homed DHT nodes * deprecate broadcast_lsd setting. Just use multicast * deprecate upnp_ignore_nonrouters setting diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index de7f00178..2348f4d5a 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -164,6 +164,7 @@ nobase_include_HEADERS = \ aux_/aligned_storage.hpp \ aux_/aligned_union.hpp \ aux_/bind_to_device.hpp \ + aux_/keepalive.hpp \ aux_/block_cache_reference.hpp \ aux_/container_wrapper.hpp \ aux_/cpuid.hpp \ diff --git a/include/libtorrent/aux_/keepalive.hpp b/include/libtorrent/aux_/keepalive.hpp new file mode 100644 index 000000000..2e5fb304f --- /dev/null +++ b/include/libtorrent/aux_/keepalive.hpp @@ -0,0 +1,102 @@ +/* + +Copyright (c) 2020, Arvid Norberg +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_KEEP_ALIVE_HPP_INCLUDED +#define TORRENT_KEEP_ALIVE_HPP_INCLUDED + +#if !defined _WIN32 + +#include "libtorrent/config.hpp" + +#include // for IPPROTO_TCP + +namespace libtorrent { +namespace aux { + +#if defined TCP_KEEPIDLE +#define TORRENT_HAS_KEEPALIVE_IDLE + struct tcp_keepalive_idle + { + explicit tcp_keepalive_idle(int seconds): m_value(seconds) {} + template + int level(Protocol const&) const { return IPPROTO_TCP; } + template + int name(Protocol const&) const { return TCP_KEEPIDLE; } + template + char const* data(Protocol const&) const { return reinterpret_cast(&m_value); } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + private: + int m_value; + }; +#elif defined TCP_KEEPALIVE +#define TORRENT_HAS_KEEPALIVE_IDLE + struct tcp_keepalive_idle + { + explicit tcp_keepalive_idle(int seconds): m_value(seconds) {} + template + int level(Protocol const&) const { return IPPROTO_TCP; } + template + int name(Protocol const&) const { return TCP_KEEPALIVE; } + template + char const* data(Protocol const&) const { return reinterpret_cast(&m_value); } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + private: + int m_value; + }; +#endif + +#ifdef TCP_KEEPINTVL +#define TORRENT_HAS_KEEPALIVE_INTERVAL + struct tcp_keepalive_interval + { + explicit tcp_keepalive_interval(int seconds): m_value(seconds) {} + template + int level(Protocol const&) const { return IPPROTO_TCP; } + template + int name(Protocol const&) const { return TCP_KEEPINTVL; } + template + char const* data(Protocol const&) const { return reinterpret_cast(&m_value); } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + private: + int m_value; + }; +#endif +} +} + +#endif // _WIN32 + +#endif + diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 3b93cdef7..ed5b3e435 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -42,6 +42,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" // for is_v4 #include "libtorrent/alert_manager.hpp" #include "libtorrent/socks5_stream.hpp" // for socks_error +#include "libtorrent/aux_/keepalive.hpp" #include #include @@ -50,6 +51,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/aux_/disable_warnings_pop.hpp" +#ifdef _WIN32 +// for SIO_KEEPALIVE_VALS +#include +#endif + namespace libtorrent { using namespace std::placeholders; @@ -570,9 +576,46 @@ void socks5::on_name_lookup(error_code const& e, tcp::resolver::iterator i) { if (m_alerts.should_post()) m_alerts.emplace_alert(m_proxy_addr, operation_t::sock_option, ec); - return; + ec.clear(); } +#if defined _WIN32 && !defined TORRENT_BUILD_SIMULATOR + SOCKET sock = m_socks5_sock.native_handle(); + DWORD bytes = 0; + tcp_keepalive timeout{}; + timeout.onoff = TRUE; + timeout.keepalivetime = 30; + timeout.keepaliveinterval = 30; + auto const ret = WSAIoctl(sock, SIO_KEEPALIVE_VALS, &timeout, sizeof(timeout) + , nullptr, 0, &bytes, nullptr, nullptr); + if (ret != 0) + { + if (m_alerts.should_post()) + m_alerts.emplace_alert(m_proxy_addr, operation_t::sock_option + , error_code(WSAGetLastError(), system_category())); + } +#else +#if defined TORRENT_HAS_KEEPALIVE_IDLE + // set keepalive timeouts + m_socks5_sock.set_option(aux::tcp_keepalive_idle(30), ec); + if (ec) + { + if (m_alerts.should_post()) + m_alerts.emplace_alert(m_proxy_addr, operation_t::sock_option, ec); + ec.clear(); + } +#endif +#ifdef TORRENT_HAS_KEEPALIVE_INTERVAL + m_socks5_sock.set_option(aux::tcp_keepalive_interval(1), ec); + if (ec) + { + if (m_alerts.should_post()) + m_alerts.emplace_alert(m_proxy_addr, operation_t::sock_option, ec); + ec.clear(); + } +#endif +#endif + tcp::endpoint const bind_ep(m_listen_socket.get_local_endpoint().address(), 0); m_socks5_sock.bind(bind_ep, ec); if (ec)