From 72a24b63baa3e00afc1fb702ca505a181836952c Mon Sep 17 00:00:00 2001 From: arvidn Date: Mon, 8 Feb 2016 18:11:00 -0500 Subject: [PATCH] use bind_to_device for listen sockets --- include/libtorrent/Makefile.am | 1 + include/libtorrent/alert_types.hpp | 2 +- include/libtorrent/aux_/bind_to_device.hpp | 112 +++++++++++++++++++++ include/libtorrent/enum_net.hpp | 23 +---- src/alert.cpp | 3 +- src/session_impl.cpp | 29 +++++- src/string_util.cpp | 2 + 7 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 include/libtorrent/aux_/bind_to_device.hpp diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index b6918ae8e..97bd6d182 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -17,6 +17,7 @@ nobase_include_HEADERS = \ bandwidth_queue_entry.hpp \ bencode.hpp \ bdecode.hpp \ + bind_to_device.hpp \ bitfield.hpp \ block_cache.hpp \ bloom_filter.hpp \ diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp index 8298f88b3..c6094bd81 100644 --- a/include/libtorrent/alert_types.hpp +++ b/include/libtorrent/alert_types.hpp @@ -1286,7 +1286,7 @@ namespace libtorrent enum op_t { - parse_addr, open, bind, listen, get_socket_name, accept, enum_if + parse_addr, open, bind, listen, get_socket_name, accept, enum_if, bind_to_device }; // the specific low level operation that failed. See op_t. diff --git a/include/libtorrent/aux_/bind_to_device.hpp b/include/libtorrent/aux_/bind_to_device.hpp new file mode 100644 index 000000000..2a1742831 --- /dev/null +++ b/include/libtorrent/aux_/bind_to_device.hpp @@ -0,0 +1,112 @@ +/* + +Copyright (c) 2016, 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_BIND_TO_DEVICE_HPP_INCLUDED +#define TORRENT_BIND_TO_DEVICE_HPP_INCLUDED + +#include "libtorrent/config.hpp" +#include "libtorrent/socket.hpp" + +#if TORRENT_USE_IFCONF || TORRENT_USE_NETLINK || TORRENT_USE_SYSCTL +#include // for SO_BINDTODEVICE +#include +#endif + +namespace libtorrent { namespace aux { + +#if defined SO_BINDTODEVICE + + struct bind_to_device + { + bind_to_device(char const* device): m_value(device) {} + template + int level(Protocol const&) const { return SOL_SOCKET; } + template + int name(Protocol const&) const { return SO_BINDTODEVICE; } + template + char const* data(Protocol const&) const { return m_value; } + template + size_t size(Protocol const&) const { return strlen(m_value) + 1; } + private: + char const* m_value; + }; + +#define TORRENT_HAS_BINDTODEVICE 1 + +#elif defined IP_BOUND_IF + + struct bind_to_device + { + bind_to_device(char const* device): m_value(if_nametoindex(device)) {} + template + int level(Protocol const&) const { return IPPROTO_IP; } + template + int name(Protocol const&) const { return IP_BOUND_IF; } + template + char const* data(Protocol const&) const { return reinterpret_cast(&m_value); } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + private: + unsigned int m_value; + }; + +#define TORRENT_HAS_BINDTODEVICE 1 + +#elif defined IP_FORCE_OUT_IFP + + struct bind_to_device + { + bind_to_device(char const* device): m_value(device) {} + template + int level(Protocol const&) const { return SOL_SOCKET; } + template + int name(Protocol const&) const { return IP_FORCE_OUT_IFP; } + template + char const* data(Protocol const&) const { return m_value; } + template + size_t size(Protocol const&) const { return strlen(m_value) + 1; } + private: + char const* m_value; + }; + +#define TORRENT_HAS_BINDTODEVICE 1 + +#else + +#define TORRENT_HAS_BINDTODEVICE 0 + +#endif + +} } + +#endif + diff --git a/include/libtorrent/enum_net.hpp b/include/libtorrent/enum_net.hpp index c82c8e187..af59ff3c4 100644 --- a/include/libtorrent/enum_net.hpp +++ b/include/libtorrent/enum_net.hpp @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/address.hpp" #include "libtorrent/error_code.hpp" #include "libtorrent/socket.hpp" +#include "libtorrent/aux_/bind_to_device.hpp" namespace libtorrent { @@ -93,22 +94,6 @@ namespace libtorrent TORRENT_EXTRA_EXPORT address get_default_gateway(io_service& ios, error_code& ec); -#ifdef SO_BINDTODEVICE - struct bind_to_device_opt - { - bind_to_device_opt(char const* device): m_value(device) {} - template - int level(Protocol const&) const { return SOL_SOCKET; } - template - int name(Protocol const&) const { return SO_BINDTODEVICE; } - template - const char* data(Protocol const&) const { return m_value; } - template - size_t size(Protocol const&) const { return IFNAMSIZ; } - char const* m_value; - }; -#endif - // 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 // IP addresses of the specified device. In this case it is necessary to @@ -116,7 +101,7 @@ namespace libtorrent // the returned address is the ip the socket was bound to (or address_v4::any() // in case SO_BINDTODEVICE succeeded and we don't need to verify it). template - address bind_to_device(io_service& ios, Socket& sock + address bind_socket_to_device(io_service& ios, Socket& sock , boost::asio::ip::tcp const& protocol , char const* device_name, int port, error_code& ec) { @@ -140,10 +125,10 @@ namespace libtorrent ec.clear(); -#ifdef SO_BINDTODEVICE +#if TORRENT_HAS_BINDTODEVICE // try to use SO_BINDTODEVICE here, if that exists. If it fails, // fall back to the mechanism we have below - sock.set_option(bind_to_device_opt(device_name), ec); + sock.set_option(aux::bind_to_device(device_name), ec); if (ec) #endif { diff --git a/src/alert.cpp b/src/alert.cpp index 3df130dda..e11827866 100644 --- a/src/alert.cpp +++ b/src/alert.cpp @@ -818,7 +818,8 @@ namespace libtorrent { "listen", "get_socket_name", "accept", - "enum_if" + "enum_if", + "bind_to_device" }; char ret[300]; snprintf(ret, sizeof(ret), "listening on %s (device: %s) failed: [%s] [%s] %s" diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 07fc7de7d..4fa5ae351 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -117,6 +117,7 @@ const rlim_t rlim_infinity = RLIM_INFINITY; #include "libtorrent/choker.hpp" #include "libtorrent/error.hpp" #include "libtorrent/platform_util.hpp" +#include "libtorrent/aux_/bind_to_device.hpp" #ifndef TORRENT_DISABLE_LOGGING @@ -1737,6 +1738,30 @@ namespace aux { } #endif // TORRENT_USE_IPV6 + if (!device.empty()) + { + // we have an actual device we're interested in listening on, if we + // have SO_BINDTODEVICE functionality, use it now. +#if TORRENT_HAS_BINDTODEVICE + ret.sock->set_option(bind_to_device(device.c_str()), ec); + if (ec) + { +#ifndef TORRENT_DISABLE_LOGGING + session_log("bind to device failed (device: %s): %s" + , device.c_str(), ec.message().c_str()); +#endif // TORRENT_DISABLE_LOGGING + + last_op = listen_failed_alert::bind_to_device; + if (m_alerts.should_post()) + { + m_alerts.emplace_alert(device, bind_ep + , last_op, ec, sock_type); + } + return ret; + } +#endif + } + ret.sock->bind(bind_ep, ec); last_op = listen_failed_alert::bind; @@ -1876,7 +1901,7 @@ namespace aux { address adr = address::from_string(device.c_str(), err); if (!err) { - listen_socket_t s = setup_listener(device, tcp::endpoint(adr, port) + listen_socket_t s = setup_listener("", tcp::endpoint(adr, port) , flags | (ssl ? open_ssl_socket : 0), ec); if (!ec && s.sock) @@ -4910,7 +4935,7 @@ namespace aux { if (ec) return bind_ep; - bind_ep.address(bind_to_device(m_io_service, s + bind_ep.address(bind_socket_to_device(m_io_service, s , remote_address.is_v4() ? boost::asio::ip::tcp::v4() : boost::asio::ip::tcp::v6() diff --git a/src/string_util.cpp b/src/string_util.cpp index 15df6e554..38eded3c7 100644 --- a/src/string_util.cpp +++ b/src/string_util.cpp @@ -177,6 +177,7 @@ namespace libtorrent { if (i != in.begin()) ret += ","; +#if TORRENT_USE_IPV6 error_code ec; address_v6::from_string(i->device, ec); if (!ec) @@ -187,6 +188,7 @@ namespace libtorrent ret += "]"; } else +#endif { ret += i->device; }