use bind_to_device for listen sockets

This commit is contained in:
arvidn 2016-02-08 18:11:00 -05:00
parent 6d77000ab0
commit 72a24b63ba
7 changed files with 149 additions and 23 deletions

View File

@ -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 \

View File

@ -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.

View File

@ -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 <sys/socket.h> // for SO_BINDTODEVICE
#include <netinet/in.h>
#endif
namespace libtorrent { namespace aux {
#if defined SO_BINDTODEVICE
struct bind_to_device
{
bind_to_device(char const* device): m_value(device) {}
template<class Protocol>
int level(Protocol const&) const { return SOL_SOCKET; }
template<class Protocol>
int name(Protocol const&) const { return SO_BINDTODEVICE; }
template<class Protocol>
char const* data(Protocol const&) const { return m_value; }
template<class Protocol>
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<class Protocol>
int level(Protocol const&) const { return IPPROTO_IP; }
template<class Protocol>
int name(Protocol const&) const { return IP_BOUND_IF; }
template<class Protocol>
char const* data(Protocol const&) const { return reinterpret_cast<char const*>(&m_value); }
template<class Protocol>
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<class Protocol>
int level(Protocol const&) const { return SOL_SOCKET; }
template<class Protocol>
int name(Protocol const&) const { return IP_FORCE_OUT_IFP; }
template<class Protocol>
char const* data(Protocol const&) const { return m_value; }
template<class Protocol>
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

View File

@ -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<class Protocol>
int level(Protocol const&) const { return SOL_SOCKET; }
template<class Protocol>
int name(Protocol const&) const { return SO_BINDTODEVICE; }
template<class Protocol>
const char* data(Protocol const&) const { return m_value; }
template<class Protocol>
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 <class Socket>
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
{

View File

@ -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"

View File

@ -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<listen_failed_alert>())
{
m_alerts.emplace_alert<listen_failed_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()

View File

@ -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;
}